Root/
1 | /* |
2 | * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) |
3 | */ |
4 | |
5 | /* |
6 | * Authors: |
7 | * Jaromir Koutek <miri@punknet.cz>, |
8 | * Jan Harkes <jaharkes@cwi.nl>, |
9 | * Mark Lord <mlord@pobox.com> |
10 | * Some parts of code are from ali14xx.c and from rz1000.c. |
11 | */ |
12 | |
13 | #include <linux/types.h> |
14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/pci.h> |
17 | #include <linux/ide.h> |
18 | |
19 | #include <asm/io.h> |
20 | |
21 | #define DRV_NAME "opti621" |
22 | |
23 | #define READ_REG 0 /* index of Read cycle timing register */ |
24 | #define WRITE_REG 1 /* index of Write cycle timing register */ |
25 | #define CNTRL_REG 3 /* index of Control register */ |
26 | #define STRAP_REG 5 /* index of Strap register */ |
27 | #define MISC_REG 6 /* index of Miscellaneous register */ |
28 | |
29 | static int reg_base; |
30 | |
31 | static DEFINE_SPINLOCK(opti621_lock); |
32 | |
33 | /* Write value to register reg, base of register |
34 | * is at reg_base (0x1f0 primary, 0x170 secondary, |
35 | * if not changed by PCI configuration). |
36 | * This is from setupvic.exe program. |
37 | */ |
38 | static void write_reg(u8 value, int reg) |
39 | { |
40 | inw(reg_base + 1); |
41 | inw(reg_base + 1); |
42 | outb(3, reg_base + 2); |
43 | outb(value, reg_base + reg); |
44 | outb(0x83, reg_base + 2); |
45 | } |
46 | |
47 | /* Read value from register reg, base of register |
48 | * is at reg_base (0x1f0 primary, 0x170 secondary, |
49 | * if not changed by PCI configuration). |
50 | * This is from setupvic.exe program. |
51 | */ |
52 | static u8 read_reg(int reg) |
53 | { |
54 | u8 ret = 0; |
55 | |
56 | inw(reg_base + 1); |
57 | inw(reg_base + 1); |
58 | outb(3, reg_base + 2); |
59 | ret = inb(reg_base + reg); |
60 | outb(0x83, reg_base + 2); |
61 | |
62 | return ret; |
63 | } |
64 | |
65 | static void opti621_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) |
66 | { |
67 | ide_drive_t *pair = ide_get_pair_dev(drive); |
68 | unsigned long flags; |
69 | unsigned long mode = drive->pio_mode, pair_mode; |
70 | const u8 pio = mode - XFER_PIO_0; |
71 | u8 tim, misc, addr_pio = pio, clk; |
72 | |
73 | /* DRDY is default 2 (by OPTi Databook) */ |
74 | static const u8 addr_timings[2][5] = { |
75 | { 0x20, 0x10, 0x00, 0x00, 0x00 }, /* 33 MHz */ |
76 | { 0x10, 0x10, 0x00, 0x00, 0x00 }, /* 25 MHz */ |
77 | }; |
78 | static const u8 data_rec_timings[2][5] = { |
79 | { 0x5b, 0x45, 0x32, 0x21, 0x20 }, /* 33 MHz */ |
80 | { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */ |
81 | }; |
82 | |
83 | ide_set_drivedata(drive, (void *)mode); |
84 | |
85 | if (pair) { |
86 | pair_mode = (unsigned long)ide_get_drivedata(pair); |
87 | if (pair_mode && pair_mode < mode) |
88 | addr_pio = pair_mode - XFER_PIO_0; |
89 | } |
90 | |
91 | spin_lock_irqsave(&opti621_lock, flags); |
92 | |
93 | reg_base = hwif->io_ports.data_addr; |
94 | |
95 | /* allow Register-B */ |
96 | outb(0xc0, reg_base + CNTRL_REG); |
97 | /* hmm, setupvic.exe does this ;-) */ |
98 | outb(0xff, reg_base + 5); |
99 | /* if reads 0xff, adapter not exist? */ |
100 | (void)inb(reg_base + CNTRL_REG); |
101 | /* if reads 0xc0, no interface exist? */ |
102 | read_reg(CNTRL_REG); |
103 | |
104 | /* check CLK speed */ |
105 | clk = read_reg(STRAP_REG) & 1; |
106 | |
107 | printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33); |
108 | |
109 | tim = data_rec_timings[clk][pio]; |
110 | misc = addr_timings[clk][addr_pio]; |
111 | |
112 | /* select Index-0/1 for Register-A/B */ |
113 | write_reg(drive->dn & 1, MISC_REG); |
114 | /* set read cycle timings */ |
115 | write_reg(tim, READ_REG); |
116 | /* set write cycle timings */ |
117 | write_reg(tim, WRITE_REG); |
118 | |
119 | /* use Register-A for drive 0 */ |
120 | /* use Register-B for drive 1 */ |
121 | write_reg(0x85, CNTRL_REG); |
122 | |
123 | /* set address setup, DRDY timings, */ |
124 | /* and read prefetch for both drives */ |
125 | write_reg(misc, MISC_REG); |
126 | |
127 | spin_unlock_irqrestore(&opti621_lock, flags); |
128 | } |
129 | |
130 | static const struct ide_port_ops opti621_port_ops = { |
131 | .set_pio_mode = opti621_set_pio_mode, |
132 | }; |
133 | |
134 | static const struct ide_port_info opti621_chipset __devinitdata = { |
135 | .name = DRV_NAME, |
136 | .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, |
137 | .port_ops = &opti621_port_ops, |
138 | .host_flags = IDE_HFLAG_NO_DMA, |
139 | .pio_mask = ATA_PIO4, |
140 | }; |
141 | |
142 | static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id) |
143 | { |
144 | return ide_pci_init_one(dev, &opti621_chipset, NULL); |
145 | } |
146 | |
147 | static const struct pci_device_id opti621_pci_tbl[] = { |
148 | { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 }, |
149 | { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 }, |
150 | { 0, }, |
151 | }; |
152 | MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); |
153 | |
154 | static struct pci_driver opti621_pci_driver = { |
155 | .name = "Opti621_IDE", |
156 | .id_table = opti621_pci_tbl, |
157 | .probe = opti621_init_one, |
158 | .remove = ide_pci_remove, |
159 | .suspend = ide_pci_suspend, |
160 | .resume = ide_pci_resume, |
161 | }; |
162 | |
163 | static int __init opti621_ide_init(void) |
164 | { |
165 | return ide_pci_register_driver(&opti621_pci_driver); |
166 | } |
167 | |
168 | static void __exit opti621_ide_exit(void) |
169 | { |
170 | pci_unregister_driver(&opti621_pci_driver); |
171 | } |
172 | |
173 | module_init(opti621_ide_init); |
174 | module_exit(opti621_ide_exit); |
175 | |
176 | MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord"); |
177 | MODULE_DESCRIPTION("PCI driver module for Opti621 IDE"); |
178 | MODULE_LICENSE("GPL"); |
179 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9