patch-2_6_7-vs1_9_1_12
[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 static struct pci_dev *triflex_dev;
45
46 #ifdef CONFIG_PROC_FS
47 static int triflex_get_info(char *buf, char **addr, off_t offset, int count)
48 {
49         char *p = buf;
50         int len;
51
52         struct pci_dev *dev     = triflex_dev;
53         unsigned long bibma = pci_resource_start(dev, 4);
54         u8  c0 = 0, c1 = 0;
55         u32 pri_timing, sec_timing;
56
57         p += sprintf(p, "\n                                Compaq Triflex Chipset\n");
58         
59         pci_read_config_dword(dev, 0x70, &pri_timing);
60         pci_read_config_dword(dev, 0x74, &sec_timing);
61
62         /*
63          * at that point bibma+0x2 et bibma+0xa are byte registers
64          * to investigate:
65          */
66         c0 = inb((unsigned short)bibma + 0x02);
67         c1 = inb((unsigned short)bibma + 0x0a);
68
69         p += sprintf(p, "--------------- Primary Channel "
70                         "---------------- Secondary Channel "
71                         "-------------\n");
72         p += sprintf(p, "                %sabled "
73                         "                        %sabled\n",
74                         (c0&0x80) ? "dis" : " en",
75                         (c1&0x80) ? "dis" : " en");
76         p += sprintf(p, "--------------- drive0 --------- drive1 "
77                         "-------- drive0 ---------- drive1 ------\n");
78         p += sprintf(p, "DMA enabled:    %s              %s "
79                         "            %s               %s\n",
80                         (c0&0x20) ? "yes" : "no ",
81                         (c0&0x40) ? "yes" : "no ",
82                         (c1&0x20) ? "yes" : "no ",
83                         (c1&0x40) ? "yes" : "no " );
84
85         p += sprintf(p, "DMA\n");
86         p += sprintf(p, "PIO\n");
87
88         len = (p - buf) - offset;
89         *addr = buf + offset;
90         
91         return len > count ? count : len;
92 }
93 #endif
94
95 static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
96 {
97         ide_hwif_t *hwif = HWIF(drive);
98         struct pci_dev *dev = hwif->pci_dev;
99         u8 channel_offset = hwif->channel ? 0x74 : 0x70;
100         u16 timing = 0;
101         u32 triflex_timings = 0;
102         u8 unit = (drive->select.b.unit & 0x01);
103         u8 speed = ide_rate_filter(0, xferspeed);
104         
105         pci_read_config_dword(dev, channel_offset, &triflex_timings);
106         
107         switch(speed) {
108                 case XFER_MW_DMA_2:
109                         timing = 0x0103; 
110                         break;
111                 case XFER_MW_DMA_1:
112                         timing = 0x0203;
113                         break;
114                 case XFER_MW_DMA_0:
115                         timing = 0x0808;
116                         break;
117                 case XFER_SW_DMA_2:
118                 case XFER_SW_DMA_1:
119                 case XFER_SW_DMA_0:
120                         timing = 0x0f0f;
121                         break;
122                 case XFER_PIO_4:
123                         timing = 0x0202;
124                         break;
125                 case XFER_PIO_3:
126                         timing = 0x0204;
127                         break;
128                 case XFER_PIO_2:
129                         timing = 0x0404;
130                         break;
131                 case XFER_PIO_1:
132                         timing = 0x0508;
133                         break;
134                 case XFER_PIO_0:
135                         timing = 0x0808;
136                         break;
137                 default:
138                         return -1;
139         }
140
141         triflex_timings &= ~(0xFFFF << (16 * unit));
142         triflex_timings |= (timing << (16 * unit));
143         
144         pci_write_config_dword(dev, channel_offset, triflex_timings);
145         
146         return (ide_config_drive_speed(drive, speed));
147 }
148
149 static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
150 {
151         int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
152         (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
153 }
154
155 static int triflex_config_drive_for_dma(ide_drive_t *drive)
156 {
157         int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
158
159         if (!speed) { 
160                 u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
161                 speed = XFER_PIO_0 + pspeed;
162         }
163         
164         (void) triflex_tune_chipset(drive, speed);
165          return ide_dma_enable(drive);
166 }
167
168 static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
169 {
170         ide_hwif_t *hwif        = HWIF(drive);
171         struct hd_driveid *id   = drive->id;
172         
173         if (id && (id->capability & 1) && drive->autodma) {
174                 if (__ide_dma_bad_drive(drive))
175                         goto tune_pio;
176                 if (id->field_valid & 2) {
177                         if ((id->dma_mword & hwif->mwdma_mask) ||
178                                 (id->dma_1word & hwif->swdma_mask)) {
179                                 if (!triflex_config_drive_for_dma(drive))
180                                         goto tune_pio;
181                         }
182                 } else 
183                         goto tune_pio;
184         } else {
185 tune_pio:
186                 hwif->tuneproc(drive, 255);
187                 return hwif->ide_dma_off_quietly(drive);
188         }
189
190         return hwif->ide_dma_on(drive);
191 }
192
193 static void __init init_hwif_triflex(ide_hwif_t *hwif)
194 {
195         hwif->tuneproc = &triflex_tune_drive;
196         hwif->speedproc = &triflex_tune_chipset;
197
198         hwif->atapi_dma  = 1;
199         hwif->mwdma_mask = 0x07;
200         hwif->swdma_mask = 0x07;
201         hwif->ide_dma_check = &triflex_config_drive_xfer_rate;
202         
203         if (!noautodma)
204                 hwif->autodma = 1;
205         hwif->drives[0].autodma = hwif->autodma;
206         hwif->drives[1].autodma = hwif->autodma;
207 }
208
209 static unsigned int __init init_chipset_triflex(struct pci_dev *dev, 
210                 const char *name) 
211 {
212 #ifdef CONFIG_PROC_FS
213         ide_pci_create_host_proc("triflex", triflex_get_info);
214 #endif
215         return 0;       
216 }
217
218 static ide_pci_device_t triflex_device __devinitdata = {
219         .name           = "TRIFLEX",
220         .init_chipset   = init_chipset_triflex,
221         .init_hwif      = init_hwif_triflex,
222         .channels       = 2,
223         .autodma        = AUTODMA,
224         .enablebits     = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
225         .bootable       = ON_BOARD,
226 };
227
228 static int __devinit triflex_init_one(struct pci_dev *dev, 
229                 const struct pci_device_id *id)
230 {
231         ide_setup_pci_device(dev, &triflex_device);
232         triflex_dev = dev;
233
234         return 0;
235 }
236
237 static struct pci_device_id triflex_pci_tbl[] = {
238         { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
239           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
240         { 0, },
241 };
242 MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
243
244 static struct pci_driver driver = {
245         .name           = "TRIFLEX IDE",
246         .id_table       = triflex_pci_tbl,
247         .probe          = triflex_init_one,
248 };
249
250 static int triflex_ide_init(void)
251 {
252         return ide_pci_register_driver(&driver);
253 }
254
255 module_init(triflex_ide_init);
256
257 MODULE_AUTHOR("Torben Mathiasen");
258 MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
259 MODULE_LICENSE("GPL");
260
261