xref: /netbsd-src/sys/dev/pci/rdcide.c (revision ff0489cbb59576f7287aef8a0397b0022fd864f1)
1*ff0489cbSmsaitoh /*	$NetBSD: rdcide.c,v 1.8 2014/07/08 18:01:26 msaitoh Exp $	*/
288db8892Sbouyer 
388db8892Sbouyer /*
488db8892Sbouyer  * Copyright (c) 2011 Manuel Bouyer.
588db8892Sbouyer  *
688db8892Sbouyer  * Redistribution and use in source and binary forms, with or without
788db8892Sbouyer  * modification, are permitted provided that the following conditions
888db8892Sbouyer  * are met:
988db8892Sbouyer  * 1. Redistributions of source code must retain the above copyright
1088db8892Sbouyer  *    notice, this list of conditions and the following disclaimer.
1188db8892Sbouyer  * 2. Redistributions in binary form must reproduce the above copyright
1288db8892Sbouyer  *    notice, this list of conditions and the following disclaimer in the
1388db8892Sbouyer  *    documentation and/or other materials provided with the distribution.
1488db8892Sbouyer  *
1588db8892Sbouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1688db8892Sbouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1788db8892Sbouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1888db8892Sbouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1988db8892Sbouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2088db8892Sbouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2188db8892Sbouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2288db8892Sbouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2388db8892Sbouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2488db8892Sbouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2588db8892Sbouyer  */
2688db8892Sbouyer 
2788db8892Sbouyer #include <sys/cdefs.h>
28*ff0489cbSmsaitoh __KERNEL_RCSID(0, "$NetBSD: rdcide.c,v 1.8 2014/07/08 18:01:26 msaitoh Exp $");
2988db8892Sbouyer 
3088db8892Sbouyer #include <sys/param.h>
3188db8892Sbouyer #include <sys/systm.h>
3288db8892Sbouyer 
3388db8892Sbouyer #include <dev/pci/pcivar.h>
3488db8892Sbouyer #include <dev/pci/pcidevs.h>
3588db8892Sbouyer #include <dev/pci/pciidereg.h>
3688db8892Sbouyer #include <dev/pci/pciidevar.h>
3788db8892Sbouyer #include <dev/pci/rdcide_reg.h>
3888db8892Sbouyer 
393c888757Sdyoung static void rdcide_chip_map(struct pciide_softc *,
403c888757Sdyoung     const struct pci_attach_args *);
4188db8892Sbouyer static void rdcide_setup_channel(struct ata_channel *);
4288db8892Sbouyer 
4388db8892Sbouyer static bool rdcide_resume(device_t, const pmf_qual_t *);
4488db8892Sbouyer static bool rdcide_suspend(device_t, const pmf_qual_t *);
4588db8892Sbouyer static int  rdcide_match(device_t, cfdata_t, void *);
4688db8892Sbouyer static void rdcide_attach(device_t, device_t, void *);
4788db8892Sbouyer 
4888db8892Sbouyer static const struct pciide_product_desc pciide_intel_products[] =  {
49*ff0489cbSmsaitoh 	{ PCI_PRODUCT_RDC_R1011_IDE,
5088db8892Sbouyer 	  0,
51*ff0489cbSmsaitoh 	  "RDC R1011 IDE controller",
52*ff0489cbSmsaitoh 	  rdcide_chip_map,
53*ff0489cbSmsaitoh 	},
54*ff0489cbSmsaitoh 	{ PCI_PRODUCT_RDC_R1012_IDE,
55*ff0489cbSmsaitoh 	  0,
56*ff0489cbSmsaitoh 	  "RDC R1012 IDE controller",
5788db8892Sbouyer 	  rdcide_chip_map,
5888db8892Sbouyer 	},
5988db8892Sbouyer };
6088db8892Sbouyer 
6188db8892Sbouyer CFATTACH_DECL_NEW(rdcide, sizeof(struct pciide_softc),
6288db8892Sbouyer     rdcide_match, rdcide_attach, NULL, NULL);
6388db8892Sbouyer 
6488db8892Sbouyer static int
rdcide_match(device_t parent,cfdata_t match,void * aux)6588db8892Sbouyer rdcide_match(device_t parent, cfdata_t match, void *aux)
6688db8892Sbouyer {
6788db8892Sbouyer 	struct pci_attach_args *pa = aux;
6888db8892Sbouyer 
6988db8892Sbouyer 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RDC) {
7088db8892Sbouyer 		if (pciide_lookup_product(pa->pa_id, pciide_intel_products))
7188db8892Sbouyer 			return (2);
7288db8892Sbouyer 	}
7388db8892Sbouyer 	return (0);
7488db8892Sbouyer }
7588db8892Sbouyer 
7688db8892Sbouyer static void
rdcide_attach(device_t parent,device_t self,void * aux)7788db8892Sbouyer rdcide_attach(device_t parent, device_t self, void *aux)
7888db8892Sbouyer {
7988db8892Sbouyer 	struct pci_attach_args *pa = aux;
8088db8892Sbouyer 	struct pciide_softc *sc = device_private(self);
8188db8892Sbouyer 
8288db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_dev = self;
8388db8892Sbouyer 
8488db8892Sbouyer 	pciide_common_attach(sc, pa,
8588db8892Sbouyer 	    pciide_lookup_product(pa->pa_id, pciide_intel_products));
8688db8892Sbouyer 
8788db8892Sbouyer 	if (!pmf_device_register(self, rdcide_suspend, rdcide_resume))
8888db8892Sbouyer 		aprint_error_dev(self, "couldn't establish power handler\n");
8988db8892Sbouyer }
9088db8892Sbouyer 
9188db8892Sbouyer static bool
rdcide_resume(device_t dv,const pmf_qual_t * qual)9288db8892Sbouyer rdcide_resume(device_t dv, const pmf_qual_t *qual)
9388db8892Sbouyer {
9488db8892Sbouyer 	struct pciide_softc *sc = device_private(dv);
9588db8892Sbouyer 
9688db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR,
9788db8892Sbouyer 	    sc->sc_pm_reg[0]);
9888db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR,
9988db8892Sbouyer 	    sc->sc_pm_reg[1]);
10088db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR,
10188db8892Sbouyer 	    sc->sc_pm_reg[2]);
10288db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR,
10388db8892Sbouyer 	    sc->sc_pm_reg[3]);
10488db8892Sbouyer 
10588db8892Sbouyer 	return true;
10688db8892Sbouyer }
10788db8892Sbouyer 
10888db8892Sbouyer static bool
rdcide_suspend(device_t dv,const pmf_qual_t * qual)10988db8892Sbouyer rdcide_suspend(device_t dv, const pmf_qual_t *qual)
11088db8892Sbouyer {
11188db8892Sbouyer 	struct pciide_softc *sc = device_private(dv);
11288db8892Sbouyer 
11388db8892Sbouyer 	sc->sc_pm_reg[0] = pci_conf_read(sc->sc_pc, sc->sc_tag,
11488db8892Sbouyer 	    RDCIDE_PATR);
11588db8892Sbouyer 	sc->sc_pm_reg[1] = pci_conf_read(sc->sc_pc, sc->sc_tag,
11688db8892Sbouyer 	    RDCIDE_PSD1ATR);
11788db8892Sbouyer 	sc->sc_pm_reg[2] = pci_conf_read(sc->sc_pc, sc->sc_tag,
11888db8892Sbouyer 	    RDCIDE_UDCCR);
11988db8892Sbouyer 	sc->sc_pm_reg[3] = pci_conf_read(sc->sc_pc, sc->sc_tag,
12088db8892Sbouyer 	    RDCIDE_IIOCR);
12188db8892Sbouyer 
12288db8892Sbouyer 	return true;
12388db8892Sbouyer }
12488db8892Sbouyer 
12588db8892Sbouyer static void
rdcide_chip_map(struct pciide_softc * sc,const struct pci_attach_args * pa)1263c888757Sdyoung rdcide_chip_map(struct pciide_softc *sc, const struct pci_attach_args *pa)
12788db8892Sbouyer {
12888db8892Sbouyer 	struct pciide_channel *cp;
12988db8892Sbouyer 	int channel;
13088db8892Sbouyer 	u_int32_t patr;
13188db8892Sbouyer 	pcireg_t interface = PCI_INTERFACE(pa->pa_class);
13288db8892Sbouyer 
13388db8892Sbouyer 	if (pciide_chipen(sc, pa) == 0)
13488db8892Sbouyer 		return;
13588db8892Sbouyer 
13688db8892Sbouyer 	aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
13788db8892Sbouyer 	    "bus-master DMA support present");
13888db8892Sbouyer 	pciide_mapreg_dma(sc, pa);
13988db8892Sbouyer 	aprint_verbose("\n");
14088db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
14188db8892Sbouyer 	if (sc->sc_dma_ok) {
14288db8892Sbouyer 		sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA;
14388db8892Sbouyer 		sc->sc_wdcdev.irqack = pciide_irqack;
14488db8892Sbouyer 		sc->sc_wdcdev.dma_init = pciide_dma_init;
14588db8892Sbouyer 	}
14688db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_pio_cap = 4;
14788db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_dma_cap = 2;
14888db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_udma_cap = 5;
14988db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_set_modes = rdcide_setup_channel;
15088db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
15188db8892Sbouyer 	sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
1529edd4d81Sbouyer 	sc->sc_wdcdev.wdc_maxdrives = 2;
15388db8892Sbouyer 
15488db8892Sbouyer 	ATADEBUG_PRINT(("rdcide_setup_chip: old PATR=0x%x",
15588db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR)),
15688db8892Sbouyer 	    DEBUG_PROBE);
15788db8892Sbouyer 	ATADEBUG_PRINT((", PSD1ATR=0x%x",
15888db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR)),
15988db8892Sbouyer 	    DEBUG_PROBE);
16088db8892Sbouyer 	ATADEBUG_PRINT((", UDCCR 0x%x",
16188db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR)),
16288db8892Sbouyer 	    DEBUG_PROBE);
16388db8892Sbouyer 	ATADEBUG_PRINT((", IIOCR 0x%x",
16488db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
16588db8892Sbouyer 	    DEBUG_PROBE);
16688db8892Sbouyer 	ATADEBUG_PRINT(("\n"), DEBUG_PROBE);
16788db8892Sbouyer 
16888db8892Sbouyer 	wdc_allocate_regs(&sc->sc_wdcdev);
16988db8892Sbouyer 
17088db8892Sbouyer 	for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
17188db8892Sbouyer 	     channel++) {
17288db8892Sbouyer 		cp = &sc->pciide_channels[channel];
17388db8892Sbouyer 		if (pciide_chansetup(sc, channel, interface) == 0)
17488db8892Sbouyer 			continue;
17588db8892Sbouyer 		patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
17688db8892Sbouyer 		if ((patr & RDCIDE_PATR_EN(channel)) == 0) {
17788db8892Sbouyer 			aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
17888db8892Sbouyer 			    "%s channel ignored (disabled)\n", cp->name);
17988db8892Sbouyer 			cp->ata_channel.ch_flags |= ATACH_DISABLED;
18088db8892Sbouyer 			continue;
18188db8892Sbouyer 		}
18288db8892Sbouyer 		pciide_mapchan(pa, cp, interface, pciide_pci_intr);
18388db8892Sbouyer 	}
18488db8892Sbouyer 	ATADEBUG_PRINT(("rdcide_setup_chip: PATR=0x%x",
18588db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR)),
18688db8892Sbouyer 	    DEBUG_PROBE);
18788db8892Sbouyer 	ATADEBUG_PRINT((", PSD1ATR=0x%x",
18888db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR)),
18988db8892Sbouyer 	    DEBUG_PROBE);
19088db8892Sbouyer 	ATADEBUG_PRINT((", UDCCR 0x%x",
19188db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR)),
19288db8892Sbouyer 	    DEBUG_PROBE);
19388db8892Sbouyer 	ATADEBUG_PRINT((", IIOCR 0x%x",
19488db8892Sbouyer 	    pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
19588db8892Sbouyer 	    DEBUG_PROBE);
19688db8892Sbouyer 	ATADEBUG_PRINT(("\n"), DEBUG_PROBE);
19788db8892Sbouyer 
19888db8892Sbouyer }
19988db8892Sbouyer 
20088db8892Sbouyer static void
rdcide_setup_channel(struct ata_channel * chp)20188db8892Sbouyer rdcide_setup_channel(struct ata_channel *chp)
20288db8892Sbouyer {
20388db8892Sbouyer 	u_int8_t drive;
20488db8892Sbouyer 	u_int32_t patr, psd1atr, udccr, iiocr;
20588db8892Sbouyer 	struct pciide_channel *cp = CHAN_TO_PCHAN(chp);
20688db8892Sbouyer 	struct pciide_softc *sc = CHAN_TO_PCIIDE(chp);
20788db8892Sbouyer 	struct ata_drive_datas *drvp = cp->ata_channel.ch_drive;
20888db8892Sbouyer 
20988db8892Sbouyer 	patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
21088db8892Sbouyer 	psd1atr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR);
21188db8892Sbouyer 	udccr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR);
21288db8892Sbouyer 	iiocr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR);
21388db8892Sbouyer 
21488db8892Sbouyer 	/* setup DMA */
21588db8892Sbouyer 	pciide_channel_dma_setup(cp);
21688db8892Sbouyer 
21788db8892Sbouyer 	/* clear modes */
21888db8892Sbouyer 	patr = patr & (RDCIDE_PATR_EN(0) | RDCIDE_PATR_EN(1));
21988db8892Sbouyer 	psd1atr &= ~RDCIDE_PSD1ATR_SETUP_MASK(chp->ch_channel);
22088db8892Sbouyer 	psd1atr &= ~RDCIDE_PSD1ATR_HOLD_MASK(chp->ch_channel);
22188db8892Sbouyer 	for (drive = 0; drive < 2; drive++) {
22288db8892Sbouyer 		udccr &= ~RDCIDE_UDCCR_EN(chp->ch_channel, drive);
22388db8892Sbouyer 		udccr &= ~RDCIDE_UDCCR_TIM_MASK(chp->ch_channel, drive);
22488db8892Sbouyer 		iiocr &= ~RDCIDE_IIOCR_CLK_MASK(chp->ch_channel, drive);
22588db8892Sbouyer 	}
22688db8892Sbouyer 	/* now setup modes */
22788db8892Sbouyer 	for (drive = 0; drive < 2; drive++) {
2289edd4d81Sbouyer 		if (drvp[drive].drive_type == ATA_DRIVET_NONE)
22988db8892Sbouyer 			continue;
2309edd4d81Sbouyer 		if (drvp[drive].drive_type == ATA_DRIVET_ATAPI)
23188db8892Sbouyer 			patr |= RDCIDE_PATR_ATA(chp->ch_channel, drive);
23288db8892Sbouyer 		if (drive == 0) {
23388db8892Sbouyer 			patr |= RDCIDE_PATR_SETUP(
23488db8892Sbouyer 			    rdcide_setup[drvp[drive].PIO_mode],
23588db8892Sbouyer 			    chp->ch_channel);
23688db8892Sbouyer 			patr |= RDCIDE_PATR_HOLD(
23788db8892Sbouyer 			    rdcide_hold[drvp[drive].PIO_mode],
23888db8892Sbouyer 			    chp->ch_channel);
23988db8892Sbouyer 		} else {
24088db8892Sbouyer 			patr |= RDCIDE_PATR_DEV1_TEN(chp->ch_channel);
24188db8892Sbouyer 			psd1atr |= RDCIDE_PSD1ATR_SETUP(
24288db8892Sbouyer 			    rdcide_setup[drvp[drive].PIO_mode],
24388db8892Sbouyer 			    chp->ch_channel);
24488db8892Sbouyer 			psd1atr |= RDCIDE_PSD1ATR_HOLD(
24588db8892Sbouyer 			    rdcide_hold[drvp[drive].PIO_mode],
24688db8892Sbouyer 			    chp->ch_channel);
24788db8892Sbouyer 		}
24888db8892Sbouyer 		if (drvp[drive].PIO_mode > 0) {
24988db8892Sbouyer 			patr |= RDCIDE_PATR_FTIM(chp->ch_channel, drive);
25088db8892Sbouyer 			patr |= RDCIDE_PATR_IORDY(chp->ch_channel, drive);
25188db8892Sbouyer 		}
2529edd4d81Sbouyer 		if (drvp[drive].drive_flags & ATA_DRIVE_DMA) {
25388db8892Sbouyer 			patr |= RDCIDE_PATR_DMAEN(chp->ch_channel, drive);
25488db8892Sbouyer 		}
2559edd4d81Sbouyer 		if ((drvp[drive].drive_flags & ATA_DRIVE_UDMA) == 0)
25688db8892Sbouyer 			continue;
25788db8892Sbouyer 
25888db8892Sbouyer 		if ((iiocr & RDCIDE_IIOCR_CABLE(chp->ch_channel, drive)) == 0
25988db8892Sbouyer 		    && drvp[drive].UDMA_mode > 2)
26088db8892Sbouyer 			drvp[drive].UDMA_mode = 2;
26188db8892Sbouyer 		udccr |= RDCIDE_UDCCR_EN(chp->ch_channel, drive);
26288db8892Sbouyer 		udccr |= RDCIDE_UDCCR_TIM(
26388db8892Sbouyer 		    rdcide_udmatim[drvp[drive].UDMA_mode],
26488db8892Sbouyer 		    chp->ch_channel, drive);
26588db8892Sbouyer 		iiocr |= RDCIDE_IIOCR_CLK(
26688db8892Sbouyer 		    rdcide_udmaclk[drvp[drive].UDMA_mode],
26788db8892Sbouyer 		    chp->ch_channel, drive);
26888db8892Sbouyer 	}
26988db8892Sbouyer 
27088db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR, patr);
27188db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR, psd1atr);
27288db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR, udccr);
27388db8892Sbouyer 	pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR, iiocr);
27488db8892Sbouyer }
275