From 0c6fc91130dc558c590043011e59b139c870f26c Mon Sep 17 00:00:00 2001 From: sasano Date: Sun, 13 Jul 2014 23:19:51 +0000 Subject: [PATCH] pciide.c, pciide_rdc_reg.h(new): ported rdcide(4) from NetBSD. it supports RDC's R1012 IDE controller. tested on 86duino EduCake (DM&P Vortex86EX SoC) ok by deraadt@ --- sys/dev/pci/pciide.c | 165 ++++++++++++++++++++++++++++++++++- sys/dev/pci/pciide_rdc_reg.h | 75 ++++++++++++++++ 2 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 sys/dev/pci/pciide_rdc_reg.h diff --git a/sys/dev/pci/pciide.c b/sys/dev/pci/pciide.c index e141c3c36cd..5ee86324f8e 100644 --- a/sys/dev/pci/pciide.c +++ b/sys/dev/pci/pciide.c @@ -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 #include #include +#include #include /* 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 index 00000000000..b552380ce9f --- /dev/null +++ b/sys/dev/pci/pciide_rdc_reg.h @@ -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)) -- 2.20.1