ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / ide / pci / triflex.c
1 /*
2  * triflex.c
3  * 
4  * IDE Chipset driver for the Compaq TriFlex IDE controller.
5  * 
6  * Known to work with the Compaq Workstation 5x00 series.
7  *
8  * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
9  * Author: Torben Mathiasen <torben.mathiasen@hp.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  * 
24  * Loosely based on the piix & svwks drivers.
25  *
26  * Documentation:
27  *      Not publically available.
28  */
29
30 #include <linux/config.h>
31 #include <linux/types.h>
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/delay.h>
35 #include <linux/timer.h>
36 #include <linux/mm.h>
37 #include <linux/ioport.h>
38 #include <linux/blkdev.h>
39 #include <linux/hdreg.h>
40 #include <linux/pci.h>
41 #include <linux/ide.h>
42 #include <linux/init.h>
43
44 #include "triflex.h"
45
46 static struct pci_dev *triflex_dev;
47
48 #ifdef CONFIG_PROC_FS
49 static int triflex_get_info(char *buf, char **addr, off_t offset, int count)
50 {
51         char *p = buf;
52         int len;
53
54         struct pci_dev *dev     = triflex_dev;
55         unsigned long bibma = pci_resource_start(dev, 4);
56         u8  c0 = 0, c1 = 0;
57         u32 pri_timing, sec_timing;
58
59         p += sprintf(p, "\n                                Compaq Triflex Chipset\n");
60         
61         pci_read_config_dword(dev, 0x70, &pri_timing);
62         pci_read_config_dword(dev, 0x74, &sec_timing);
63
64         /*
65          * at that point bibma+0x2 et bibma+0xa are byte registers
66          * to investigate:
67          */
68         c0 = inb((unsigned short)bibma + 0x02);
69         c1 = inb((unsigned short)bibma + 0x0a);
70
71         p += sprintf(p, "--------------- Primary Channel "
72                         "---------------- Secondary Channel "
73                         "-------------\n");
74         p += sprintf(p, "                %sabled "
75                         "                        %sabled\n",
76                         (c0&0x80) ? "dis" : " en",
77                         (c1&0x80) ? "dis" : " en");
78         p += sprintf(p, "--------------- drive0 --------- drive1 "
79                         "-------- drive0 ---------- drive1 ------\n");
80         p += sprintf(p, "DMA enabled:    %s              %s "
81                         "            %s               %s\n",
82                         (c0&0x20) ? "yes" : "no ",
83                         (c0&0x40) ? "yes" : "no ",
84                         (c1&0x20) ? "yes" : "no ",
85                         (c1&0x40) ? "yes" : "no " );
86
87         p += sprintf(p, "DMA\n");
88         p += sprintf(p, "PIO\n");
89
90         len = (p - buf) - offset;
91         *addr = buf + offset;
92         
93         return len > count ? count : len;
94 }
95 #endif
96
97 static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
98 {
99         ide_hwif_t *hwif = HWIF(drive);
100         struct pci_dev *dev = hwif->pci_dev;
101         u8 channel_offset = hwif->channel ? 0x74 : 0x70;
102         u16 timing = 0;
103         u32 triflex_timings = 0;
104         u8 unit = (drive->select.b.unit & 0x01);
105         u8 speed = ide_rate_filter(0, xferspeed);
106         
107         pci_read_config_dword(dev, channel_offset, &triflex_timings);
108         
109         switch(speed) {
110                 case XFER_MW_DMA_2:
111                         timing = 0x0103; 
112                         break;
113                 case XFER_MW_DMA_1:
114                         timing = 0x0203;
115                         break;
116                 case XFER_MW_DMA_0:
117                         timing = 0x0808;
118                         break;
119                 case XFER_SW_DMA_2:
120                 case XFER_SW_DMA_1:
121                 case XFER_SW_DMA_0:
122                         timing = 0x0f0f;
123                         break;
124                 case XFER_PIO_4:
125                         timing = 0x0202;
126                         break;
127                 case XFER_PIO_3:
128                         timing = 0x0204;
129                         break;
130                 case XFER_PIO_2:
131                         timing = 0x0404;
132                         break;
133                 case XFER_PIO_1:
134                         timing = 0x0508;
135                         break;
136                 case XFER_PIO_0:
137                         timing = 0x0808;
138                         break;
139                 default:
140                         return -1;
141         }
142
143         triflex_timings &= ~(0xFFFF << (16 * unit));
144         triflex_timings |= (timing << (16 * unit));
145         
146         pci_write_config_dword(dev, channel_offset, triflex_timings);
147         
148         return (ide_config_drive_speed(drive, speed));
149 }
150
151 static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
152 {
153         int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
154         (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
155 }
156
157 static int triflex_config_drive_for_dma(ide_drive_t *drive)
158 {
159         int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
160
161         if (!speed) { 
162                 u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
163                 speed = XFER_PIO_0 + pspeed;
164         }
165         
166         (void) triflex_tune_chipset(drive, speed);
167          return ide_dma_enable(drive);
168 }
169
170 static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
171 {
172         ide_hwif_t *hwif        = HWIF(drive);
173         struct hd_driveid *id   = drive->id;
174         
175         if (id && (id->capability & 1) && drive->autodma) {
176                 if (__ide_dma_bad_drive(drive))
177                         goto tune_pio;
178                 if (id->field_valid & 2) {
179                         if ((id->dma_mword & hwif->mwdma_mask) ||
180                                 (id->dma_1word & hwif->swdma_mask)) {
181                                 if (!triflex_config_drive_for_dma(drive))
182                                         goto tune_pio;
183                         }
184                 } else 
185                         goto tune_pio;
186         } else {
187 tune_pio:
188                 hwif->tuneproc(drive, 255);
189                 return hwif->ide_dma_off_quietly(drive);
190         }
191
192         return hwif->ide_dma_on(drive);
193 }
194
195 static void __init init_hwif_triflex(ide_hwif_t *hwif)
196 {
197         hwif->tuneproc = &triflex_tune_drive;
198         hwif->speedproc = &triflex_tune_chipset;
199
200         hwif->atapi_dma  = 1;
201         hwif->mwdma_mask = 0x07;
202         hwif->swdma_mask = 0x07;
203         hwif->ide_dma_check = &triflex_config_drive_xfer_rate;
204         
205         if (!noautodma)
206                 hwif->autodma = 1;
207         hwif->drives[0].autodma = hwif->autodma;
208         hwif->drives[1].autodma = hwif->autodma;
209 }
210
211 static unsigned int __init init_chipset_triflex(struct pci_dev *dev, 
212                 const char *name) 
213 {
214 #ifdef CONFIG_PROC_FS
215         ide_pci_create_host_proc("triflex", triflex_get_info);
216 #endif
217         return 0;       
218 }
219
220 static int __devinit triflex_init_one(struct pci_dev *dev, 
221                 const struct pci_device_id *id)
222 {
223         ide_pci_device_t *d = &triflex_devices[id->driver_data];
224         if (dev->device != d->device)
225                 BUG();
226         
227         ide_setup_pci_device(dev, d);
228         triflex_dev = dev;
229         
230         return 0;
231 }
232
233 static struct pci_driver driver = {
234         .name           = "TRIFLEX IDE",
235         .id_table       = triflex_pci_tbl,
236         .probe          = triflex_init_one,
237 };
238
239 static int triflex_ide_init(void)
240 {
241         return ide_pci_register_driver(&driver);
242 }
243
244 module_init(triflex_ide_init);
245
246 MODULE_AUTHOR("Torben Mathiasen");
247 MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
248 MODULE_LICENSE("GPL");
249
250