pciide.c, pciide_rdc_reg.h(new): ported rdcide(4) from NetBSD.
authorsasano <sasano@openbsd.org>
Sun, 13 Jul 2014 23:19:51 +0000 (23:19 +0000)
committersasano <sasano@openbsd.org>
Sun, 13 Jul 2014 23:19:51 +0000 (23:19 +0000)
it supports RDC's R1012 IDE controller.

tested on 86duino EduCake (DM&P Vortex86EX SoC)

ok by deraadt@

sys/dev/pci/pciide.c
sys/dev/pci/pciide_rdc_reg.h [new file with mode: 0644]

index e141c3c..5ee8632 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pciide.c,v 1.346 2014/07/12 18:48:52 tedu Exp $       */
+/*     $OpenBSD: pciide.c,v 1.347 2014/07/13 23:19:51 sasano Exp $     */
 /*     $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $     */
 
 /*
@@ -123,6 +123,7 @@ int wdcdebug_pciide_mask = WDCDEBUG_PCIIDE_MASK;
 #include <dev/pci/pciide_ixp_reg.h>
 #include <dev/pci/pciide_svwsata_reg.h>
 #include <dev/pci/pciide_jmicron_reg.h>
+#include <dev/pci/pciide_rdc_reg.h>
 #include <dev/pci/cy82c693var.h>
 
 /* functions for reading/writing 8-bit PCI registers */
@@ -282,6 +283,9 @@ void phison_setup_channel(struct channel_softc *);
 void sch_chip_map(struct pciide_softc *, struct pci_attach_args *);
 void sch_setup_channel(struct channel_softc *);
 
+void rdc_chip_map(struct pciide_softc *, struct pci_attach_args *);
+void rdc_setup_channel(struct channel_softc *);
+
 struct pciide_product_desc {
        u_int32_t ide_product;
        u_short ide_flags;
@@ -1335,6 +1339,13 @@ const struct pciide_product_desc pciide_phison_products[] = {
        },
 };
 
+const struct pciide_product_desc pciide_rdc_products[] = {
+       { PCI_PRODUCT_RDC_R1012_IDE,
+         0,
+         rdc_chip_map
+       },
+};
+
 struct pciide_vendor_desc {
        u_int32_t ide_vendor;
        const struct pciide_product_desc *ide_products;
@@ -1379,7 +1390,9 @@ const struct pciide_vendor_desc pciide_vendors[] = {
        { PCI_VENDOR_JMICRON, pciide_jmicron_products,
          nitems(pciide_jmicron_products) },
        { PCI_VENDOR_PHISON, pciide_phison_products,
-         nitems(pciide_phison_products) }
+         nitems(pciide_phison_products) },
+       { PCI_VENDOR_RDC, pciide_rdc_products,
+         nitems(pciide_rdc_products) }
 };
 
 /* options passed via the 'flags' config keyword */
@@ -1581,6 +1594,7 @@ pciide_activate(struct device *self, int act)
                    sc->sc_pp->chip_map == piix_chip_map ||
                    sc->sc_pp->chip_map == amd756_chip_map ||
                    sc->sc_pp->chip_map == phison_chip_map ||
+                   sc->sc_pp->chip_map == rdc_chip_map ||
                    sc->sc_pp->chip_map == ixp_chip_map ||
                    sc->sc_pp->chip_map == acard_chip_map ||
                    sc->sc_pp->chip_map == apollo_chip_map ||
@@ -9104,3 +9118,150 @@ pio:
 
        pciide_print_modes(cp);
 }
