Properly setup timings for ata-4 controllers, including UDMA modes.

Tested on a brand new ("dual USB ?") ibook.
This commit is contained in:
bouyer 2001-08-02 12:41:39 +00:00
parent ad2c12a28d
commit f7c2f13a54
1 changed files with 113 additions and 16 deletions

View File

@ -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);
}