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