ide: add PIO masks
[linux-2.6-block.git] / drivers / ide / pci / siimage.c
index 71eccdf5f817f10880e803c361a3e7983031e235..50f6d172ef7715dc8371933af223ced8d02a8384 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * linux/drivers/ide/pci/siimage.c             Version 1.11    Jan 27, 2007
+ * linux/drivers/ide/pci/siimage.c             Version 1.15    Jun 29 2007
  *
  * Copyright (C) 2001-2002     Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2003          Red Hat <alan@redhat.com>
  * Copyright (C) 2007          MontaVista Software, Inc.
+ * Copyright (C) 2007          Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
  *
  *  unplugging/replugging the virtual CD interface when the DRAC is reset.
  *  This often causes drivers/ide/siimage to panic but is ok with the rather
  *  smarter code in libata.
+ *
+ * TODO:
+ * - IORDY fixes
+ * - VDMA support
  */
 
 #include <linux/types.h>
@@ -122,124 +127,83 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
 }
 
 /**
- *     siimage_ratemask        -       Compute available modes
- *     @drive: IDE drive
+ *     sil_udma_filter         -       compute UDMA mask
+ *     @drive: IDE device
+ *
+ *     Compute the available UDMA speeds for the device on the interface.
  *
- *     Compute the available speeds for the devices on the interface.
  *     For the CMD680 this depends on the clocking mode (scsc), for the
- *     SI3312 SATA controller life is a bit simpler. Enforce UDMA33
- *     as a limit if there is no 80pin cable present.
+ *     SI3112 SATA controller life is a bit simpler.
  */
