Blame view
drivers/ide/cy82c693.c
6.29 KB
09c434b8a
|
1 |
// SPDX-License-Identifier: GPL-2.0-only |
1da177e4c
|
2 |
/* |
1da177e4c
|
3 4 |
* Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator |
0ab3d8b32
|
5 |
* Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz |
1da177e4c
|
6 7 8 9 |
* * CYPRESS CY82C693 chipset IDE controller * * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards. |
1da177e4c
|
10 |
*/ |
1da177e4c
|
11 12 13 |
#include <linux/module.h> #include <linux/types.h> #include <linux/pci.h> |
1da177e4c
|
14 15 16 17 |
#include <linux/ide.h> #include <linux/init.h> #include <asm/io.h> |
ced3ec8aa
|
18 |
#define DRV_NAME "cy82c693" |
1da177e4c
|
19 |
/* |
1da177e4c
|
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
* NOTE: the value for busmaster timeout is tricky and I got it by * trial and error! By using a to low value will cause DMA timeouts * and drop IDE performance, and by using a to high value will cause * audio playback to scatter. * If you know a better value or how to calc it, please let me know. */ /* twice the value written in cy82c693ub datasheet */ #define BUSMASTER_TIMEOUT 0x50 /* * the value above was tested on my machine and it seems to work okay */ /* here are the offset definitions for the registers */ #define CY82_IDE_CMDREG 0x04 #define CY82_IDE_ADDRSETUP 0x48 #define CY82_IDE_MASTER_IOR 0x4C #define CY82_IDE_MASTER_IOW 0x4D #define CY82_IDE_SLAVE_IOR 0x4E #define CY82_IDE_SLAVE_IOW 0x4F #define CY82_IDE_MASTER_8BIT 0x50 #define CY82_IDE_SLAVE_8BIT 0x51 #define CY82_INDEX_PORT 0x22 #define CY82_DATA_PORT 0x23 |
1da177e4c
|
45 46 47 |
#define CY82_INDEX_CHANNEL0 0x30 #define CY82_INDEX_CHANNEL1 0x31 #define CY82_INDEX_TIMEOUT 0x32 |
1da177e4c
|
48 49 50 |
/* * set DMA mode a specific channel for CY82C693 */ |
8776168ca
|
51 |
static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
1da177e4c
|
52 |
{ |
8776168ca
|
53 |
const u8 mode = drive->dma_mode; |
8704de8f2
|
54 |
u8 single = (mode & 0x10) >> 4, index = 0, data = 0; |
1da177e4c
|
55 |
|
8704de8f2
|
56 |
index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0; |
1da177e4c
|
57 |
|
8704de8f2
|
58 |
data = (mode & 3) | (single << 2); |
1da177e4c
|
59 |
|
0ecdca26e
|
60 61 |
outb(index, CY82_INDEX_PORT); outb(data, CY82_DATA_PORT); |
1da177e4c
|
62 |
|
175f354b7
|
63 |
/* |
1da177e4c
|
64 |
* note: below we set the value for Bus Master IDE TimeOut Register |
25985edce
|
65 |
* I'm not absolutely sure what this does, but it solved my problem |
1da177e4c
|
66 67 68 69 70 71 72 73 |
* with IDE DMA and sound, so I now can play sound and work with * my IDE driver at the same time :-) * * If you know the correct (best) value for this register please * let me know - ASK */ data = BUSMASTER_TIMEOUT; |
0ecdca26e
|
74 75 |
outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); outb(data, CY82_DATA_PORT); |
1da177e4c
|
76 |
} |
e085b3cae
|
77 |
static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
1da177e4c
|
78 |
{ |
36501650e
|
79 |
struct pci_dev *dev = to_pci_dev(hwif->dev); |
4d6b32894
|
80 81 |
int bus_speed = ide_pci_clk ? ide_pci_clk : 33; const unsigned long T = 1000000 / bus_speed; |
1da177e4c
|
82 |
unsigned int addrCtrl; |
4d6b32894
|
83 84 |
struct ide_timing t; u8 time_16, time_8; |
1da177e4c
|
85 86 |
/* select primary or secondary channel */ |
0ab3d8b32
|
87 |
if (drive->dn > 1) { /* drive is on the secondary channel */ |
652aa1629
|
88 |
dev = pci_get_slot(dev->bus, dev->devfn+1); |
1da177e4c
|
89 90 91 92 93 94 95 96 |
if (!dev) { printk(KERN_ERR "%s: tune_drive: " "Cannot find secondary interface! ", drive->name); return; } } |
e085b3cae
|
97 |
ide_timing_compute(drive, drive->pio_mode, &t, T, 1); |
4d6b32894
|
98 99 100 101 102 |
time_16 = clamp_val(t.recover - 1, 0, 15) | (clamp_val(t.active - 1, 0, 15) << 4); time_8 = clamp_val(t.act8b - 1, 0, 15) | (clamp_val(t.rec8b - 1, 0, 15) << 4); |
1da177e4c
|
103 104 |
/* now let's write the clocks registers */ |
123995b97
|
105 |
if ((drive->dn & 1) == 0) { |
1da177e4c
|
106 107 108 109 |
/* * set master drive * address setup control register * is 32 bit !!! |
175f354b7
|
110 |
*/ |
1da177e4c
|
111 |
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); |
175f354b7
|
112 |
|
1da177e4c
|
113 |
addrCtrl &= (~0xF); |
4d6b32894
|
114 |
addrCtrl |= clamp_val(t.setup - 1, 0, 15); |
1da177e4c
|
115 116 117 |
pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); /* now let's set the remaining registers */ |
4d6b32894
|
118 119 120 |
pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, time_16); pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, time_16); pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, time_8); |
1da177e4c
|
121 122 123 124 125 |
} else { /* * set slave drive * address setup control register * is 32 bit !!! |
175f354b7
|
126 |
*/ |
1da177e4c
|
127 128 129 |
pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); addrCtrl &= (~0xF0); |
4d6b32894
|
130 |
addrCtrl |= (clamp_val(t.setup - 1, 0, 15) << 4); |
1da177e4c
|
131 132 133 |
pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); /* now let's set the remaining registers */ |
4d6b32894
|
134 135 136 |
pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, time_16); pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16); pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8); |
175f354b7
|
137 |
} |
0ab3d8b32
|
138 |
if (drive->dn > 1) |
0302899e1
|
139 |
pci_dev_put(dev); |
1da177e4c
|
140 |
} |
fe31edc8a
|
141 |
static void init_iops_cy82c693(ide_hwif_t *hwif) |
1da177e4c
|
142 |
{ |
f32d26ae2
|
143 |
static ide_hwif_t *primary; |
36501650e
|
144 |
struct pci_dev *dev = to_pci_dev(hwif->dev); |
f32d26ae2
|
145 |
|
36501650e
|
146 |
if (PCI_FUNC(dev->devfn) == 1) |
1da177e4c
|
147 148 149 150 151 152 |
primary = hwif; else { hwif->mate = primary; hwif->channel = 1; } } |
ac95beedf
|
153 154 155 156 |
static const struct ide_port_ops cy82c693_port_ops = { .set_pio_mode = cy82c693_set_pio_mode, .set_dma_mode = cy82c693_set_dma_mode, }; |
fe31edc8a
|
157 |
static const struct ide_port_info cy82c693_chipset = { |
ced3ec8aa
|
158 |
.name = DRV_NAME, |
7b77d864a
|
159 |
.init_iops = init_iops_cy82c693, |
ac95beedf
|
160 |
.port_ops = &cy82c693_port_ops, |
951784b66
|
161 |
.host_flags = IDE_HFLAG_SINGLE, |
4099d1432
|
162 |
.pio_mask = ATA_PIO4, |
8704de8f2
|
163 164 |
.swdma_mask = ATA_SWDMA2, .mwdma_mask = ATA_MWDMA2, |
1da177e4c
|
165 |
}; |
fe31edc8a
|
166 167 |
static int cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id) |
1da177e4c
|
168 |
{ |
1da177e4c
|
169 170 171 172 173 |
struct pci_dev *dev2; int ret = -ENODEV; /* CY82C693 is more than only a IDE controller. Function 1 is primary IDE channel, function 2 - secondary. */ |
175f354b7
|
174 |
if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && |
1da177e4c
|
175 |
PCI_FUNC(dev->devfn) == 1) { |
652aa1629
|
176 |
dev2 = pci_get_slot(dev->bus, dev->devfn + 1); |
6cdf6eb35
|
177 |
ret = ide_pci_init_two(dev, dev2, &cy82c693_chipset, NULL); |
cd68841b8
|
178 179 |
if (ret) pci_dev_put(dev2); |
1da177e4c
|
180 181 182 |
} return ret; } |
fe31edc8a
|
183 |
static void cy82c693_remove(struct pci_dev *dev) |
cd68841b8
|
184 185 186 187 188 189 190 |
{ struct ide_host *host = pci_get_drvdata(dev); struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; ide_pci_remove(dev); pci_dev_put(dev2); } |
9cbcc5e3c
|
191 192 |
static const struct pci_device_id cy82c693_pci_tbl[] = { { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 }, |
1da177e4c
|
193 194 195 |
{ 0, }, }; MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl); |
a9ab09e26
|
196 |
static struct pci_driver cy82c693_pci_driver = { |
1da177e4c
|
197 198 199 |
.name = "Cypress_IDE", .id_table = cy82c693_pci_tbl, .probe = cy82c693_init_one, |
fe31edc8a
|
200 |
.remove = cy82c693_remove, |
feb22b7f8
|
201 202 |
.suspend = ide_pci_suspend, .resume = ide_pci_resume, |
1da177e4c
|
203 |
}; |
82ab1eece
|
204 |
static int __init cy82c693_ide_init(void) |
1da177e4c
|
205 |
{ |
a9ab09e26
|
206 |
return ide_pci_register_driver(&cy82c693_pci_driver); |
1da177e4c
|
207 |
} |
cd68841b8
|
208 209 |
static void __exit cy82c693_ide_exit(void) { |
a9ab09e26
|
210 |
pci_unregister_driver(&cy82c693_pci_driver); |
cd68841b8
|
211 |
} |
1da177e4c
|
212 |
module_init(cy82c693_ide_init); |
cd68841b8
|
213 |
module_exit(cy82c693_ide_exit); |
1da177e4c
|
214 |
|
4d6b32894
|
215 |
MODULE_AUTHOR("Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz"); |
1da177e4c
|
216 217 |
MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE"); MODULE_LICENSE("GPL"); |