]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
1da177e4 | 2 | * Copyright (C) 1999-2002 Andre Hedrick <[email protected]> |
826a1b65 | 3 | * Copyright (C) 2007 MontaVista Software, Inc. <[email protected]> |
1da177e4 LT |
4 | * |
5 | */ | |
6 | ||
7 | #include <linux/module.h> | |
1da177e4 LT |
8 | #include <linux/types.h> |
9 | #include <linux/pci.h> | |
1da177e4 LT |
10 | #include <linux/ide.h> |
11 | #include <linux/init.h> | |
12 | ||
13 | #include <asm/io.h> | |
14 | ||
ced3ec8a BZ |
15 | #define DRV_NAME "aec62xx" |
16 | ||
1da177e4 LT |
17 | struct chipset_bus_clock_list_entry { |
18 | u8 xfer_speed; | |
19 | u8 chipset_settings; | |
20 | u8 ultra_settings; | |
21 | }; | |
22 | ||
f201f504 | 23 | static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = { |
1da177e4 LT |
24 | { XFER_UDMA_6, 0x31, 0x07 }, |
25 | { XFER_UDMA_5, 0x31, 0x06 }, | |
26 | { XFER_UDMA_4, 0x31, 0x05 }, | |
27 | { XFER_UDMA_3, 0x31, 0x04 }, | |
28 | { XFER_UDMA_2, 0x31, 0x03 }, | |
29 | { XFER_UDMA_1, 0x31, 0x02 }, | |
30 | { XFER_UDMA_0, 0x31, 0x01 }, | |
31 | ||
32 | { XFER_MW_DMA_2, 0x31, 0x00 }, | |
33 | { XFER_MW_DMA_1, 0x31, 0x00 }, | |
34 | { XFER_MW_DMA_0, 0x0a, 0x00 }, | |
35 | { XFER_PIO_4, 0x31, 0x00 }, | |
36 | { XFER_PIO_3, 0x33, 0x00 }, | |
37 | { XFER_PIO_2, 0x08, 0x00 }, | |
38 | { XFER_PIO_1, 0x0a, 0x00 }, | |
39 | { XFER_PIO_0, 0x00, 0x00 }, | |
40 | { 0, 0x00, 0x00 } | |
41 | }; | |
42 | ||
f201f504 | 43 | static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = { |
1da177e4 LT |
44 | { XFER_UDMA_6, 0x41, 0x06 }, |
45 | { XFER_UDMA_5, 0x41, 0x05 }, | |
46 | { XFER_UDMA_4, 0x41, 0x04 }, | |
47 | { XFER_UDMA_3, 0x41, 0x03 }, | |
48 | { XFER_UDMA_2, 0x41, 0x02 }, | |
49 | { XFER_UDMA_1, 0x41, 0x01 }, | |
50 | { XFER_UDMA_0, 0x41, 0x01 }, | |
51 | ||
52 | { XFER_MW_DMA_2, 0x41, 0x00 }, | |
53 | { XFER_MW_DMA_1, 0x42, 0x00 }, | |
54 | { XFER_MW_DMA_0, 0x7a, 0x00 }, | |
55 | { XFER_PIO_4, 0x41, 0x00 }, | |
56 | { XFER_PIO_3, 0x43, 0x00 }, | |
57 | { XFER_PIO_2, 0x78, 0x00 }, | |
58 | { XFER_PIO_1, 0x7a, 0x00 }, | |
59 | { XFER_PIO_0, 0x70, 0x00 }, | |
60 | { 0, 0x00, 0x00 } | |
61 | }; | |
62 | ||
1da177e4 LT |
63 | /* |
64 | * TO DO: active tuning and correction of cards without a bios. | |
65 | */ | |
66 | static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) | |
67 | { | |
68 | for ( ; chipset_table->xfer_speed ; chipset_table++) | |
69 | if (chipset_table->xfer_speed == speed) { | |
70 | return chipset_table->chipset_settings; | |
71 | } | |
72 | return chipset_table->chipset_settings; | |
73 | } | |
74 | ||
75 | static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) | |
76 | { | |
77 | for ( ; chipset_table->xfer_speed ; chipset_table++) | |
78 | if (chipset_table->xfer_speed == speed) { | |
79 | return chipset_table->ultra_settings; | |
80 | } | |
81 | return chipset_table->ultra_settings; | |
82 | } | |
83 | ||
8776168c | 84 | static void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
1da177e4 | 85 | { |
36501650 | 86 | struct pci_dev *dev = to_pci_dev(hwif->dev); |
60e57ed7 BZ |
87 | struct ide_host *host = pci_get_drvdata(dev); |
88 | struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; | |
1da177e4 | 89 | u16 d_conf = 0; |
1da177e4 LT |
90 | u8 ultra = 0, ultra_conf = 0; |
91 | u8 tmp0 = 0, tmp1 = 0, tmp2 = 0; | |
8776168c | 92 | const u8 speed = drive->dma_mode; |
1da177e4 LT |
93 | unsigned long flags; |
94 | ||
95 | local_irq_save(flags); | |
96 | /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */ | |
97 | pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); | |
60e57ed7 | 98 | tmp0 = pci_bus_clock_list(speed, bus_clock); |
1da177e4 LT |
99 | d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf); |
100 | pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf); | |
101 | ||
102 | tmp1 = 0x00; | |
103 | tmp2 = 0x00; | |
104 | pci_read_config_byte(dev, 0x54, &ultra); | |
105 | tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn)))); | |
60e57ed7 | 106 | ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock); |
1da177e4 LT |
107 | tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn)))); |
108 | pci_write_config_byte(dev, 0x54, tmp2); | |
109 | local_irq_restore(flags); | |
1da177e4 LT |
110 | } |
111 | ||
8776168c | 112 | static void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
1da177e4 | 113 | { |
36501650 | 114 | struct pci_dev *dev = to_pci_dev(hwif->dev); |
60e57ed7 BZ |
115 | struct ide_host *host = pci_get_drvdata(dev); |
116 | struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; | |
123995b9 | 117 | u8 unit = drive->dn & 1; |
1da177e4 LT |
118 | u8 tmp1 = 0, tmp2 = 0; |
119 | u8 ultra = 0, drive_conf = 0, ultra_conf = 0; | |
8776168c | 120 | const u8 speed = drive->dma_mode; |
1da177e4 LT |
121 | unsigned long flags; |
122 | ||
123 | local_irq_save(flags); | |
124 | /* high 4-bits: Active, low 4-bits: Recovery */ | |
125 | pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); | |
60e57ed7 | 126 | drive_conf = pci_bus_clock_list(speed, bus_clock); |
1da177e4 LT |
127 | pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); |
128 | ||
129 | pci_read_config_byte(dev, (0x44|hwif->channel), &ultra); | |
130 | tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit)))); | |
60e57ed7 | 131 | ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock); |
1da177e4 LT |
132 | tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit)))); |
133 | pci_write_config_byte(dev, (0x44|hwif->channel), tmp2); | |
134 | local_irq_restore(flags); | |
1da177e4 LT |
135 | } |
136 | ||
e085b3ca | 137 | static void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
1da177e4 | 138 | { |
e085b3ca | 139 | drive->dma_mode = drive->pio_mode; |
8776168c | 140 | hwif->port_ops->set_dma_mode(hwif, drive); |
1da177e4 LT |
141 | } |
142 | ||
2ed0ef54 | 143 | static int init_chipset_aec62xx(struct pci_dev *dev) |
1da177e4 | 144 | { |
d237bf49 TV |
145 | /* These are necessary to get AEC6280 Macintosh cards to work */ |
146 | if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) || | |
147 | (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) { | |
148 | u8 reg49h = 0, reg4ah = 0; | |
149 | /* Clear reset and test bits. */ | |
150 | pci_read_config_byte(dev, 0x49, ®49h); | |
151 | pci_write_config_byte(dev, 0x49, reg49h & ~0x30); | |
152 | /* Enable chip interrupt output. */ | |
153 | pci_read_config_byte(dev, 0x4a, ®4ah); | |
154 | pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01); | |
155 | /* Enable burst mode. */ | |
156 | pci_read_config_byte(dev, 0x4a, ®4ah); | |
157 | pci_write_config_byte(dev, 0x4a, reg4ah | 0x80); | |
158 | } | |
159 | ||
2ed0ef54 | 160 | return 0; |
1da177e4 LT |
161 | } |
162 | ||
f454cbe8 | 163 | static u8 atp86x_cable_detect(ide_hwif_t *hwif) |
bfa14b42 BZ |
164 | { |
165 | struct pci_dev *dev = to_pci_dev(hwif->dev); | |
166 | u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01; | |
167 | ||
168 | pci_read_config_byte(dev, 0x49, &ata66); | |
169 | ||
170 | return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; | |
171 | } | |
172 | ||
ac95beed BZ |
173 | static const struct ide_port_ops atp850_port_ops = { |
174 | .set_pio_mode = aec_set_pio_mode, | |
175 | .set_dma_mode = aec6210_set_mode, | |
176 | }; | |
1da177e4 | 177 | |
ac95beed BZ |
178 | static const struct ide_port_ops atp86x_port_ops = { |
179 | .set_pio_mode = aec_set_pio_mode, | |
180 | .set_dma_mode = aec6260_set_mode, | |
181 | .cable_detect = atp86x_cable_detect, | |
182 | }; | |
1da177e4 | 183 | |
fe31edc8 | 184 | static const struct ide_port_info aec62xx_chipsets[] = { |
ced3ec8a BZ |
185 | { /* 0: AEC6210 */ |
186 | .name = DRV_NAME, | |
1da177e4 | 187 | .init_chipset = init_chipset_aec62xx, |
1da177e4 | 188 | .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, |
ac95beed | 189 | .port_ops = &atp850_port_ops, |
1c51361a BZ |
190 | .host_flags = IDE_HFLAG_SERIALIZE | |
191 | IDE_HFLAG_NO_ATAPI_DMA | | |
4166c199 | 192 | IDE_HFLAG_NO_DSC | |
1c51361a | 193 | IDE_HFLAG_OFF_BOARD, |
4099d143 | 194 | .pio_mask = ATA_PIO4, |
5f8b6c34 BZ |
195 | .mwdma_mask = ATA_MWDMA2, |
196 | .udma_mask = ATA_UDMA2, | |
ced3ec8a BZ |
197 | }, |
198 | { /* 1: AEC6260 */ | |
199 | .name = DRV_NAME, | |
1da177e4 | 200 | .init_chipset = init_chipset_aec62xx, |
ac95beed | 201 | .port_ops = &atp86x_port_ops, |
47b68788 BZ |
202 | .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA | |
203 | IDE_HFLAG_OFF_BOARD, | |
4099d143 | 204 | .pio_mask = ATA_PIO4, |
5f8b6c34 BZ |
205 | .mwdma_mask = ATA_MWDMA2, |
206 | .udma_mask = ATA_UDMA4, | |
ced3ec8a BZ |
207 | }, |
208 | { /* 2: AEC6260R */ | |
209 | .name = DRV_NAME, | |
1da177e4 | 210 | .init_chipset = init_chipset_aec62xx, |
1da177e4 | 211 | .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, |
ac95beed | 212 | .port_ops = &atp86x_port_ops, |
4db90a14 | 213 | .host_flags = IDE_HFLAG_NO_ATAPI_DMA | |
5e71d9c5 | 214 | IDE_HFLAG_NON_BOOTABLE, |
4099d143 | 215 | .pio_mask = ATA_PIO4, |
5f8b6c34 BZ |
216 | .mwdma_mask = ATA_MWDMA2, |
217 | .udma_mask = ATA_UDMA4, | |
ced3ec8a BZ |
218 | }, |
219 | { /* 3: AEC6280 */ | |
220 | .name = DRV_NAME, | |
1da177e4 | 221 | .init_chipset = init_chipset_aec62xx, |
ac95beed | 222 | .port_ops = &atp86x_port_ops, |
4db90a14 | 223 | .host_flags = IDE_HFLAG_NO_ATAPI_DMA | |
4db90a14 | 224 | IDE_HFLAG_OFF_BOARD, |
4099d143 | 225 | .pio_mask = ATA_PIO4, |
5f8b6c34 BZ |
226 | .mwdma_mask = ATA_MWDMA2, |
227 | .udma_mask = ATA_UDMA5, | |
ced3ec8a BZ |
228 | }, |
229 | { /* 4: AEC6280R */ | |
230 | .name = DRV_NAME, | |
1da177e4 | 231 | .init_chipset = init_chipset_aec62xx, |
1da177e4 | 232 | .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, |
ac95beed | 233 | .port_ops = &atp86x_port_ops, |
4db90a14 | 234 | .host_flags = IDE_HFLAG_NO_ATAPI_DMA | |
4db90a14 | 235 | IDE_HFLAG_OFF_BOARD, |
4099d143 | 236 | .pio_mask = ATA_PIO4, |
5f8b6c34 BZ |
237 | .mwdma_mask = ATA_MWDMA2, |
238 | .udma_mask = ATA_UDMA5, | |
1da177e4 LT |
239 | } |
240 | }; | |
241 | ||
242 | /** | |
243 | * aec62xx_init_one - called when a AEC is found | |
244 | * @dev: the aec62xx device | |
245 | * @id: the matching pci id | |
246 | * | |
247 | * Called when the PCI registration layer (or the IDE initialization) | |
248 | * finds a device matching our IDE device tables. | |
b1d19db4 SS |
249 | * |
250 | * NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R] | |
039788e1 | 251 | * chips, pass a local copy of 'struct ide_port_info' down the call chain. |
1da177e4 | 252 | */ |
039788e1 | 253 | |
fe31edc8 | 254 | static int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) |
1da177e4 | 255 | { |
60e57ed7 | 256 | const struct chipset_bus_clock_list_entry *bus_clock; |
039788e1 | 257 | struct ide_port_info d; |
df95f5ab | 258 | u8 idx = id->driver_data; |
60e57ed7 | 259 | int bus_speed = ide_pci_clk ? ide_pci_clk : 33; |
b48d0817 AR |
260 | int err; |
261 | ||
60e57ed7 BZ |
262 | if (bus_speed <= 33) |
263 | bus_clock = aec6xxx_33_base; | |
264 | else | |
265 | bus_clock = aec6xxx_34_base; | |
266 | ||
b48d0817 AR |
267 | err = pci_enable_device(dev); |
268 | if (err) | |
269 | return err; | |
df95f5ab BZ |
270 | |
271 | d = aec62xx_chipsets[idx]; | |
272 | ||
273 | if (idx == 3 || idx == 4) { | |
274 | unsigned long dma_base = pci_resource_start(dev, 4); | |
275 | ||
276 | if (inb(dma_base + 2) & 0x10) { | |
ced3ec8a BZ |
277 | printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected" |
278 | "\n", pci_name(dev), (idx == 4) ? "R" : ""); | |
df95f5ab BZ |
279 | d.udma_mask = ATA_UDMA6; |
280 | } | |
281 | } | |
1da177e4 | 282 | |
60e57ed7 | 283 | err = ide_pci_init_one(dev, &d, (void *)bus_clock); |
b48d0817 AR |
284 | if (err) |
285 | pci_disable_device(dev); | |
286 | ||
287 | return err; | |
1da177e4 LT |
288 | } |
289 | ||
fe31edc8 | 290 | static void aec62xx_remove(struct pci_dev *dev) |
eb7cb98b BZ |
291 | { |
292 | ide_pci_remove(dev); | |
293 | pci_disable_device(dev); | |
294 | } | |
295 | ||
9cbcc5e3 BZ |
296 | static const struct pci_device_id aec62xx_pci_tbl[] = { |
297 | { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 }, | |
298 | { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 }, | |
299 | { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 }, | |
300 | { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 }, | |
301 | { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 }, | |
1da177e4 LT |
302 | { 0, }, |
303 | }; | |
304 | MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl); | |
305 | ||
a9ab09e2 | 306 | static struct pci_driver aec62xx_pci_driver = { |
1da177e4 LT |
307 | .name = "AEC62xx_IDE", |
308 | .id_table = aec62xx_pci_tbl, | |
309 | .probe = aec62xx_init_one, | |
fe31edc8 | 310 | .remove = aec62xx_remove, |
feb22b7f BZ |
311 | .suspend = ide_pci_suspend, |
312 | .resume = ide_pci_resume, | |
1da177e4 LT |
313 | }; |
314 | ||
82ab1eec | 315 | static int __init aec62xx_ide_init(void) |
1da177e4 | 316 | { |
a9ab09e2 | 317 | return ide_pci_register_driver(&aec62xx_pci_driver); |
1da177e4 LT |
318 | } |
319 | ||
eb7cb98b BZ |
320 | static void __exit aec62xx_ide_exit(void) |
321 | { | |
a9ab09e2 | 322 | pci_unregister_driver(&aec62xx_pci_driver); |
eb7cb98b BZ |
323 | } |
324 | ||
1da177e4 | 325 | module_init(aec62xx_ide_init); |
eb7cb98b | 326 | module_exit(aec62xx_ide_exit); |
1da177e4 LT |
327 | |
328 | MODULE_AUTHOR("Andre Hedrick"); | |
329 | MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE"); | |
330 | MODULE_LICENSE("GPL"); |