-static byte siimage_ratemask (ide_drive_t *drive)
+
+static u8 sil_udma_filter(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 mode = 0, scsc = 0;
+       ide_hwif_t *hwif = drive->hwif;
        unsigned long base = (unsigned long) hwif->hwif_data;
+       u8 mask = 0, scsc = 0;
 
        if (hwif->mmio)
                scsc = hwif->INB(base + 0x4A);
        else
                pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 
-       if(is_sata(hwif))
-       {
-               if(strstr(drive->id->model, "Maxtor"))
-                       return 3;
-               return 4;
+       if (is_sata(hwif)) {
+               mask = strstr(drive->id->model, "Maxtor") ? 0x3f : 0x7f;
+               goto out;
        }
-       
+
        if ((scsc & 0x30) == 0x10)      /* 133 */
-               mode = 4;
+               mask = 0x7f;
        else if ((scsc & 0x30) == 0x20) /* 2xPCI */
-               mode = 4;
+               mask = 0x7f;
        else if ((scsc & 0x30) == 0x00) /* 100 */
-               mode = 3;
+               mask = 0x3f;
        else    /* Disabled ? */
                BUG();
-
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
+out:
+       return mask;
 }
 
 /**
- *     siimage_taskfile_timing -       turn timing data to a mode
- *     @hwif: interface to query
- *
- *     Read the timing data for the interface and return the 
- *     mode that is being used.
- */
-static byte siimage_taskfile_timing (ide_hwif_t *hwif)
-{
-       u16 timing      = 0x328a;
-       unsigned long addr = siimage_selreg(hwif, 2);
-
-       if (hwif->mmio)
-               timing = hwif->INW(addr);
-       else
-               pci_read_config_word(hwif->pci_dev, addr, &timing);
-
-       switch (timing) {
-               case 0x10c1:    return 4;
-               case 0x10c3:    return 3;
-               case 0x1104:
-               case 0x1281:    return 2;
-               case 0x2283:    return 1;
-               case 0x328a:
-               default:        return 0;
-       }
-}
-
-/**
- *     simmage_tuneproc        -       tune a drive
+ *     sil_tune_pio    -       tune a drive
  *     @drive: drive to tune
- *     @mode_wanted: the target operating mode
+ *     @pio: the desired PIO mode
  *
  *     Load the timing settings for this device mode into the
  *     controller. If we are in PIO mode 3 or 4 turn on IORDY
  *     monitoring (bit 9). The TF timing is bits 31:16
  */
-static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+
+static void sil_tune_pio(ide_drive_t *drive, u8 pio)
 {
+       const u16 tf_speed[]    = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
+       const u16 data_speed[]  = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+
        ide_hwif_t *hwif        = HWIF(drive);
+       ide_drive_t *pair       = &hwif->drives[drive->dn ^ 1];
        u32 speedt              = 0;
        u16 speedp              = 0;
        unsigned long addr      = siimage_seldev(drive, 0x04);
        unsigned long tfaddr    = siimage_selreg(hwif, 0x02);
-       
-       /* cheat for now and use the docs */
-       switch (mode_wanted) {
-       case 4:
-               speedp = 0x10c1;
-               speedt = 0x10c1;
-               break;
-       case 3:
-               speedp = 0x10c3;
-               speedt = 0x10c3;
-               break;
-       case 2:
-               speedp = 0x1104;
-               speedt = 0x1281;
-               break;
-       case 1:
-               speedp = 0x2283;
-               speedt = 0x2283;
-               break;
-       case 0:
-       default:
-               speedp = 0x328a;
-               speedt = 0x328a;
-               break;
+       u8 tf_pio               = pio;
+
+       /* trim *taskfile* PIO to the slowest of the master/slave */
+       if (pair->present) {
+               u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+
+               if (pair_pio < tf_pio)
+                       tf_pio = pair_pio;
        }
 
+       /* cheat for now and use the docs */
+       speedp = data_speed[pio];
+       speedt = tf_speed[tf_pio];
+
        if (hwif->mmio) {
                hwif->OUTW(speedp, addr);
                hwif->OUTW(speedt, tfaddr);
                /* Now set up IORDY */
-               if(mode_wanted == 3 || mode_wanted == 4)
+               if (pio > 2)
                        hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
                else
                        hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
@@ -249,47 +213,17 @@ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
                pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
                speedp &= ~0x200;
                /* Set IORDY for mode 3 or 4 */
-               if(mode_wanted == 3 || mode_wanted == 4)
+               if (pio > 2)
                        speedp |= 0x200;
                pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
        }
 }
 
-/**
- *     config_siimage_chipset_for_pio  -       set drive timings
- *     @drive: drive to tune
- *     @speed we want
- *
- *     Compute the best pio mode we can for a given device. Also honour
- *     the timings for the driver when dealing with mixed devices. Some
- *     of this is ugly but its all wrapped up here
- *
- *     The SI680 can also do VDMA - we need to start using that
- *
- *     FIXME: we use the BIOS channel timings to avoid driving the task
- *     files too fast at the disk. We need to compute the master/slave
- *     drive PIO mode properly so that we can up the speed on a hotplug
- *     system.
- */
-static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static void sil_tuneproc(ide_drive_t *drive, u8 pio)
 {
-       u8 channel_timings      = siimage_taskfile_timing(HWIF(drive));
-       u8 speed = 0, set_pio   = ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-       /* 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;
-
-       siimage_tuneproc(drive, set_pio);
-       speed = XFER_PIO_0 + set_pio;
-       if (set_speed)
-               (void) ide_config_drive_speed(drive, speed);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-       config_siimage_chipset_for_pio(drive, set_speed);
+       pio = ide_get_best_pio_mode(drive, pio, 4);
+       sil_tune_pio(drive, pio);
+       (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 /**
@@ -311,7 +245,7 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
        ide_hwif_t *hwif        = HWIF(drive);
        u16 ultra = 0, multi    = 0;
        u8 mode = 0, unit       = drive->select.b.unit;
-       u8 speed                = ide_rate_filter(siimage_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
        unsigned long base      = (unsigned long)hwif->hwif_data;
        u8 scsc = 0, addr_mask  = ((hwif->channel) ?
                                    ((hwif->mmio) ? 0xF4 : 0x84) :
@@ -344,7 +278,7 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
                case XFER_PIO_2:
                case XFER_PIO_1:
                case XFER_PIO_0:
-                       siimage_tuneproc(drive, (speed - XFER_PIO_0));
+                       sil_tune_pio(drive, speed - XFER_PIO_0);
                        mode |= ((unit) ? 0x10 : 0x01);
                        break;
                case XFER_MW_DMA_2:
@@ -352,7 +286,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
                case XFER_MW_DMA_0:
                        multi = dma[speed - XFER_MW_DMA_0];
                        mode |= ((unit) ? 0x20 : 0x02);
-                       config_siimage_chipset_for_pio(drive, 0);
                        break;
                case XFER_UDMA_6:
                case XFER_UDMA_5:
@@ -365,7 +298,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
                        ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
                                           (ultra5[speed - XFER_UDMA_0]));
                        mode |= ((unit) ? 0x30 : 0x03);
-                       config_siimage_chipset_for_pio(drive, 0);
                        break;
                default:
                        return 1;
@@ -383,30 +315,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
        return (ide_config_drive_speed(drive, speed));
 }
 
-/**
- *     config_chipset_for_dma  -       configure for DMA
- *     @drive: drive to configure
- *
- *     Called by the IDE layer when it wants the timings set up.
- *     For the CMD680 we also need to set up the PIO timings and
- *     enable DMA.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-       u8 speed        = ide_dma_speed(drive, siimage_ratemask(drive));
-
-       config_chipset_for_pio(drive, !speed);
-
-       if (!speed)
-               return 0;
-
-       if (siimage_tune_chipset(drive, speed))
-               return 0;
-
-       return ide_dma_enable(drive);
-}
-
 /**
  *     siimage_configure_drive_for_dma -       set up for DMA transfers
  *     @drive: drive we are going to set up
@@ -419,11 +327,11 @@ static int config_chipset_for_dma (ide_drive_t *drive)
  
 static int siimage_config_drive_for_dma (ide_drive_t *drive)
 {
-       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+       if (ide_tune_dma(drive))
                return 0;
 
        if (ide_use_fast_pio(drive))
-               config_chipset_for_pio(drive, 1);
+               sil_tuneproc(drive, 255);
 
        return -1;
 }
@@ -838,7 +746,7 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
 
        /*
         *      Now set up the hw. We have to do this ourselves as
-        *      the MMIO layout isnt the same as the the standard port
+        *      the MMIO layout isnt the same as the standard port
         *      based I/O
         */
 
@@ -966,16 +874,17 @@ static void __devinit init_iops_siimage(ide_hwif_t *hwif)
  *     interface.
  */
 
-static unsigned int __devinit ata66_siimage(ide_hwif_t *hwif)
+static u8 __devinit ata66_siimage(ide_hwif_t *hwif)
 {
        unsigned long addr = siimage_selreg(hwif, 0);
-       if (pci_get_drvdata(hwif->pci_dev) == NULL) {
-               u8 ata66 = 0;
+       u8 ata66 = 0;
+
+       if (pci_get_drvdata(hwif->pci_dev) == NULL)
                pci_read_config_byte(hwif->pci_dev, addr, &ata66);
-               return (ata66 & 0x01) ? 1 : 0;
-       }
+       else
+               ata66 = hwif->INB(addr);
 
-       return (hwif->INB(addr) & 0x01) ? 1 : 0;
+       return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 }
 
 /**
@@ -993,9 +902,10 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
        
        hwif->resetproc = &siimage_reset;
        hwif->speedproc = &siimage_tune_chipset;
-       hwif->tuneproc  = &siimage_tuneproc;
+       hwif->tuneproc  = &sil_tuneproc;
        hwif->reset_poll = &siimage_reset_poll;
        hwif->pre_reset = &siimage_pre_reset;
+       hwif->udma_filter = &sil_udma_filter;
 
        if(is_sata(hwif)) {
                static int first = 1;
@@ -1007,22 +917,22 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
                        first = 0;
                }
        }
-       if (!hwif->dma_base) {
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
+
+       hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+       if (hwif->dma_base == 0)
                return;
-       }
 
        hwif->ultra_mask = 0x7f;
        hwif->mwdma_mask = 0x07;
-       hwif->swdma_mask = 0x07;
 
        if (!is_sata(hwif))
                hwif->atapi_dma = 1;
 
        hwif->ide_dma_check = &siimage_config_drive_for_dma;
-       if (!(hwif->udma_four))
-               hwif->udma_four = ata66_siimage(hwif);
+
+       if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+               hwif->cbl = ata66_siimage(hwif);
 
        if (hwif->mmio) {
                hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
@@ -1047,9 +957,9 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
                .init_iops      = init_iops_siimage,    \
                .init_hwif      = init_hwif_siimage,    \
                .fixup          = siimage_fixup,        \
-               .channels       = 2,                    \
                .autodma        = AUTODMA,              \
                .bootable       = ON_BOARD,             \
+               .pio_mask       = ATA_PIO4,             \
        }
 
 static ide_pci_device_t siimage_chipsets[] __devinitdata = {