patch-2.4.19 linux-2.4.19/drivers/ide/cmd64x.c
Next file: linux-2.4.19/drivers/ide/falconide.c
Previous file: linux-2.4.19/drivers/ide/buddha.c
Back to the patch index
Back to the overall index
- Lines: 538
- Date:
Fri Aug 2 17:39:44 2002
- Orig file:
linux-2.4.18/drivers/ide/cmd64x.c
- Orig date:
Thu Jul 27 16:40:57 2000
diff -urN linux-2.4.18/drivers/ide/cmd64x.c linux-2.4.19/drivers/ide/cmd64x.c
@@ -86,6 +86,7 @@
#include <linux/proc_fs.h>
static int cmd64x_get_info(char *, char **, off_t, int);
+static int cmd680_get_info(char *, char **, off_t, int);
extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
extern char *ide_media_verbose(ide_drive_t *);
static struct pci_dev *bmide_dev;
@@ -180,24 +181,21 @@
return p-buffer; /* => must be less than 4k! */
}
-#if 0
-static char * cmd64x_chipset_data (char *buf, struct pci_dev *dev)
-{
- char *p = buf;
- p += sprintf(p, "thingy stuff\n");
- return (char *)p;
-}
-static int __init cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
- p = cmd64x_chipset_data(buffer, bmide_dev);
- return p-buffer; /* hoping it is less than 4K... */
+ p += sprintf(p, "\n CMD680 Chipset.\n");
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "PIO Mode: %s %s %s %s\n",
+ "?", "?", "?", "?");
+ return p-buffer; /* => must be less than 4k! */
}
-#endif
#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
byte cmd64x_proc = 0;
+byte cmd680_proc = 0;
/*
* Registers and masks for easy access by drive index:
@@ -345,10 +343,58 @@
setup_count, active_count, recovery_count);
}
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
{
- byte speed= 0x00;
- byte set_pio= ide_get_best_pio_mode(drive, 4, 5, NULL);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte addr_mask = (hwif->channel) ? 0xB2 : 0xA2;
+ unsigned short timing;
+
+ pci_read_config_word(dev, addr_mask, &timing);
+
+ switch (timing) {
+ case 0x10c1: return 4;
+ case 0x10c3: return 3;
+ case 0x1281: return 2;
+ case 0x2283: return 1;
+ case 0x328a:
+ default: return 0;
+ }
+}
+
+static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ byte drive_pci;
+ unsigned short speedt;
+
+ switch (drive->dn) {
+ case 0: drive_pci = 0xA4; break;
+ case 1: drive_pci = 0xA6; break;
+ case 2: drive_pci = 0xB4; break;
+ case 3: drive_pci = 0xB6; break;
+ default: return;
+ }
+
+ pci_read_config_word(dev, drive_pci, &speedt);
+
+ /* cheat for now and use the docs */
+// switch(cmd680_taskfile_timing(hwif)) {
+ switch(mode_wanted) {
+ case 4: speedt = 0x10c1; break;
+ case 3: speedt = 0x10C3; break;
+ case 2: speedt = 0x1104; break;
+ case 1: speedt = 0x2283; break;
+ case 0:
+ default: speedt = 0x328A; break;
+ }
+ pci_write_config_word(dev, drive_pci, speedt);
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ byte speed = 0x00;
+ byte set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
cmd64x_tuneproc(drive, set_pio);
speed = XFER_PIO_0 + set_pio;
@@ -356,6 +402,41 @@
(void) ide_config_drive_speed(drive, speed);
}
+static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 speed = 0x00;
+ u8 mode_pci = 0x00;
+ u8 channel_timings = cmd680_taskfile_timing(hwif);
+ u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+ pci_read_config_byte(dev, addr_mask, &mode_pci);
+ mode_pci &= ~((unit) ? 0x30 : 0x03);
+
+ /* WARNING PIO timing mess is going to happen b/w devices, argh */
+ if ((channel_timings != set_pio) && (set_pio > channel_timings))
+ set_pio = channel_timings;
+
+ cmd680_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ if (set_speed) {
+ (void) ide_config_drive_speed(drive, speed);
+ drive->current_speed = speed;
+ }
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+ config_cmd680_chipset_for_pio(drive, set_speed);
+ } else {
+ config_cmd64x_chipset_for_pio(drive, set_speed);
+ }
+}
+
static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
@@ -363,7 +444,7 @@
struct pci_dev *dev = hwif->pci_dev;
int err = 0;
- byte unit = (drive->select.b.unit & 0x01);
+ u8 unit = (drive->select.b.unit & 0x01);
u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
u8 regU = 0;
@@ -424,8 +505,123 @@
return err;
}
+static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 addr_mask = (hwif->channel) ? 0x84 : 0x80;
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 dma_pci = 0;
+ u8 udma_pci = 0;
+ u8 mode_pci = 0;
+ u8 scsc = 0;
+ u16 ultra = 0;
+ u16 multi = 0;
+ int err = 0;
+
+ pci_read_config_byte(dev, addr_mask, &mode_pci);
+ pci_read_config_byte(dev, 0x8A, &scsc);
+
+ switch (drive->dn) {
+ case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
+ case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
+ case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
+ case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
+ default: return 1;
+ }
+
+ pci_read_config_byte(dev, addr_mask, &mode_pci);
+ mode_pci &= ~((unit) ? 0x30 : 0x03);
+ pci_read_config_word(dev, dma_pci, &multi);
+ pci_read_config_word(dev, udma_pci, &ultra);
+
+ if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
+ pci_write_config_byte(dev, 0x8A, scsc|0x01);
+ pci_read_config_byte(dev, 0x8A, &scsc);
+ }
+
+ switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ case XFER_UDMA_6:
+ if ((scsc & 0x30) == 0x00)
+ goto speed_break;
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= 0x01;
+ break;
+speed_break :
+ speed = XFER_UDMA_5;
+ case XFER_UDMA_5:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
+ break;
+ case XFER_UDMA_4:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
+ break;
+ case XFER_UDMA_3:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
+ break;
+ case XFER_UDMA_2:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
+ break;
+ case XFER_UDMA_1:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
+ break;
+ case XFER_UDMA_0:
+ multi = 0x10C1;
+ ultra &= ~0x3F;
+ ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
+ break;
+ case XFER_MW_DMA_2:
+ multi = 0x10C1;
+ break;
+ case XFER_MW_DMA_1:
+ multi = 0x10C2;
+ break;
+ case XFER_MW_DMA_0:
+ multi = 0x2208;
+ break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ case XFER_PIO_4: cmd680_tuneproc(drive, 4); break;
+ case XFER_PIO_3: cmd680_tuneproc(drive, 3); break;
+ case XFER_PIO_2: cmd680_tuneproc(drive, 2); break;
+ case XFER_PIO_1: cmd680_tuneproc(drive, 1); break;
+ case XFER_PIO_0: cmd680_tuneproc(drive, 0); break;
+ default:
+ return 1;
+ }
+
+
+ if (speed >= XFER_MW_DMA_0)
+ config_cmd680_chipset_for_pio(drive, 0);
+
+ if (speed >= XFER_UDMA_0)
+ mode_pci |= ((unit) ? 0x30 : 0x03);
+ else if (speed >= XFER_MW_DMA_0)
+ mode_pci |= ((unit) ? 0x20 : 0x02);
+ else
+ mode_pci |= ((unit) ? 0x10 : 0x01);
+
+ pci_write_config_byte(dev, addr_mask, mode_pci);
+ pci_write_config_word(dev, dma_pci, multi);
+ pci_write_config_word(dev, udma_pci, ultra);
+
+ err = ide_config_drive_speed(drive, speed);
+ drive->current_speed = speed;
+ return err;
+}
+
#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = HWIF(drive);
@@ -510,6 +706,55 @@
return rval;
}
+static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ byte udma_66 = eighty_ninty_three(drive);
+ byte speed = 0x00;
+ byte set_pio = 0x00;
+ int rval;
+
+ if ((id->dma_ultra & 0x0040) && (udma_66)) speed = XFER_UDMA_6;
+ else if ((id->dma_ultra & 0x0020) && (udma_66)) speed = XFER_UDMA_5;
+ else if ((id->dma_ultra & 0x0010) && (udma_66)) speed = XFER_UDMA_4;
+ else if ((id->dma_ultra & 0x0008) && (udma_66)) speed = XFER_UDMA_3;
+ else if (id->dma_ultra & 0x0004) speed = XFER_UDMA_2;
+ else if (id->dma_ultra & 0x0002) speed = XFER_UDMA_1;
+ else if (id->dma_ultra & 0x0001) speed = XFER_UDMA_0;
+ else if (id->dma_mword & 0x0004) speed = XFER_MW_DMA_2;
+ else if (id->dma_mword & 0x0002) speed = XFER_MW_DMA_1;
+ else if (id->dma_mword & 0x0001) speed = XFER_MW_DMA_0;
+ else {
+ set_pio = 1;
+ }
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+
+ config_chipset_for_pio(drive, set_pio);
+
+ if (set_pio)
+ return ((int) ide_dma_off_quietly);
+
+ if (cmd680_tune_chipset(drive, speed))
+ return ((int) ide_dma_off);
+
+ rval = (int)( ((id->dma_ultra >> 14) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
+ return rval;
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
+{
+ if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+ return (config_cmd680_chipset_for_dma(drive));
+ return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
+}
+
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -519,12 +764,15 @@
byte can_ultra_33 = 0;
byte can_ultra_66 = 0;
byte can_ultra_100 = 0;
+ byte can_ultra_133 = 0;
ide_dma_action_t dma_func = ide_dma_on;
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_680:
+ can_ultra_133 = 1;
case PCI_DEVICE_ID_CMD_649:
can_ultra_100 = 1;
case PCI_DEVICE_ID_CMD_648:
@@ -550,7 +798,7 @@
}
dma_func = ide_dma_off_quietly;
if ((id->field_valid & 4) && (can_ultra_33)) {
- if (id->dma_ultra & 0x002F) {
+ if (id->dma_ultra & 0x007F) {
/* Force if Capable UltraDMA */
dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
if ((id->field_valid & 2) &&
@@ -586,6 +834,18 @@
return HWIF(drive)->dmaproc(dma_func, drive);
}
+static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch (func) {
+ case ide_dma_check:
+ return cmd64x_config_drive_for_dma(drive);
+ default:
+ break;
+ }
+ /* Other cases are done by generic IDE-DMA code. */
+ return ide_dmaproc(func, drive);
+}
+
static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
byte dma_stat = 0;
@@ -663,7 +923,78 @@
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+static int cmd680_busproc (ide_drive_t * drive, int state)
+{
+#if 0
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ u32 stat_config = 0;
+
+ pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
+
+ if (!hwif)
+ return -EINVAL;
+
+ switch (state) {
+ case BUSSTATE_ON:
+ hwif->drives[0].failures = 0;
+ hwif->drives[1].failures = 0;
+ break;
+ case BUSSTATE_OFF:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ case BUSSTATE_TRISTATE:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ default:
+ return 0;
+ }
+ hwif->bus_state = state;
+#endif
+ return 0;
+}
+
+void cmd680_reset (ide_drive_t *drive)
+{
+#if 0
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+ byte reset = 0;
+
+ pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
+ pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
+#endif
+}
+
+unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
+{
+ u8 tmpbyte = 0;
+ pci_write_config_byte(dev, 0x80, 0x00);
+ pci_write_config_byte(dev, 0x84, 0x00);
+ pci_read_config_byte(dev, 0x8A, &tmpbyte);
+ pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
+ pci_write_config_word(dev, 0xA2, 0x328A);
+ pci_write_config_dword(dev, 0xA4, 0x328A);
+ pci_write_config_dword(dev, 0xA8, 0x4392);
+ pci_write_config_dword(dev, 0xAC, 0x4009);
+ pci_write_config_word(dev, 0xB2, 0x328A);
+ pci_write_config_dword(dev, 0xB4, 0x328A);
+ pci_write_config_dword(dev, 0xB8, 0x4392);
+ pci_write_config_dword(dev, 0xBC, 0x4009);
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!cmd64x_proc) {
+ cmd64x_proc = 1;
+ bmide_dev = dev;
+ cmd64x_display_info = &cmd680_get_info;
+ }
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+ return 0;
+}
+
+unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
{
unsigned char mrdmode;
unsigned int class_rev;
@@ -752,7 +1083,23 @@
return 0;
}
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+{
+ if (dev->device == PCI_DEVICE_ID_CMD_680)
+ return cmd680_pci_init (dev, name);
+ return cmd64x_pci_init (dev, name);
+}
+
+unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+{
+ byte ata66 = 0;
+ byte addr_mask = (hwif->channel) ? 0xB0 : 0xA0;
+
+ pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
+ return (ata66 & 0x01) ? 1 : 0;
+}
+
+unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
{
byte ata66 = 0;
byte mask = (hwif->channel) ? 0x02 : 0x01;
@@ -761,6 +1108,14 @@
return (ata66 & mask) ? 1 : 0;
}
+unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->device == PCI_DEVICE_ID_CMD_680)
+ return cmd680_ata66(hwif);
+ return cmd64x_ata66(hwif);
+}
+
void __init ide_init_cmd64x (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
@@ -769,8 +1124,6 @@
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
- hwif->tuneproc = &cmd64x_tuneproc;
- hwif->speedproc = &cmd64x_tune_chipset;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
@@ -779,10 +1132,19 @@
#ifdef CONFIG_BLK_DEV_IDEDMA
switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_680:
+ hwif->busproc = &cmd680_busproc;
+ hwif->dmaproc = &cmd680_dmaproc;
+ hwif->resetproc = &cmd680_reset;
+ hwif->speedproc = &cmd680_tune_chipset;
+ hwif->tuneproc = &cmd680_tuneproc;
+ break;
case PCI_DEVICE_ID_CMD_649:
case PCI_DEVICE_ID_CMD_648:
case PCI_DEVICE_ID_CMD_643:
- hwif->dmaproc = &cmd64x_dmaproc;
+ hwif->dmaproc = &cmd64x_dmaproc;
+ hwif->tuneproc = &cmd64x_tuneproc;
+ hwif->speedproc = &cmd64x_tune_chipset;
break;
case PCI_DEVICE_ID_CMD_646:
hwif->chipset = ide_cmd646;
@@ -791,6 +1153,8 @@
} else {
hwif->dmaproc = &cmd64x_dmaproc;
}
+ hwif->tuneproc = &cmd64x_tuneproc;
+ hwif->speedproc = &cmd64x_tune_chipset;
break;
default:
break;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)