aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/pci/cs5530.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide/pci/cs5530.c')
-rw-r--r--drivers/ide/pci/cs5530.c160
1 files changed, 79 insertions, 81 deletions
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index b2d7c132ef4b..1eec1f308d16 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -1,10 +1,10 @@
1/* 1/*
2 * linux/drivers/ide/pci/cs5530.c Version 0.7 Sept 10, 2002 2 * linux/drivers/ide/pci/cs5530.c Version 0.73 Mar 10 2007
3 * 3 *
4 * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> 4 * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
5 * Ditto of GNU General Public License.
6 *
7 * Copyright (C) 2000 Mark Lord <mlord@pobox.com> 5 * Copyright (C) 2000 Mark Lord <mlord@pobox.com>
6 * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
7 *
8 * May be copied or modified under the terms of the GNU General Public License 8 * May be copied or modified under the terms of the GNU General Public License
9 * 9 *
10 * Development of this chipset driver was funded 10 * Development of this chipset driver was funded
@@ -62,6 +62,14 @@ static unsigned int cs5530_pio_timings[2][5] = {
62#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132) 62#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
63#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20)) 63#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
64 64
65static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
66{
67 unsigned long basereg = CS5530_BASEREG(drive->hwif);
68 unsigned int format = (inl(basereg + 4) >> 31) & 1;
69
70 outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
71}
72
65/** 73/**
66 * cs5530_tuneproc - select/set PIO modes 74 * cs5530_tuneproc - select/set PIO modes
67 * 75 *
@@ -74,98 +82,78 @@ static unsigned int cs5530_pio_timings[2][5] = {
74 82
75static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */ 83static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */
76{ 84{
77 ide_hwif_t *hwif = HWIF(drive);
78 unsigned int format;
79 unsigned long basereg = CS5530_BASEREG(hwif);
80 static u8 modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
81
82 pio = ide_get_best_pio_mode(drive, pio, 4, NULL); 85 pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
83 if (!cs5530_set_xfer_mode(drive, modes[pio])) { 86
84 format = (inl(basereg + 4) >> 31) & 1; 87 if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
85 outl(cs5530_pio_timings[format][pio], 88 cs5530_tunepio(drive, pio);
86 basereg+(drive->select.b.unit<<3)); 89}
90
91/**
92 * cs5530_udma_filter - UDMA filter
93 * @drive: drive
94 *
95 * cs5530_udma_filter() does UDMA mask filtering for the given drive
96 * taking into the consideration capabilities of the mate device.
97 *
98 * The CS5530 specifies that two drives sharing a cable cannot mix
99 * UDMA/MDMA. It has to be one or the other, for the pair, though
100 * different timings can still be chosen for each drive. We could
101 * set the appropriate timing bits on the fly, but that might be
102 * a bit confusing. So, for now we statically handle this requirement
103 * by looking at our mate drive to see what it is capable of, before
104 * choosing a mode for our own drive.
105 *
106 * Note: This relies on the fact we never fail from UDMA to MWDMA2
107 * but instead drop to PIO.
108 */
109
110static u8 cs5530_udma_filter(ide_drive_t *drive)
111{
112 ide_hwif_t *hwif = drive->hwif;
113 ide_drive_t *mate = &hwif->drives[(drive->dn & 1) ^ 1];
114 struct hd_driveid *mateid = mate->id;
115 u8 mask = hwif->ultra_mask;
116
117 if (mate->present == 0)
118 goto out;
119
120 if ((mateid->capability & 1) && __ide_dma_bad_drive(mate) == 0) {
121 if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
122 goto out;
123 if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
124 mask = 0;
87 } 125 }
126out:
127 return mask;
88} 128}
89 129
90/** 130/**
91 * cs5530_config_dma - select/set DMA and UDMA modes 131 * cs5530_config_dma - set DMA/UDMA mode
92 * @drive: drive to tune 132 * @drive: drive to tune
93 * 133 *
94 * cs5530_config_dma() handles selection/setting of DMA/UDMA modes 134 * cs5530_config_dma() handles setting of DMA/UDMA mode
95 * for both the chipset and drive. The CS5530 has limitations about 135 * for both the chipset and drive.
96 * mixing DMA/UDMA on the same cable.
97 */ 136 */
98 137
99static int cs5530_config_dma (ide_drive_t *drive) 138static int cs5530_config_dma(ide_drive_t *drive)
100{ 139{
101 int udma_ok = 1, mode = 0; 140 if (ide_tune_dma(drive))
102 ide_hwif_t *hwif = HWIF(drive); 141 return 0;
103 int unit = drive->select.b.unit;
104 ide_drive_t *mate = &hwif->drives[unit^1];
105 struct hd_driveid *id = drive->id;
106 unsigned int reg, timings = 0;
107 unsigned long basereg;
108 142
109 /* 143 return 1;
110 * Default to DMA-off in case we run into trouble here. 144}
111 */
112 hwif->dma_off_quietly(drive);
113 145
114 /* 146static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
115 * The CS5530 specifies that two drives sharing a cable cannot 147{
116 * mix UDMA/MDMA. It has to be one or the other, for the pair, 148 unsigned long basereg;
117 * though different timings can still be chosen for each drive. 149 unsigned int reg, timings = 0;
118 * We could set the appropriate timing bits on the fly,
119 * but that might be a bit confusing. So, for now we statically
120 * handle this requirement by looking at our mate drive to see
121 * what it is capable of, before choosing a mode for our own drive.
122 *
123 * Note: This relies on the fact we never fail from UDMA to MWDMA_2
124 * but instead drop to PIO
125 */
126 if (mate->present) {
127 struct hd_driveid *mateid = mate->id;
128 if (mateid && (mateid->capability & 1) &&
129 !__ide_dma_bad_drive(mate)) {
130 if ((mateid->field_valid & 4) &&
131 (mateid->dma_ultra & 7))
132 udma_ok = 1;
133 else if ((mateid->field_valid & 2) &&
134 (mateid->dma_mword & 7))
135 udma_ok = 0;
136 else
137 udma_ok = 1;
138 }
139 }
140 150
141 /* 151 mode = ide_rate_filter(drive, mode);
142 * Now see what the current drive is capable of,
143 * selecting UDMA only if the mate said it was ok.
144 */
145 if (id && (id->capability & 1) && drive->autodma &&
146 !__ide_dma_bad_drive(drive)) {
147 if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
148 if (id->dma_ultra & 4)
149 mode = XFER_UDMA_2;
150 else if (id->dma_ultra & 2)
151 mode = XFER_UDMA_1;
152 else if (id->dma_ultra & 1)
153 mode = XFER_UDMA_0;
154 }
155 if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
156 if (id->dma_mword & 4)
157 mode = XFER_MW_DMA_2;
158 else if (id->dma_mword & 2)
159 mode = XFER_MW_DMA_1;
160 else if (id->dma_mword & 1)
161 mode = XFER_MW_DMA_0;
162 }
163 }
164 152
165 /* 153 /*
166 * Tell the drive to switch to the new mode; abort on failure. 154 * Tell the drive to switch to the new mode; abort on failure.
167 */ 155 */
168 if (!mode || cs5530_set_xfer_mode(drive, mode)) 156 if (cs5530_set_xfer_mode(drive, mode))
169 return 1; /* failure */ 157 return 1; /* failure */
170 158
171 /* 159 /*
@@ -178,14 +166,21 @@ static int cs5530_config_dma (ide_drive_t *drive)
178 case XFER_MW_DMA_0: timings = 0x00077771; break; 166 case XFER_MW_DMA_0: timings = 0x00077771; break;
179 case XFER_MW_DMA_1: timings = 0x00012121; break; 167 case XFER_MW_DMA_1: timings = 0x00012121; break;
180 case XFER_MW_DMA_2: timings = 0x00002020; break; 168 case XFER_MW_DMA_2: timings = 0x00002020; break;
169 case XFER_PIO_4:
170 case XFER_PIO_3:
171 case XFER_PIO_2:
172 case XFER_PIO_1:
173 case XFER_PIO_0:
174 cs5530_tunepio(drive, mode - XFER_PIO_0);
175 return 0;
181 default: 176 default:
182 BUG(); 177 BUG();
183 break; 178 break;
184 } 179 }
185 basereg = CS5530_BASEREG(hwif); 180 basereg = CS5530_BASEREG(drive->hwif);
186 reg = inl(basereg + 4); /* get drive0 config register */ 181 reg = inl(basereg + 4); /* get drive0 config register */
187 timings |= reg & 0x80000000; /* preserve PIO format bit */ 182 timings |= reg & 0x80000000; /* preserve PIO format bit */
188 if (unit == 0) { /* are we configuring drive0? */ 183 if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */
189 outl(timings, basereg + 4); /* write drive0 config register */ 184 outl(timings, basereg + 4); /* write drive0 config register */
190 } else { 185 } else {
191 if (timings & 0x00100000) 186 if (timings & 0x00100000)
@@ -311,6 +306,8 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
311 hwif->serialized = hwif->mate->serialized = 1; 306 hwif->serialized = hwif->mate->serialized = 1;
312 307
313 hwif->tuneproc = &cs5530_tuneproc; 308 hwif->tuneproc = &cs5530_tuneproc;
309 hwif->speedproc = &cs5530_tune_chipset;
310
314 basereg = CS5530_BASEREG(hwif); 311 basereg = CS5530_BASEREG(hwif);
315 d0_timings = inl(basereg + 0); 312 d0_timings = inl(basereg + 0);
316 if (CS5530_BAD_PIO(d0_timings)) { 313 if (CS5530_BAD_PIO(d0_timings)) {
@@ -332,6 +329,7 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
332 hwif->ultra_mask = 0x07; 329 hwif->ultra_mask = 0x07;
333 hwif->mwdma_mask = 0x07; 330 hwif->mwdma_mask = 0x07;
334 331
332 hwif->udma_filter = cs5530_udma_filter;
335 hwif->ide_dma_check = &cs5530_config_dma; 333 hwif->ide_dma_check = &cs5530_config_dma;
336 if (!noautodma) 334 if (!noautodma)
337 hwif->autodma = 1; 335 hwif->autodma = 1;