+
+void
+rdc_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
+{
+       struct pciide_channel *cp;
+       int channel;
+       u_int32_t patr;
+       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;
+       if (sc->sc_dma_ok) {
+               sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
+                       WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
+               sc->sc_wdcdev.irqack = pciide_irqack;
+               sc->sc_wdcdev.dma_init = pciide_dma_init;
+       }
+       sc->sc_wdcdev.PIO_cap = 4;
+       sc->sc_wdcdev.DMA_cap = 2;
+       sc->sc_wdcdev.UDMA_cap = 5;
+       sc->sc_wdcdev.set_modes = rdc_setup_channel;
+       sc->sc_wdcdev.channels = sc->wdc_chanarray;
+       sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
+
+       pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
+
+       WDCDEBUG_PRINT(("rdc_chip_map: old PATR=0x%x, "
+                       "PSD1ATR=0x%x, UDCCR=0x%x, IIOCR=0x%x\n",
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR),
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR),
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR),
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
+                      DEBUG_PROBE);
+
+       for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
+               cp = &sc->pciide_channels[channel];
+
+               if (pciide_chansetup(sc, channel, interface) == 0)
+                       continue;
+               patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
+               if ((patr & RDCIDE_PATR_EN(channel)) == 0) {
+                       printf("%s: %s ignored (disabled)\n",
+                              sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
+                       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)
+                       goto next;
+               if (pciide_chan_candisable(cp)) {
+                       patr &= ~RDCIDE_PATR_EN(channel);
+                       pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR,
+                                      patr);
+               }
+               if (cp->hw_ok == 0)
+                       goto next;
+               sc->sc_wdcdev.set_modes(&cp->wdc_channel);
+next:
+               if (cp->hw_ok == 0)
+                       pciide_unmap_compat_intr(pa, cp, channel, interface);
+       }
+
+       WDCDEBUG_PRINT(("rdc_chip_map: PATR=0x%x, "
+                       "PSD1ATR=0x%x, UDCCR=0x%x, IIOCR=0x%x\n",
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR),
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR),
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR),
+                       pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
+                      DEBUG_PROBE);
+}
+
+void
+rdc_setup_channel(struct channel_softc *chp)
+{
+       u_int8_t drive;
+       u_int32_t patr, psd1atr, udccr, iiocr;
+       struct pciide_channel *cp = (struct pciide_channel *)chp;
+       struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
+       struct ata_drive_datas *drvp;
+
+       patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
+       psd1atr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR);
+       udccr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR);
+       iiocr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR);
+
+       /* setup DMA */
+       pciide_channel_dma_setup(cp);
+
+       /* clear modes */
+       patr = patr & (RDCIDE_PATR_EN(0) | RDCIDE_PATR_EN(1));
+       psd1atr &= ~RDCIDE_PSD1ATR_SETUP_MASK(chp->channel);
+       psd1atr &= ~RDCIDE_PSD1ATR_HOLD_MASK(chp->channel);
+       for (drive = 0; drive < 2; drive++) {
+               udccr &= ~RDCIDE_UDCCR_EN(chp->channel, drive);
+               udccr &= ~RDCIDE_UDCCR_TIM_MASK(chp->channel, drive);
+               iiocr &= ~RDCIDE_IIOCR_CLK_MASK(chp->channel, drive);
+       }
+       /* now setup modes */
+       for (drive = 0; drive < 2; drive++) {
+               drvp = &cp->wdc_channel.ch_drive[drive];
+               if ((drvp->drive_flags & DRIVE) == 0)
+                       continue;
+               if (drvp->drive_flags & DRIVE_ATAPI)
+                       patr |= RDCIDE_PATR_ATA(chp->channel, drive);
+               if (drive == 0) {
+                       patr |= RDCIDE_PATR_SETUP(rdcide_setup[drvp->PIO_mode],
+                                                 chp->channel);
+                       patr |= RDCIDE_PATR_HOLD(rdcide_hold[drvp->PIO_mode],
+                                                chp->channel);
+               } else {
+                       patr |= RDCIDE_PATR_DEV1_TEN(chp->channel);
+                       psd1atr |= RDCIDE_PSD1ATR_SETUP(
+                               rdcide_setup[drvp->PIO_mode],
+                               chp->channel);
+                       psd1atr |= RDCIDE_PSD1ATR_HOLD(
+                               rdcide_hold[drvp->PIO_mode],
+                               chp->channel);
+               }
+               if (drvp->PIO_mode > 0) {
+                       patr |= RDCIDE_PATR_FTIM(chp->channel, drive);
+                       patr |= RDCIDE_PATR_IORDY(chp->channel, drive);
+               }
+               if (drvp->drive_flags & DRIVE_DMA)
+                       patr |= RDCIDE_PATR_DMAEN(chp->channel, drive);
+               if ((drvp->drive_flags & DRIVE_UDMA) == 0)
+                       continue;
+
+               if ((iiocr & RDCIDE_IIOCR_CABLE(chp->channel, drive)) == 0
+                   && drvp->UDMA_mode > 2)
+                       drvp->UDMA_mode = 2;
+               udccr |= RDCIDE_UDCCR_EN(chp->channel, drive);
+               udccr |= RDCIDE_UDCCR_TIM(rdcide_udmatim[drvp->UDMA_mode],
+                       chp->channel, drive);
+               iiocr |= RDCIDE_IIOCR_CLK(rdcide_udmaclk[drvp->UDMA_mode],
+                       chp->channel, drive);
+       }
+
+       pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR, patr);
+       pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR, psd1atr);
+       pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR, udccr);
+       pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR, iiocr);
+}
diff --git a/sys/dev/pci/pciide_rdc_reg.h b/sys/dev/pci/pciide_rdc_reg.h
new file mode 100644 (file)
index 0000000..b552380
--- /dev/null
@@ -0,0 +1,75 @@
+/*      $OpenBSD: pciide_rdc_reg.h,v 1.1 2014/07/13 23:19:51 sasano Exp $    */
+/*      $NetBSD: rdcide_reg.h,v 1.1 2011/04/04 14:33:51 bouyer Exp $    */
+
+/*
+ * Copyright (c) 2011 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+/*
+ * register definitions for the RDC ide controller as found in the
+ * PMX-1000 SoC
+ */
+/* ATA Timing Register */
+#define RDCIDE_PATR 0x40
+#define RDCIDE_PATR_EN(chan)           (0x8000 << ((chan) * 16))
+#define RDCIDE_PATR_DEV1_TEN(chan)     (0x4000 << ((chan) * 16))
+#define RDCIDE_PATR_SETUP(val, chan)   (((val) << 12) << ((chan) * 16))
+#define RDCIDE_PATR_SETUP_MASK(chan)   (0x3000 << ((chan) * 16))
+#define RDCIDE_PATR_HOLD(val, chan)    (((val) << 8) << ((chan) * 16))
+#define RDCIDE_PATR_HOLD_MASK(chan)    (0x0300 << ((chan) * 16))
+#define RDCIDE_PATR_DMAEN(chan, drv)   ((0x0008 << (drv * 4)) << ((chan) * 16))
+#define RDCIDE_PATR_ATA(chan, drv)     ((0x0004 << (drv * 4)) << ((chan) * 16))
+#define RDCIDE_PATR_IORDY(chan, drv)   ((0x0002 << (drv * 4)) << ((chan) * 16))
+#define RDCIDE_PATR_FTIM(chan, drv)    ((0x0001 << (drv * 4)) << ((chan) * 16))
+
+/* Primary and Secondary Device 1 ATA Timing */
+#define RDCIDE_PSD1ATR 0x44
+#define RDCIDE_PSD1ATR_SETUP(val, chan)        (((val) << 2) << (chan * 4))
+#define RDCIDE_PSD1ATR_SETUP_MASK(chan)        (0x0c << (chan * 4))
+#define RDCIDE_PSD1ATR_HOLD(val, chan) (((val) << 0) << (chan * 4))
+#define RDCIDE_PSD1ATR_HOLD_MASK(chan) (0x03 << (chan * 4))
+
+const uint8_t rdcide_setup[] = {0, 0, 1, 2, 2};
+const uint8_t rdcide_hold[] = {0, 0, 0, 1, 3};
+
+/* Ultra DMA Control and timing Register */
+#define RDCIDE_UDCCR   0x48
+#define RDCIDE_UDCCR_EN(chan, drv)     ((1 << (drv)) << (chan * 2))
+#define RDCIDE_UDCCR_TIM(val, chan, drv) (((val) << ((drv) * 4)) << (chan * 8))
+#define RDCIDE_UDCCR_TIM_MASK(chan, drv) ((0x3 << ((drv) * 4)) << (chan * 8))
+
+const uint8_t rdcide_udmatim[] = {0, 1, 2, 1, 2, 1};
+
+/* IDE I/O Configuration Registers */
+#define RDCIDE_IIOCR   0x54
+#define RDCIDE_IIOCR_CABLE(chan, drv)  ((0x10 << (drv)) << (chan * 2))
+#define RDCIDE_IIOCR_CLK(val, chan, drv) (((val) << drv) << (chan * 2))
+#define RDCIDE_IIOCR_CLK_MASK(chan, drv) ((0x1001 << drv) << (chan * 2))
+
+const uint32_t rdcide_udmaclk[] =
+    {0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x1000};
+
+/* Miscellaneous Control Register */
+#define RDCIDE_MCR     0x90
+#define RDCIDE_MCR_RESET(chan) (0x01000000 << (chan))