patch-2.3.99-pre9 linux/drivers/ide/ide-pmac.c
Next file: linux/drivers/ide/ide-probe.c
Previous file: linux/drivers/ide/ide-pci.c
Back to the patch index
Back to the overall index
- Lines: 491
- Date:
Mon May 15 11:03:48 2000
- Orig file:
v2.3.99-pre8/linux/drivers/ide/ide-pmac.c
- Orig date:
Mon Mar 27 08:08:24 2000
diff -u --recursive --new-file v2.3.99-pre8/linux/drivers/ide/ide-pmac.c linux/drivers/ide/ide-pmac.c
@@ -7,6 +7,8 @@
*
* Copyright (C) 1998 Paul Mackerras.
*
+ * Bits from Benjamin Herrenschmidt
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -16,12 +18,6 @@
*
* Copyright (c) 1995-1998 Mark Lord
*
- * BenH: I began adding more complete timing setup code, mostly because DMA
- * won't work on new machines unless timings are setup correctly. This
- * code was mainly stolen from Cmd646 driver and should be completed to
- * include real timing calc. instead of hard coded values. The format of
- * the timing register can be found in Darwin's source code, except for
- * Keylargo ATA-4 controller.
*/
#include <linux/config.h>
#include <linux/types.h>
@@ -44,14 +40,18 @@
#endif
#include "ide_modes.h"
+extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+
#undef IDE_PMAC_DEBUG
-#define IDE_SYSCLK_NS 30
+#define IDE_SYSCLK_NS 30
+#define IDE_SYSCLK_ULTRA_PS 0x1d4c /* (15 * 1000 / 2)*/
struct pmac_ide_hwif {
ide_ioreg_t regbase;
int irq;
int kind;
+ int aapl_bus_id;
struct device_node* node;
u32 timings[2];
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
@@ -90,17 +90,27 @@
static pmac_ide_timing udma_timings[] =
{
{ 0, 114 }, /* Mode 0 */
- { 0, 73 }, /* 1 */
- { 0, 54 }, /* 2 */
- { 0, 39 }, /* 3 */
- { 0, 25 } /* 4 */
+ { 0, 75 }, /* 1 */
+ { 0, 55 }, /* 2 */
+ { 100, 45 }, /* 3 */
+ { 100, 25 } /* 4 */
};
-#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS 256
+
+/* Wait 1.5s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ * before anwering on the bus. I beleive we could add a kernel command
+ * line arg to override this delay for such cases.
+ */
+#define IDE_WAKEUP_DELAY_MS 1500
static void pmac_ide_setup_dma(struct device_node *np, int ix);
static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
static void pmac_ide_selectproc(ide_drive_t *drive);
@@ -156,14 +166,6 @@
return;
}
- /* we check only for -EINVAL meaning that we have found a matching
- bay but with the wrong device type */
- i = check_media_bay_by_base(data_port, MB_CD);
- if (i == -EINVAL) {
- hw->io_ports[IDE_DATA_OFFSET] = 0;
- return;
- }
-
for (i = 0; i < 8; ++i)
hw->io_ports[i] = data_port + i * 0x10;
hw->io_ports[8] = data_port + 0x160;
@@ -178,6 +180,7 @@
#ifdef CONFIG_PMAC_IDEDMA_AUTO
ide_hwifs[ix].autodma = 1;
#endif
+// ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
}
}
@@ -214,7 +217,9 @@
/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_UDMA(t) (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS)
+/* Calculate PIO timings */
static void
pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
{
@@ -227,26 +232,31 @@
if (i < 0)
return;
- /* The "ata-4" IDE controller of UMA machines is a bit different.
- * We don't do anything for PIO modes until we know how to do the
- * calculation.
- */
- if (pmac_ide[i].kind == controller_kl_ata4)
- return;
-
pio = ide_get_best_pio_mode(drive, pio, 4, &d);
accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
- if (accessTicks < 4)
- accessTicks = 4;
- recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4;
- if (recTicks < 1)
- recTicks = 1;
if (drive->select.all & 0x10)
timings = &pmac_ide[i].timings[1];
else
timings = &pmac_ide[i].timings[0];
- *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);
+ if (pmac_ide[i].kind == controller_kl_ata4) {
+ /* The "ata-4" IDE controller of Core99 machines */
+ accessTicks = SYSCLK_TICKS_UDMA(ide_pio_timings[pio].active_time * 1000);
+ recTicks = SYSCLK_TICKS_UDMA(d.cycle_time * 1000) - accessTicks;
+
+ *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5);
+ } else {
+ /* The old "ata-3" IDE controller */
+ accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+ if (accessTicks < 4)
+ accessTicks = 4;
+ recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4;
+ if (recTicks < 1)
+ recTicks = 1;
+
+ *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5);
+ }
+
#ifdef IDE_PMAC_DEBUG
printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
pio, *timings);
@@ -294,7 +304,7 @@
struct device_node *atas;
struct device_node *p, **pp, *removables, **rp;
unsigned long base;
- int irq;
+ int irq, big_delay;
ide_hwif_t *hwif;
if (_machine != _MACH_Pmac)
@@ -322,9 +332,11 @@
}
*rp = NULL;
*pp = removables;
+ big_delay = 0;
for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
struct device_node *tp;
+ int *bidp;
/*
* If this node is not under a mac-io or dbdma node,
@@ -378,6 +390,9 @@
else
pmac_ide[i].kind = controller_ohare;
+ bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+ pmac_ide[i].aapl_bus_id = bidp ? *bidp : 0;
+
if (np->parent && np->parent->name
&& strcasecmp(np->parent->name, "media-bay") == 0) {
media_bay_set_ide_infos(np->parent,base,irq,i);
@@ -388,42 +403,41 @@
*/
feature_set(np, FEATURE_IDE0_enable);
} else {
- /* This is necessary to enable IDE when net-booting */
- int *bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
- int bid = bidp ? *bidp : 0;
- printk("pmac_ide: enabling IDE bus ID %d\n", bid);
- switch(bid) {
+ /* This is necessary to enable IDE when net-booting */
+ printk("pmac_ide: enabling IDE bus ID %d\n",
+ pmac_ide[i].aapl_bus_id);
+ switch(pmac_ide[i].aapl_bus_id) {
case 0:
feature_set(np, FEATURE_IDE0_reset);
- feature_set(np, FEATURE_IOBUS_enable);
mdelay(10);
feature_set(np, FEATURE_IDE0_enable);
mdelay(10);
feature_clear(np, FEATURE_IDE0_reset);
break;
case 1:
- feature_set(np, FEATURE_Mediabay_IDE_reset);
+ feature_set(np, FEATURE_IDE1_reset);
mdelay(10);
- feature_set(np, FEATURE_Mediabay_IDE_enable);
+ feature_set(np, FEATURE_IDE1_enable);
mdelay(10);
- feature_clear(np, FEATURE_Mediabay_IDE_reset);
+ feature_clear(np, FEATURE_IDE1_reset);
break;
case 2:
- /* This one exists only for KL, I don't know about any
- enable bit */
+ /* This one exists only for KL, I don't know
+ about any enable bit */
feature_set(np, FEATURE_IDE2_reset);
mdelay(10);
feature_clear(np, FEATURE_IDE2_reset);
break;
}
- mdelay(1000);
+ big_delay = 1;
}
hwif = &ide_hwifs[i];
pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
hwif->chipset = ide_pmac;
- hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+ hwif->noprobe = (!hwif->io_ports[IDE_DATA_OFFSET]) ||
+ (check_media_bay_by_base(base, MB_CD) == -EINVAL);
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
if (np->n_addrs >= 2) {
@@ -435,6 +449,8 @@
++i;
}
pmac_ide_count = i;
+ if (big_delay)
+ mdelay(IDE_WAKEUP_DELAY_MS);
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&idepmac_sleep_notifier);
@@ -642,6 +658,7 @@
return result;
}
+/* Calculate MultiWord DMA timings */
static int
pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
{
@@ -652,18 +669,15 @@
int accessTicks, recTicks;
struct hd_driveid *id = drive->id;
- /* For now, we don't know these values */
- if (pmac_ide[idx].kind == controller_kl_ata4 && feature != IDE_DMA2_ENABLE)
- return 0;
- if (pmac_ide[idx].kind != controller_kl_ata4 && feature == IDE_DMA0_ENABLE)
- return 0;
-
/* Set feature on drive */
printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
if (pmac_ide_do_setfeature(drive, feature)) {
printk("%s: Failed !\n", drive->name);
return 0;
}
+
+ if (!drive->init_speed)
+ drive->init_speed = feature;
/* which drive is it ? */
if (drive->select.all & 0x10)
@@ -681,7 +695,10 @@
/* For ata-4 controller, we don't know the calculation */
if (pmac_ide[idx].kind == controller_kl_ata4) {
- *timings = 0x00019465; /* MDMA2 */
+ accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+ recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks;
+ *timings = ((*timings) & 0xffe003ff) |
+ (accessTicks | (recTicks << 5)) << 10;
} else {
int halfTick = 0;
int origAccessTime = accessTime;
@@ -696,7 +713,9 @@
recTicks = 1;
cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS;
- if ((accessTicks > 1) &&
+ /* KeyLargo ata-3 don't support the half-tick stuff */
+ if ((pmac_ide[idx].kind != controller_kl_ata3) &&
+ (accessTicks > 1) &&
((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) {
halfTick = 1;
@@ -708,21 +727,21 @@
#ifdef IDE_PMAC_DEBUG
printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
feature & 0xf, *timings);
-#endif
+#endif
+ drive->current_speed = feature;
return 1;
}
+/* Calculate Ultra DMA timings */
static int
pmac_ide_udma_enable(ide_drive_t *drive, int idx)
{
byte bits = drive->id->dma_ultra & 0x1f;
byte feature = udma_bits_to_command(bits);
- u32 timings;
+ int cycleTime, accessTime;
+ int rdyToPauseTicks, cycleTicks;
+ u32 *timings;
- /* We support only those values */
- if (feature != IDE_UDMA4_ENABLE && feature != IDE_UDMA2_ENABLE)
- return 0;
-
/* Set feature on drive */
printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
if (pmac_ide_do_setfeature(drive, feature)) {
@@ -730,23 +749,25 @@
return 0;
}
- /* Put this channel into UDMA mode.
- * This value is set by MacOS on the iBook for U/DMA2
- */
- switch(feature) {
- case IDE_UDMA4_ENABLE:
- timings = 0x0cd00065;
- break;
- case IDE_UDMA2_ENABLE:
- timings = 0x11100065;
- break;
- }
-
+ if (!drive->init_speed)
+ drive->init_speed = feature;
+
+ /* which drive is it ? */
if (drive->select.all & 0x10)
- pmac_ide[idx].timings[1] = timings;
+ timings = &pmac_ide[idx].timings[1];
else
- pmac_ide[idx].timings[0] = timings;
-
+ timings = &pmac_ide[idx].timings[0];
+
+ cycleTime = udma_timings[feature & 0xf].cycleTime;
+ accessTime = udma_timings[feature & 0xf].accessTime;
+
+ rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);
+ cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);
+
+ *timings = ((*timings) & 0xe00fffff) |
+ ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;
+
+ drive->current_speed = feature;
return 1;
}
@@ -792,6 +813,12 @@
return 0;
}
+static int
+pmac_ide_tune_chipset(ide_drive_t *drive, byte speed)
+{
+ return 0;
+}
+
int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -813,6 +840,7 @@
pmac_ide_dma_onoff(drive, (func == ide_dma_on));
break;
case ide_dma_check:
+ printk("IDE-DMA check !\n");
if (hwif->autodma)
pmac_ide_dma_onoff(drive, 1);
break;
@@ -837,8 +865,21 @@
return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
case ide_dma_test_irq:
return (in_le32(&dma->status) & (RUN|ACTIVE)) == RUN;
+
+ /* Let's implement tose just in case someone wants them */
+ case ide_dma_bad_drive:
+ case ide_dma_good_drive:
+ return check_drive_lists(drive, (func == ide_dma_good_drive));
+ case ide_dma_verbose:
+ return report_drive_dmaing(drive);
+ case ide_dma_retune:
+ case ide_dma_lostirq:
+ case ide_dma_timeout:
+ printk("ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func);
+ return 1;
default:
- printk(KERN_ERR "pmac_ide_dmaproc: bad func %d\n", func);
+ printk("ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
+ return 1;
}
return 0;
}
@@ -869,8 +910,20 @@
}
}
feature_set(np, FEATURE_IDE0_reset);
- feature_clear(np, FEATURE_IOBUS_enable);
feature_clear(np, FEATURE_IDE0_enable);
+ switch(pmac_ide[i].aapl_bus_id) {
+ case 0:
+ feature_set(np, FEATURE_IDE0_reset);
+ feature_clear(np, FEATURE_IDE0_enable);
+ break;
+ case 1:
+ feature_set(np, FEATURE_IDE1_reset);
+ feature_clear(np, FEATURE_IDE1_enable);
+ break;
+ case 2:
+ feature_set(np, FEATURE_IDE2_reset);
+ break;
+ }
pmac_ide[i].timings[0] = 0;
pmac_ide[i].timings[1] = 0;
}
@@ -881,12 +934,30 @@
int j;
/* Revive IDE disk and controller */
- feature_set(np, FEATURE_IOBUS_enable);
- mdelay(10);
- feature_set(np, FEATURE_IDE0_enable);
- mdelay(10);
- feature_clear(np, FEATURE_IDE0_reset);
- mdelay(100);
+ switch(pmac_ide[i].aapl_bus_id) {
+ case 0:
+ feature_set(np, FEATURE_IDE0_reset);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE0_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE0_reset);
+ break;
+ case 1:
+ feature_set(np, FEATURE_IDE1_reset);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE1_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE1_reset);
+ break;
+ case 2:
+ /* This one exists only for KL, I don't know
+ about any enable bit */
+ feature_set(np, FEATURE_IDE2_reset);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE2_reset);
+ break;
+ }
+ mdelay(IDE_WAKEUP_DELAY_MS);
/* Reset timings */
pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
@@ -940,7 +1011,7 @@
/* Disable irq during sleep */
disable_irq(pmac_ide[i].irq);
ret = check_media_bay_by_base(base, MB_CD);
- if (ret == -ENODEV)
+ if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
/* not media bay - put the disk to sleep */
idepmac_sleep_disk(i, base);
}
@@ -953,7 +1024,7 @@
hwif = &ide_hwifs[i];
/* We don't handle media bay devices this way */
ret = check_media_bay_by_base(base, MB_CD);
- if (ret == -ENODEV)
+ if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
idepmac_wake_disk(i, base);
else if (ret == 0)
idepmac_wake_bay(i, base);
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen (who was at: [email protected])