diff --git a/sys/arch/macppc/dev/wdc_obio.c b/sys/arch/macppc/dev/wdc_obio.c index c4ff59639914..725ea3ea0611 100644 --- a/sys/arch/macppc/dev/wdc_obio.c +++ b/sys/arch/macppc/dev/wdc_obio.c @@ -1,4 +1,4 @@ -/* $NetBSD: wdc_obio.c,v 1.15 2001/07/25 20:26:33 bouyer Exp $ */ +/* $NetBSD: wdc_obio.c,v 1.16 2001/08/02 12:41:39 bouyer Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -81,6 +81,7 @@ int wdc_obio_dma_init __P((void *, int, int, void *, size_t, int)); void wdc_obio_dma_start __P((void *, int, int)); int wdc_obio_dma_finish __P((void *, int, int, int)); static void adjust_timing __P((struct channel_softc *)); +static void ata4_adjust_timing __P((struct channel_softc *)); struct cfattach wdc_obio_ca = { sizeof(struct wdc_obio_softc), wdc_obio_probe, wdc_obio_attach, @@ -169,6 +170,13 @@ wdc_obio_attach(parent, self, aux) ca->ca_reg[3]); sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; sc->sc_wdcdev.DMA_cap = 2; + if (strcmp(ca->ca_name, "ata-4") == 0) { + sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA; + sc->sc_wdcdev.UDMA_cap = 4; + sc->sc_wdcdev.set_modes = ata4_adjust_timing; + } else { + sc->sc_wdcdev.set_modes = adjust_timing; + } #ifdef notyet /* Minimum cycle time is 150ns (DMA MODE 1) on ohare. */ if (ohare) { @@ -186,7 +194,6 @@ wdc_obio_attach(parent, self, aux) sc->sc_wdcdev.dma_init = wdc_obio_dma_init; sc->sc_wdcdev.dma_start = wdc_obio_dma_start; sc->sc_wdcdev.dma_finish = wdc_obio_dma_finish; - sc->sc_wdcdev.set_modes = adjust_timing; chp->channel = 0; chp->wdc = &sc->sc_wdcdev; chp->ch_queue = malloc(sizeof(struct channel_queue), @@ -211,10 +218,7 @@ wdc_obio_attach(parent, self, aux) } wdcattach(chp); - - /* modify DMA access timings */ - if (use_dma) - adjust_timing(chp); + sc->sc_wdcdev.set_modes(chp); } @@ -236,7 +240,24 @@ static struct ide_timings dma_timing[3] = { { 120, 70 }, /* Mode 2 */ }; +static struct ide_timings udma_timing[5] = { + {114, 0}, /* Mode 0 */ + { 75, 0}, /* Mode 1 */ + { 55, 0}, /* Mode 2 */ + { 45, 100}, /* Mode 3 */ + { 25, 100} /* Mode 4 */ +}; + #define TIME_TO_TICK(time) howmany((time), 30) +#define PIO_REC_OFFSET 4 +#define PIO_REC_MIN 1 +#define PIO_ACT_MIN 1 +#define DMA_REC_OFFSET 1 +#define DMA_REC_MIN 1 +#define DMA_ACT_MIN 1 + +#define ATA4_TIME_TO_TICK(time) howmany((time) * 1000, 7500) + #define CONFIG_REG (0x200 >> 4) /* IDE access timing register */ @@ -278,30 +299,106 @@ adjust_timing(chp) cycle_tick = TIME_TO_TICK(min_cycle); act_tick = TIME_TO_TICK(min_active); - inact_tick = cycle_tick - act_tick - 1; - if (inact_tick < 1) - inact_tick = 1; + if (act_tick < PIO_ACT_MIN) + act_tick = PIO_ACT_MIN; + inact_tick = cycle_tick - act_tick - PIO_REC_OFFSET; + if (inact_tick < PIO_REC_MIN) + inact_tick = PIO_REC_MIN; + /* mask: 0x000007ff */ conf = (inact_tick << 5) | act_tick; if (dmamode != -1) { /* there are active DMA mode */ min_cycle = dma_timing[dmamode].cycle; min_active = dma_timing[dmamode].active; - cycle_tick = TIME_TO_TICK(min_cycle); act_tick = TIME_TO_TICK(min_active); - inact_tick = cycle_tick - act_tick - 1; - if (inact_tick < 1) - inact_tick = 1; + inact_tick = cycle_tick - act_tick - DMA_REC_OFFSET; + if (inact_tick < DMA_REC_MIN) + inact_tick = DMA_REC_MIN; half_tick = 0; /* XXX */ + /* mask: 0xfffff800 */ conf |= - (half_tick << 21) | (inact_tick << 16) | (act_tick << 11); + (half_tick << 21) | + (inact_tick << 16) | (act_tick << 11); } bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf); -#if 0 printf("conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n", conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick); -#endif + wdc_print_modes(chp); +} + +void +ata4_adjust_timing(chp) + struct channel_softc *chp; +{ + struct ata_drive_datas *drvp; + u_int conf; + int drive; + int piomode = -1, dmamode = -1; + int min_cycle, min_active; + int cycle_tick, act_tick, inact_tick; + int udmamode = -1; + + + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + if ((drvp->drive_flags & DRIVE) == 0) + continue; + if (piomode == -1 || piomode > drvp->PIO_mode) + piomode = drvp->PIO_mode; + if (drvp->drive_flags & DRIVE_DMA) { + if (dmamode == -1 || dmamode > drvp->DMA_mode) + dmamode = drvp->DMA_mode; + } + if (drvp->drive_flags & DRIVE_UDMA) { + if (udmamode == -1 || udmamode > drvp->UDMA_mode) + udmamode = drvp->UDMA_mode; + } + } + if (piomode == -1) + return; /* No drive */ + for (drive = 0; drive < 2; drive++) { + drvp = &chp->ch_drive[drive]; + if (drvp->drive_flags & DRIVE) { + drvp->PIO_mode = piomode; + if (drvp->drive_flags & DRIVE_DMA) + drvp->DMA_mode = dmamode; + if (drvp->drive_flags & DRIVE_UDMA) + drvp->UDMA_mode = udmamode; + } + } + min_cycle = pio_timing[piomode].cycle; + min_active = pio_timing[piomode].active; + + cycle_tick = ATA4_TIME_TO_TICK(min_cycle); + act_tick = ATA4_TIME_TO_TICK(min_active); + inact_tick = cycle_tick - act_tick; + /* mask: 0x000003ff */ + conf = (inact_tick << 5) | act_tick; + if (dmamode != -1) { + /* there are active DMA mode */ + + min_cycle = dma_timing[dmamode].cycle; + min_active = dma_timing[dmamode].active; + cycle_tick = ATA4_TIME_TO_TICK(min_cycle); + act_tick = ATA4_TIME_TO_TICK(min_active); + inact_tick = cycle_tick - act_tick; + /* mask: 0x001ffc00 */ + conf |= (act_tick << 10) | (inact_tick << 15); + } + if (udmamode != -1) { + min_cycle = udma_timing[udmamode].cycle; + min_active = udma_timing[udmamode].active; + act_tick = ATA4_TIME_TO_TICK(min_active); + cycle_tick = ATA4_TIME_TO_TICK(min_cycle); + /* mask: 0x1ff00000 */ + conf |= (cycle_tick << 21) | (act_tick << 25) | 0x100000; + } + + bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf); + printf("ata4 conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n", + conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick); wdc_print_modes(chp); }