145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2669a5db4SJeff Garzik /*
3669a5db4SJeff Garzik * pata_triflex.c - Compaq PATA for new ATA layer
4669a5db4SJeff Garzik * (C) 2005 Red Hat Inc
5ab771630SAlan Cox * Alan Cox <alan@lxorguk.ukuu.org.uk>
6669a5db4SJeff Garzik *
7669a5db4SJeff Garzik * based upon
8669a5db4SJeff Garzik *
9669a5db4SJeff Garzik * triflex.c
10669a5db4SJeff Garzik *
11669a5db4SJeff Garzik * IDE Chipset driver for the Compaq TriFlex IDE controller.
12669a5db4SJeff Garzik *
13669a5db4SJeff Garzik * Known to work with the Compaq Workstation 5x00 series.
14669a5db4SJeff Garzik *
15669a5db4SJeff Garzik * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
16669a5db4SJeff Garzik * Author: Torben Mathiasen <torben.mathiasen@hp.com>
17669a5db4SJeff Garzik *
18669a5db4SJeff Garzik * Loosely based on the piix & svwks drivers.
19669a5db4SJeff Garzik *
20669a5db4SJeff Garzik * Documentation:
2125985edcSLucas De Marchi * Not publicly available.
22669a5db4SJeff Garzik */
23669a5db4SJeff Garzik
24669a5db4SJeff Garzik #include <linux/kernel.h>
25669a5db4SJeff Garzik #include <linux/module.h>
26669a5db4SJeff Garzik #include <linux/pci.h>
27669a5db4SJeff Garzik #include <linux/blkdev.h>
28669a5db4SJeff Garzik #include <linux/delay.h>
29669a5db4SJeff Garzik #include <scsi/scsi_host.h>
30669a5db4SJeff Garzik #include <linux/libata.h>
31669a5db4SJeff Garzik
32669a5db4SJeff Garzik #define DRV_NAME "pata_triflex"
33a0fcdc02SJeff Garzik #define DRV_VERSION "0.2.8"
34669a5db4SJeff Garzik
35669a5db4SJeff Garzik /**
36c961922bSAlan Cox * triflex_prereset - probe begin
37cc0680a5STejun Heo * @link: ATA link
38d4b2bab4STejun Heo * @deadline: deadline jiffies for the operation
39669a5db4SJeff Garzik *
40669a5db4SJeff Garzik * Set up cable type and use generic probe init
41669a5db4SJeff Garzik */
42669a5db4SJeff Garzik
triflex_prereset(struct ata_link * link,unsigned long deadline)43cc0680a5STejun Heo static int triflex_prereset(struct ata_link *link, unsigned long deadline)
44669a5db4SJeff Garzik {
45669a5db4SJeff Garzik static const struct pci_bits triflex_enable_bits[] = {
46669a5db4SJeff Garzik { 0x80, 1, 0x01, 0x01 },
47669a5db4SJeff Garzik { 0x80, 1, 0x02, 0x02 }
48669a5db4SJeff Garzik };
49669a5db4SJeff Garzik
50cc0680a5STejun Heo struct ata_port *ap = link->ap;
51669a5db4SJeff Garzik struct pci_dev *pdev = to_pci_dev(ap->host->dev);
52669a5db4SJeff Garzik
53c961922bSAlan Cox if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
54c961922bSAlan Cox return -ENOENT;
55d4b2bab4STejun Heo
569363c382STejun Heo return ata_sff_prereset(link, deadline);
57669a5db4SJeff Garzik }
58669a5db4SJeff Garzik
59669a5db4SJeff Garzik
60669a5db4SJeff Garzik
61669a5db4SJeff Garzik /**
62669a5db4SJeff Garzik * triflex_load_timing - timing configuration
63669a5db4SJeff Garzik * @ap: ATA interface
64669a5db4SJeff Garzik * @adev: Device on the bus
65669a5db4SJeff Garzik * @speed: speed to configure
66669a5db4SJeff Garzik *
67669a5db4SJeff Garzik * The Triflex has one set of timings per device per channel. This
68669a5db4SJeff Garzik * means we must do some switching. As the PIO and DMA timings don't
69669a5db4SJeff Garzik * match we have to do some reloading unlike PIIX devices where tuning
70669a5db4SJeff Garzik * tricks can avoid it.
71669a5db4SJeff Garzik */
72669a5db4SJeff Garzik
triflex_load_timing(struct ata_port * ap,struct ata_device * adev,int speed)73669a5db4SJeff Garzik static void triflex_load_timing(struct ata_port *ap, struct ata_device *adev, int speed)
74669a5db4SJeff Garzik {
75669a5db4SJeff Garzik struct pci_dev *pdev = to_pci_dev(ap->host->dev);
76669a5db4SJeff Garzik u32 timing = 0;
77669a5db4SJeff Garzik u32 triflex_timing, old_triflex_timing;
78669a5db4SJeff Garzik int channel_offset = ap->port_no ? 0x74: 0x70;
79669a5db4SJeff Garzik unsigned int is_slave = (adev->devno != 0);
80669a5db4SJeff Garzik
81669a5db4SJeff Garzik
82669a5db4SJeff Garzik pci_read_config_dword(pdev, channel_offset, &old_triflex_timing);
83669a5db4SJeff Garzik triflex_timing = old_triflex_timing;
84669a5db4SJeff Garzik
85669a5db4SJeff Garzik switch(speed)
86669a5db4SJeff Garzik {
87669a5db4SJeff Garzik case XFER_MW_DMA_2:
88669a5db4SJeff Garzik timing = 0x0103;break;
89669a5db4SJeff Garzik case XFER_MW_DMA_1:
90669a5db4SJeff Garzik timing = 0x0203;break;
91669a5db4SJeff Garzik case XFER_MW_DMA_0:
92669a5db4SJeff Garzik timing = 0x0808;break;
93669a5db4SJeff Garzik case XFER_SW_DMA_2:
94669a5db4SJeff Garzik case XFER_SW_DMA_1:
95669a5db4SJeff Garzik case XFER_SW_DMA_0:
96669a5db4SJeff Garzik timing = 0x0F0F;break;
97669a5db4SJeff Garzik case XFER_PIO_4:
98669a5db4SJeff Garzik timing = 0x0202;break;
99669a5db4SJeff Garzik case XFER_PIO_3:
100669a5db4SJeff Garzik timing = 0x0204;break;
101669a5db4SJeff Garzik case XFER_PIO_2:
102669a5db4SJeff Garzik timing = 0x0404;break;
103669a5db4SJeff Garzik case XFER_PIO_1:
104669a5db4SJeff Garzik timing = 0x0508;break;
105669a5db4SJeff Garzik case XFER_PIO_0:
106669a5db4SJeff Garzik timing = 0x0808;break;
107669a5db4SJeff Garzik default:
108669a5db4SJeff Garzik BUG();
109669a5db4SJeff Garzik }
110669a5db4SJeff Garzik triflex_timing &= ~ (0xFFFF << (16 * is_slave));
111669a5db4SJeff Garzik triflex_timing |= (timing << (16 * is_slave));
112669a5db4SJeff Garzik
113669a5db4SJeff Garzik if (triflex_timing != old_triflex_timing)
114669a5db4SJeff Garzik pci_write_config_dword(pdev, channel_offset, triflex_timing);
115669a5db4SJeff Garzik }
116669a5db4SJeff Garzik
117669a5db4SJeff Garzik /**
118669a5db4SJeff Garzik * triflex_set_piomode - set initial PIO mode data
119669a5db4SJeff Garzik * @ap: ATA interface
120669a5db4SJeff Garzik * @adev: ATA device
121669a5db4SJeff Garzik *
122669a5db4SJeff Garzik * Use the timing loader to set up the PIO mode. We have to do this
123669a5db4SJeff Garzik * because DMA start/stop will only be called once DMA occurs. If there
124669a5db4SJeff Garzik * has been no DMA then the PIO timings are still needed.
125669a5db4SJeff Garzik */
triflex_set_piomode(struct ata_port * ap,struct ata_device * adev)126669a5db4SJeff Garzik static void triflex_set_piomode(struct ata_port *ap, struct ata_device *adev)
127669a5db4SJeff Garzik {
128669a5db4SJeff Garzik triflex_load_timing(ap, adev, adev->pio_mode);
129669a5db4SJeff Garzik }
130669a5db4SJeff Garzik
131669a5db4SJeff Garzik /**
1322ee628f3SLee Jones * triflex_bmdma_start - DMA start callback
133669a5db4SJeff Garzik * @qc: Command in progress
134669a5db4SJeff Garzik *
135669a5db4SJeff Garzik * Usually drivers set the DMA timing at the point the set_dmamode call
136669a5db4SJeff Garzik * is made. Triflex however requires we load new timings on the
137669a5db4SJeff Garzik * transition or keep matching PIO/DMA pairs (ie MWDMA2/PIO4 etc).
138669a5db4SJeff Garzik * We load the DMA timings just before starting DMA and then restore
139669a5db4SJeff Garzik * the PIO timing when the DMA is finished.
140669a5db4SJeff Garzik */
141669a5db4SJeff Garzik
triflex_bmdma_start(struct ata_queued_cmd * qc)142669a5db4SJeff Garzik static void triflex_bmdma_start(struct ata_queued_cmd *qc)
143669a5db4SJeff Garzik {
144669a5db4SJeff Garzik triflex_load_timing(qc->ap, qc->dev, qc->dev->dma_mode);
145669a5db4SJeff Garzik ata_bmdma_start(qc);
146669a5db4SJeff Garzik }
147669a5db4SJeff Garzik
148669a5db4SJeff Garzik /**
1492ee628f3SLee Jones * triflex_bmdma_stop - DMA stop callback
1502ee628f3SLee Jones * @qc: ATA command
151669a5db4SJeff Garzik *
152669a5db4SJeff Garzik * We loaded new timings in dma_start, as a result we need to restore
153669a5db4SJeff Garzik * the PIO timings in dma_stop so that the next command issue gets the
154669a5db4SJeff Garzik * right clock values.
155669a5db4SJeff Garzik */
156669a5db4SJeff Garzik
triflex_bmdma_stop(struct ata_queued_cmd * qc)157669a5db4SJeff Garzik static void triflex_bmdma_stop(struct ata_queued_cmd *qc)
158669a5db4SJeff Garzik {
159669a5db4SJeff Garzik ata_bmdma_stop(qc);
160669a5db4SJeff Garzik triflex_load_timing(qc->ap, qc->dev, qc->dev->pio_mode);
161669a5db4SJeff Garzik }
162669a5db4SJeff Garzik
163*25df73d9SBart Van Assche static const struct scsi_host_template triflex_sht = {
16468d1d07bSTejun Heo ATA_BMDMA_SHT(DRV_NAME),
165669a5db4SJeff Garzik };
166669a5db4SJeff Garzik
167669a5db4SJeff Garzik static struct ata_port_operations triflex_port_ops = {
168029cfd6bSTejun Heo .inherits = &ata_bmdma_port_ops,
169669a5db4SJeff Garzik .bmdma_start = triflex_bmdma_start,
170669a5db4SJeff Garzik .bmdma_stop = triflex_bmdma_stop,
171029cfd6bSTejun Heo .cable_detect = ata_cable_40wire,
172029cfd6bSTejun Heo .set_piomode = triflex_set_piomode,
173a1efdabaSTejun Heo .prereset = triflex_prereset,
174669a5db4SJeff Garzik };
175669a5db4SJeff Garzik
triflex_init_one(struct pci_dev * dev,const struct pci_device_id * id)176669a5db4SJeff Garzik static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
177669a5db4SJeff Garzik {
1781626aeb8STejun Heo static const struct ata_port_info info = {
1791d2808fdSJeff Garzik .flags = ATA_FLAG_SLAVE_POSS,
18014bdef98SErik Inge Bolsø .pio_mask = ATA_PIO4,
18114bdef98SErik Inge Bolsø .mwdma_mask = ATA_MWDMA2,
182669a5db4SJeff Garzik .port_ops = &triflex_port_ops
183669a5db4SJeff Garzik };
1841626aeb8STejun Heo const struct ata_port_info *ppi[] = { &info, NULL };
185669a5db4SJeff Garzik
18606296a1eSJoe Perches ata_print_version_once(&dev->dev, DRV_VERSION);
187669a5db4SJeff Garzik
1881c5afdf7STejun Heo return ata_pci_bmdma_init_one(dev, ppi, &triflex_sht, NULL, 0);
189669a5db4SJeff Garzik }
190669a5db4SJeff Garzik
191669a5db4SJeff Garzik static const struct pci_device_id triflex[] = {
1922d2744fcSJeff Garzik { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
1932d2744fcSJeff Garzik
1942d2744fcSJeff Garzik { },
195669a5db4SJeff Garzik };
196669a5db4SJeff Garzik
19758eb8cd5SBartlomiej Zolnierkiewicz #ifdef CONFIG_PM_SLEEP
triflex_ata_pci_device_suspend(struct pci_dev * pdev,pm_message_t mesg)198bfeec8caSMikulas Patocka static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
199bfeec8caSMikulas Patocka {
2000a86e1c8SJingoo Han struct ata_host *host = pci_get_drvdata(pdev);
201bfeec8caSMikulas Patocka
202ec87cf37SSergey Shtylyov ata_host_suspend(host, mesg);
203bfeec8caSMikulas Patocka
204bfeec8caSMikulas Patocka /*
205bfeec8caSMikulas Patocka * We must not disable or powerdown the device.
206bfeec8caSMikulas Patocka * APM bios refuses to suspend if IDE is not accessible.
207bfeec8caSMikulas Patocka */
208bfeec8caSMikulas Patocka pci_save_state(pdev);
209bfeec8caSMikulas Patocka
210bfeec8caSMikulas Patocka return 0;
211bfeec8caSMikulas Patocka }
212bfeec8caSMikulas Patocka
213bfeec8caSMikulas Patocka #endif
214bfeec8caSMikulas Patocka
215669a5db4SJeff Garzik static struct pci_driver triflex_pci_driver = {
216669a5db4SJeff Garzik .name = DRV_NAME,
217669a5db4SJeff Garzik .id_table = triflex,
218669a5db4SJeff Garzik .probe = triflex_init_one,
21930ced0f0SAlan .remove = ata_pci_remove_one,
22058eb8cd5SBartlomiej Zolnierkiewicz #ifdef CONFIG_PM_SLEEP
221bfeec8caSMikulas Patocka .suspend = triflex_ata_pci_device_suspend,
22230ced0f0SAlan .resume = ata_pci_device_resume,
223438ac6d5STejun Heo #endif
224669a5db4SJeff Garzik };
225669a5db4SJeff Garzik
2262fc75da0SAxel Lin module_pci_driver(triflex_pci_driver);
227669a5db4SJeff Garzik
228669a5db4SJeff Garzik MODULE_AUTHOR("Alan Cox");
229669a5db4SJeff Garzik MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
230669a5db4SJeff Garzik MODULE_LICENSE("GPL");
231669a5db4SJeff Garzik MODULE_DEVICE_TABLE(pci, triflex);
232669a5db4SJeff Garzik MODULE_VERSION(DRV_VERSION);
233