linux/drivers/ata/pata_triflex.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * pata_triflex.c       - Compaq PATA for new ATA layer
   4 *                        (C) 2005 Red Hat Inc
   5 *                        Alan Cox <alan@lxorguk.ukuu.org.uk>
   6 *
   7 * based upon
   8 *
   9 * triflex.c
  10 *
  11 * IDE Chipset driver for the Compaq TriFlex IDE controller.
  12 *
  13 * Known to work with the Compaq Workstation 5x00 series.
  14 *
  15 * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
  16 * Author: Torben Mathiasen <torben.mathiasen@hp.com>
  17 *
  18 * Loosely based on the piix & svwks drivers.
  19 *
  20 * Documentation:
  21 *      Not publicly available.
  22 */
  23
  24#include <linux/kernel.h>
  25#include <linux/module.h>
  26#include <linux/pci.h>
  27#include <linux/blkdev.h>
  28#include <linux/delay.h>
  29#include <scsi/scsi_host.h>
  30#include <linux/libata.h>
  31
  32#define DRV_NAME "pata_triflex"
  33#define DRV_VERSION "0.2.8"
  34
  35/**
  36 *      triflex_prereset                -       probe begin
  37 *      @link: ATA link
  38 *      @deadline: deadline jiffies for the operation
  39 *
  40 *      Set up cable type and use generic probe init
  41 */
  42
  43static int triflex_prereset(struct ata_link *link, unsigned long deadline)
  44{
  45        static const struct pci_bits triflex_enable_bits[] = {
  46                { 0x80, 1, 0x01, 0x01 },
  47                { 0x80, 1, 0x02, 0x02 }
  48        };
  49
  50        struct ata_port *ap = link->ap;
  51        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  52
  53        if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
  54                return -ENOENT;
  55
  56        return ata_sff_prereset(link, deadline);
  57}
  58
  59
  60
  61/**
  62 *      triflex_load_timing             -       timing configuration
  63 *      @ap: ATA interface
  64 *      @adev: Device on the bus
  65 *      @speed: speed to configure
  66 *
  67 *      The Triflex has one set of timings per device per channel. This
  68 *      means we must do some switching. As the PIO and DMA timings don't
  69 *      match we have to do some reloading unlike PIIX devices where tuning
  70 *      tricks can avoid it.
  71 */
  72
  73static void triflex_load_timing(struct ata_port *ap, struct ata_device *adev, int speed)
  74{
  75        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  76        u32 timing = 0;
  77        u32 triflex_timing, old_triflex_timing;
  78        int channel_offset = ap->port_no ? 0x74: 0x70;
  79        unsigned int is_slave   = (adev->devno != 0);
  80
  81
  82        pci_read_config_dword(pdev, channel_offset, &old_triflex_timing);
  83        triflex_timing = old_triflex_timing;
  84
  85        switch(speed)
  86        {
  87                case XFER_MW_DMA_2:
  88                        timing = 0x0103;break;
  89                case XFER_MW_DMA_1:
  90                        timing = 0x0203;break;
  91                case XFER_MW_DMA_0:
  92                        timing = 0x0808;break;
  93                case XFER_SW_DMA_2:
  94                case XFER_SW_DMA_1:
  95                case XFER_SW_DMA_0:
  96                        timing = 0x0F0F;break;
  97                case XFER_PIO_4:
  98                        timing = 0x0202;break;
  99                case XFER_PIO_3:
 100                        timing = 0x0204;break;
 101                case XFER_PIO_2:
 102                        timing = 0x0404;break;
 103                case XFER_PIO_1:
 104                        timing = 0x0508;break;
 105                case XFER_PIO_0:
 106                        timing = 0x0808;break;
 107                default:
 108                        BUG();
 109        }
 110        triflex_timing &= ~ (0xFFFF << (16 * is_slave));
 111        triflex_timing |= (timing << (16 * is_slave));
 112
 113        if (triflex_timing != old_triflex_timing)
 114                pci_write_config_dword(pdev, channel_offset, triflex_timing);
 115}
 116
 117/**
 118 *      triflex_set_piomode     -       set initial PIO mode data
 119 *      @ap: ATA interface
 120 *      @adev: ATA device
 121 *
 122 *      Use the timing loader to set up the PIO mode. We have to do this
 123 *      because DMA start/stop will only be called once DMA occurs. If there
 124 *      has been no DMA then the PIO timings are still needed.
 125 */
 126static void triflex_set_piomode(struct ata_port *ap, struct ata_device *adev)
 127{
 128        triflex_load_timing(ap, adev, adev->pio_mode);
 129}
 130
 131/**
 132 *      triflex_bmdma_start     -       DMA start callback
 133 *      @qc: Command in progress
 134 *
 135 *      Usually drivers set the DMA timing at the point the set_dmamode call
 136 *      is made. Triflex however requires we load new timings on the
 137 *      transition or keep matching PIO/DMA pairs (ie MWDMA2/PIO4 etc).
 138 *      We load the DMA timings just before starting DMA and then restore
 139 *      the PIO timing when the DMA is finished.
 140 */
 141
 142static void triflex_bmdma_start(struct ata_queued_cmd *qc)
 143{
 144        triflex_load_timing(qc->ap, qc->dev, qc->dev->dma_mode);
 145        ata_bmdma_start(qc);
 146}
 147
 148/**
 149 *      triflex_bmdma_stop      -       DMA stop callback
 150 *      @qc: ATA command
 151 *
 152 *      We loaded new timings in dma_start, as a result we need to restore
 153 *      the PIO timings in dma_stop so that the next command issue gets the
 154 *      right clock values.
 155 */
 156
 157static void triflex_bmdma_stop(struct ata_queued_cmd *qc)
 158{
 159        ata_bmdma_stop(qc);
 160        triflex_load_timing(qc->ap, qc->dev, qc->dev->pio_mode);
 161}
 162
 163static struct scsi_host_template triflex_sht = {
 164        ATA_BMDMA_SHT(DRV_NAME),
 165};
 166
 167static struct ata_port_operations triflex_port_ops = {
 168        .inherits       = &ata_bmdma_port_ops,
 169        .bmdma_start    = triflex_bmdma_start,
 170        .bmdma_stop     = triflex_bmdma_stop,
 171        .cable_detect   = ata_cable_40wire,
 172        .set_piomode    = triflex_set_piomode,
 173        .prereset       = triflex_prereset,
 174};
 175
 176static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 177{
 178        static const struct ata_port_info info = {
 179                .flags = ATA_FLAG_SLAVE_POSS,
 180                .pio_mask = ATA_PIO4,
 181                .mwdma_mask = ATA_MWDMA2,
 182                .port_ops = &triflex_port_ops
 183        };
 184        const struct ata_port_info *ppi[] = { &info, NULL };
 185
 186        ata_print_version_once(&dev->dev, DRV_VERSION);
 187
 188        return ata_pci_bmdma_init_one(dev, ppi, &triflex_sht, NULL, 0);
 189}
 190
 191static const struct pci_device_id triflex[] = {
 192        { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
 193
 194        { },
 195};
 196
 197#ifdef CONFIG_PM_SLEEP
 198static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 199{
 200        struct ata_host *host = pci_get_drvdata(pdev);
 201        int rc = 0;
 202
 203        rc = ata_host_suspend(host, mesg);
 204        if (rc)
 205                return rc;
 206
 207        /*
 208         * We must not disable or powerdown the device.
 209         * APM bios refuses to suspend if IDE is not accessible.
 210         */
 211        pci_save_state(pdev);
 212
 213        return 0;
 214}
 215
 216#endif
 217
 218static struct pci_driver triflex_pci_driver = {
 219        .name           = DRV_NAME,
 220        .id_table       = triflex,
 221        .probe          = triflex_init_one,
 222        .remove         = ata_pci_remove_one,
 223#ifdef CONFIG_PM_SLEEP
 224        .suspend        = triflex_ata_pci_device_suspend,
 225        .resume         = ata_pci_device_resume,
 226#endif
 227};
 228
 229module_pci_driver(triflex_pci_driver);
 230
 231MODULE_AUTHOR("Alan Cox");
 232MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
 233MODULE_LICENSE("GPL");
 234MODULE_DEVICE_TABLE(pci, triflex);
 235MODULE_VERSION(DRV_VERSION);
 236