diff options
Diffstat (limited to 'drivers/ide/pci/cs5530.c')
-rw-r--r-- | drivers/ide/pci/cs5530.c | 160 |
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 | ||
65 | static 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 | ||
75 | static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */ | 83 | static 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 | |||
110 | static 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 | } |
126 | out: | ||
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 | ||
99 | static int cs5530_config_dma (ide_drive_t *drive) | 138 | static 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 | /* | 146 | static 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; |