1 /* $NetBSD: optiide.c,v 1.16 2008/03/18 20:46:37 cube Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: optiide.c,v 1.16 2008/03/18 20:46:37 cube Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <dev/pci/pcivar.h>
39 #include <dev/pci/pcidevs.h>
40 #include <dev/pci/pciidereg.h>
41 #include <dev/pci/pciidevar.h>
42 #include <dev/pci/pciide_opti_reg.h>
44 static void opti_chip_map(struct pciide_softc
*, struct pci_attach_args
*);
45 static void opti_setup_channel(struct ata_channel
*);
47 static int optiide_match(device_t
, cfdata_t
, void *);
48 static void optiide_attach(device_t
, device_t
, void *);
50 CFATTACH_DECL_NEW(optiide
, sizeof(struct pciide_softc
),
51 optiide_match
, optiide_attach
, NULL
, NULL
);
53 static const struct pciide_product_desc pciide_opti_products
[] = {
54 { PCI_PRODUCT_OPTI_82C621
,
56 "OPTi 82c621 PCI IDE controller",
59 { PCI_PRODUCT_OPTI_82C568
,
61 "OPTi 82c568 (82c621 compatible) PCI IDE controller",
64 { PCI_PRODUCT_OPTI_82D568
,
66 "OPTi 82d568 (82c621 compatible) PCI IDE controller",
77 optiide_match(device_t parent
, cfdata_t match
, void *aux
)
79 struct pci_attach_args
*pa
= aux
;
81 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_OPTI
&&
82 PCI_CLASS(pa
->pa_class
) == PCI_CLASS_MASS_STORAGE
&&
83 PCI_SUBCLASS(pa
->pa_class
) == PCI_SUBCLASS_MASS_STORAGE_IDE
) {
84 if (pciide_lookup_product(pa
->pa_id
, pciide_opti_products
))
91 optiide_attach(device_t parent
, device_t self
, void *aux
)
93 struct pci_attach_args
*pa
= aux
;
94 struct pciide_softc
*sc
= device_private(self
);
96 sc
->sc_wdcdev
.sc_atac
.atac_dev
= self
;
98 pciide_common_attach(sc
, pa
,
99 pciide_lookup_product(pa
->pa_id
, pciide_opti_products
));
104 opti_chip_map(struct pciide_softc
*sc
, struct pci_attach_args
*pa
)
106 struct pciide_channel
*cp
;
107 bus_size_t cmdsize
, ctlsize
;
112 if (pciide_chipen(sc
, pa
) == 0)
115 aprint_verbose_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
116 "bus-master DMA support present");
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
126 if (PCI_REVISION(pa
->pa_class
) <= 0x12) {
127 aprint_verbose(" but disabled due to chip rev. <= 0x12");
130 pciide_mapreg_dma(sc
, pa
);
132 aprint_verbose("\n");
134 sc
->sc_wdcdev
.sc_atac
.atac_cap
= ATAC_CAP_DATA32
| ATAC_CAP_DATA16
;
135 sc
->sc_wdcdev
.sc_atac
.atac_pio_cap
= 4;
137 sc
->sc_wdcdev
.sc_atac
.atac_cap
|= ATAC_CAP_DMA
;
138 sc
->sc_wdcdev
.irqack
= pciide_irqack
;
139 sc
->sc_wdcdev
.sc_atac
.atac_dma_cap
= 2;
141 sc
->sc_wdcdev
.sc_atac
.atac_set_modes
= opti_setup_channel
;
143 sc
->sc_wdcdev
.sc_atac
.atac_channels
= sc
->wdc_chanarray
;
144 sc
->sc_wdcdev
.sc_atac
.atac_nchannels
= PCIIDE_NUM_CHANNELS
;
146 init_ctrl
= pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
,
147 OPTI_REG_INIT_CONTROL
);
149 interface
= PCI_INTERFACE(pa
->pa_class
);
151 wdc_allocate_regs(&sc
->sc_wdcdev
);
153 for (channel
= 0; channel
< sc
->sc_wdcdev
.sc_atac
.atac_nchannels
;
155 cp
= &sc
->pciide_channels
[channel
];
156 if (pciide_chansetup(sc
, channel
, interface
) == 0)
159 (init_ctrl
& OPTI_INIT_CONTROL_CH2_DISABLE
) != 0) {
160 aprint_normal_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
161 "%s channel ignored (disabled)\n", cp
->name
);
162 cp
->ata_channel
.ch_flags
|= ATACH_DISABLED
;
165 pciide_mapchan(pa
, cp
, interface
, &cmdsize
, &ctlsize
,
171 opti_setup_channel(struct ata_channel
*chp
)
173 struct ata_drive_datas
*drvp
;
174 struct pciide_channel
*cp
= CHAN_TO_PCHAN(chp
);
175 struct pciide_softc
*sc
= CHAN_TO_PCIIDE(chp
);
181 * The `Delay' and `Address Setup Time' fields of the
182 * Miscellaneous Register are always zero initially.
184 mr
= opti_read_config(chp
, OPTI_REG_MISC
) & ~OPTI_MISC_INDEX_MASK
;
185 mr
&= ~(OPTI_MISC_DELAY_MASK
|
186 OPTI_MISC_ADDR_SETUP_MASK
|
187 OPTI_MISC_INDEX_MASK
);
189 /* Prime the control register before setting timing values */
190 opti_write_config(chp
, OPTI_REG_CONTROL
, OPTI_CONTROL_DISABLE
);
192 /* Determine the clockrate of the PCIbus the chip is attached to */
193 spd
= (int) opti_read_config(chp
, OPTI_REG_STRAP
);
194 spd
&= OPTI_STRAP_PCI_SPEED_MASK
;
196 /* setup DMA if needed */
197 pciide_channel_dma_setup(cp
);
199 for (drive
= 0; drive
< 2; drive
++) {
200 drvp
= &chp
->ch_drive
[drive
];
201 /* If no drive, skip */
202 if ((drvp
->drive_flags
& DRIVE
) == 0) {
207 if ((drvp
->drive_flags
& DRIVE_DMA
)) {
209 * Timings will be used for both PIO and DMA,
210 * so adjust DMA mode if needed
212 if (drvp
->PIO_mode
> (drvp
->DMA_mode
+ 2))
213 drvp
->PIO_mode
= drvp
->DMA_mode
+ 2;
214 if (drvp
->DMA_mode
+ 2 > (drvp
->PIO_mode
))
215 drvp
->DMA_mode
= (drvp
->PIO_mode
> 2) ?
216 drvp
->PIO_mode
- 2 : 0;
217 if (drvp
->DMA_mode
== 0)
220 mode
[drive
] = drvp
->DMA_mode
+ 5;
222 mode
[drive
] = drvp
->PIO_mode
;
224 if (drive
&& mode
[0] >= 0 &&
225 (opti_tim_as
[spd
][mode
[0]] != opti_tim_as
[spd
][mode
[1]])) {
227 * Can't have two drives using different values
228 * for `Address Setup Time'.
229 * Slow down the faster drive to compensate.
231 int d
= (opti_tim_as
[spd
][mode
[0]] >
232 opti_tim_as
[spd
][mode
[1]]) ? 0 : 1;
235 chp
->ch_drive
[d
].PIO_mode
= chp
->ch_drive
[1-d
].PIO_mode
;
236 chp
->ch_drive
[d
].DMA_mode
= 0;
238 chp
->ch_drive
[d
].drive_flags
&= ~DRIVE_DMA
;
243 for (drive
= 0; drive
< 2; drive
++) {
245 if ((m
= mode
[drive
]) < 0)
248 /* Set the Address Setup Time and select appropriate index */
249 rv
= opti_tim_as
[spd
][m
] << OPTI_MISC_ADDR_SETUP_SHIFT
;
250 rv
|= OPTI_MISC_INDEX(drive
);
251 opti_write_config(chp
, OPTI_REG_MISC
, mr
| rv
);
253 /* Set the pulse width and recovery timing parameters */
254 rv
= opti_tim_cp
[spd
][m
] << OPTI_PULSE_WIDTH_SHIFT
;
255 rv
|= opti_tim_rt
[spd
][m
] << OPTI_RECOVERY_TIME_SHIFT
;
256 opti_write_config(chp
, OPTI_REG_READ_CYCLE_TIMING
, rv
);
257 opti_write_config(chp
, OPTI_REG_WRITE_CYCLE_TIMING
, rv
);
259 /* Set the Enhanced Mode register appropriately */
260 rv
= pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, OPTI_REG_ENH_MODE
);
261 rv
&= ~OPTI_ENH_MODE_MASK(chp
->ch_channel
, drive
);
262 rv
|= OPTI_ENH_MODE(chp
->ch_channel
, drive
, opti_tim_em
[m
]);
263 pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
, OPTI_REG_ENH_MODE
, rv
);
266 /* Finally, enable the timings */
267 opti_write_config(chp
, OPTI_REG_CONTROL
, OPTI_CONTROL_ENABLE
);