optiide.c revision 1.2 1 /* $NetBSD: optiide.c,v 1.2 2003/10/11 17:40:15 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41
42 #include <dev/pci/pcivar.h>
43 #include <dev/pci/pcidevs.h>
44 #include <dev/pci/pciidereg.h>
45 #include <dev/pci/pciidevar.h>
46 #include <dev/pci/pciide_opti_reg.h>
47
48 static void opti_chip_map(struct pciide_softc*, struct pci_attach_args*);
49 static void opti_setup_channel(struct channel_softc*);
50
51 static int optiide_match(struct device *, struct cfdata *, void *);
52 static void optiide_attach(struct device *, struct device *, void *);
53
54 CFATTACH_DECL(optiide, sizeof(struct pciide_softc),
55 optiide_match, optiide_attach, NULL, NULL);
56
57 static const struct pciide_product_desc pciide_opti_products[] = {
58 { PCI_PRODUCT_OPTI_82C621,
59 0,
60 "OPTi 82c621 PCI IDE controller",
61 opti_chip_map,
62 },
63 { PCI_PRODUCT_OPTI_82C568,
64 0,
65 "OPTi 82c568 (82c621 compatible) PCI IDE controller",
66 opti_chip_map,
67 },
68 { PCI_PRODUCT_OPTI_82D568,
69 0,
70 "OPTi 82d568 (82c621 compatible) PCI IDE controller",
71 opti_chip_map,
72 },
73 { 0,
74 0,
75 NULL,
76 NULL
77 }
78 };
79
80 static int
81 optiide_match(struct device *parent, struct cfdata *match, void *aux)
82 {
83 struct pci_attach_args *pa = aux;
84
85 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_OPTI) {
86 if (pciide_lookup_product(pa->pa_id, pciide_opti_products))
87 return (2);
88 }
89 return (0);
90 }
91
92 static void
93 optiide_attach(struct device *parent, struct device *self, void *aux)
94 {
95 struct pci_attach_args *pa = aux;
96 struct pciide_softc *sc = (struct pciide_softc *)self;
97
98 pciide_common_attach(sc, pa,
99 pciide_lookup_product(pa->pa_id, pciide_opti_products));
100
101 }
102
103 static void
104 opti_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
105 {
106 struct pciide_channel *cp;
107 bus_size_t cmdsize, ctlsize;
108 pcireg_t interface;
109 u_int8_t init_ctrl;
110 int channel;
111
112 if (pciide_chipen(sc, pa) == 0)
113 return;
114
115 aprint_normal("%s: bus-master DMA support present",
116 sc->sc_wdcdev.sc_dev.dv_xname);
117
118 /*
119 * XXXSCW:
120 * There seem to be a couple of buggy revisions/implementations
121 * of the OPTi pciide chipset. This kludge seems to fix one of
122 * the reported problems (PR/11644) but still fails for the
123 * other (PR/13151), although the latter may be due to other
124 * issues too...
125 */
126 if (PCI_REVISION(pa->pa_class) <= 0x12) {
127 aprint_normal(" but disabled due to chip rev. <= 0x12");
128 sc->sc_dma_ok = 0;
129 } else
130 pciide_mapreg_dma(sc, pa);
131
132 aprint_normal("\n");
133
134 sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA32 | WDC_CAPABILITY_DATA16 |
135 WDC_CAPABILITY_MODE;
136 sc->sc_wdcdev.PIO_cap = 4;
137 if (sc->sc_dma_ok) {
138 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
139 sc->sc_wdcdev.irqack = pciide_irqack;
140 sc->sc_wdcdev.DMA_cap = 2;
141 }
142 sc->sc_wdcdev.set_modes = opti_setup_channel;
143
144 sc->sc_wdcdev.channels = sc->wdc_chanarray;
145 sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
146
147 init_ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag,
148 OPTI_REG_INIT_CONTROL);
149
150 interface = PCI_INTERFACE(pa->pa_class);
151
152 for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
153 cp = &sc->pciide_channels[channel];
154 if (pciide_chansetup(sc, channel, interface) == 0)
155 continue;
156 if (channel == 1 &&
157 (init_ctrl & OPTI_INIT_CONTROL_CH2_DISABLE) != 0) {
158 aprint_normal("%s: %s channel ignored (disabled)\n",
159 sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
160 cp->wdc_channel.ch_flags |= WDCF_DISABLED;
161 continue;
162 }
163 pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
164 pciide_pci_intr);
165 }
166 }
167
168 static void
169 opti_setup_channel(struct channel_softc *chp)
170 {
171 struct ata_drive_datas *drvp;
172 struct pciide_channel *cp = (struct pciide_channel*)chp;
173 struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
174 int drive, spd;
175 int mode[2];
176 u_int8_t rv, mr;
177
178 /*
179 * The `Delay' and `Address Setup Time' fields of the
180 * Miscellaneous Register are always zero initially.
181 */
182 mr = opti_read_config(chp, OPTI_REG_MISC) & ~OPTI_MISC_INDEX_MASK;
183 mr &= ~(OPTI_MISC_DELAY_MASK |
184 OPTI_MISC_ADDR_SETUP_MASK |
185 OPTI_MISC_INDEX_MASK);
186
187 /* Prime the control register before setting timing values */
188 opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_DISABLE);
189
190 /* Determine the clockrate of the PCIbus the chip is attached to */
191 spd = (int) opti_read_config(chp, OPTI_REG_STRAP);
192 spd &= OPTI_STRAP_PCI_SPEED_MASK;
193
194 /* setup DMA if needed */
195 pciide_channel_dma_setup(cp);
196
197 for (drive = 0; drive < 2; drive++) {
198 drvp = &chp->ch_drive[drive];
199 /* If no drive, skip */
200 if ((drvp->drive_flags & DRIVE) == 0) {
201 mode[drive] = -1;
202 continue;
203 }
204
205 if ((drvp->drive_flags & DRIVE_DMA)) {
206 /*
207 * Timings will be used for both PIO and DMA,
208 * so adjust DMA mode if needed
209 */
210 if (drvp->PIO_mode > (drvp->DMA_mode + 2))
211 drvp->PIO_mode = drvp->DMA_mode + 2;
212 if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
213 drvp->DMA_mode = (drvp->PIO_mode > 2) ?
214 drvp->PIO_mode - 2 : 0;
215 if (drvp->DMA_mode == 0)
216 drvp->PIO_mode = 0;
217
218 mode[drive] = drvp->DMA_mode + 5;
219 } else
220 mode[drive] = drvp->PIO_mode;
221
222 if (drive && mode[0] >= 0 &&
223 (opti_tim_as[spd][mode[0]] != opti_tim_as[spd][mode[1]])) {
224 /*
225 * Can't have two drives using different values
226 * for `Address Setup Time'.
227 * Slow down the faster drive to compensate.
228 */
229 int d = (opti_tim_as[spd][mode[0]] >
230 opti_tim_as[spd][mode[1]]) ? 0 : 1;
231
232 mode[d] = mode[1-d];
233 chp->ch_drive[d].PIO_mode = chp->ch_drive[1-d].PIO_mode;
234 chp->ch_drive[d].DMA_mode = 0;
235 chp->ch_drive[d].drive_flags &= ~DRIVE_DMA;
236 }
237 }
238
239 for (drive = 0; drive < 2; drive++) {
240 int m;
241 if ((m = mode[drive]) < 0)
242 continue;
243
244 /* Set the Address Setup Time and select appropriate index */
245 rv = opti_tim_as[spd][m] << OPTI_MISC_ADDR_SETUP_SHIFT;
246 rv |= OPTI_MISC_INDEX(drive);
247 opti_write_config(chp, OPTI_REG_MISC, mr | rv);
248
249 /* Set the pulse width and recovery timing parameters */
250 rv = opti_tim_cp[spd][m] << OPTI_PULSE_WIDTH_SHIFT;
251 rv |= opti_tim_rt[spd][m] << OPTI_RECOVERY_TIME_SHIFT;
252 opti_write_config(chp, OPTI_REG_READ_CYCLE_TIMING, rv);
253 opti_write_config(chp, OPTI_REG_WRITE_CYCLE_TIMING, rv);
254
255 /* Set the Enhanced Mode register appropriately */
256 rv = pciide_pci_read(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE);
257 rv &= ~OPTI_ENH_MODE_MASK(chp->channel, drive);
258 rv |= OPTI_ENH_MODE(chp->channel, drive, opti_tim_em[m]);
259 pciide_pci_write(sc->sc_pc, sc->sc_tag, OPTI_REG_ENH_MODE, rv);
260 }
261
262 /* Finally, enable the timings */
263 opti_write_config(chp, OPTI_REG_CONTROL, OPTI_CONTROL_ENABLE);
264 }
265