1 /* $NetBSD: aceride.c,v 1.25 2008/03/18 20:46:36 cube Exp $ */
4 * Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: aceride.c,v 1.25 2008/03/18 20:46:36 cube Exp $");
30 #include <sys/param.h>
31 #include <sys/systm.h>
33 #include <dev/pci/pcivar.h>
34 #include <dev/pci/pcidevs.h>
35 #include <dev/pci/pciidereg.h>
36 #include <dev/pci/pciidevar.h>
37 #include <dev/pci/pciide_acer_reg.h>
39 static int acer_pcib_match(struct pci_attach_args
*);
40 static void acer_do_reset(struct ata_channel
*, int);
41 static void acer_chip_map(struct pciide_softc
*, struct pci_attach_args
*);
42 static void acer_setup_channel(struct ata_channel
*);
43 static int acer_pci_intr(void *);
45 static int aceride_match(device_t
, cfdata_t
, void *);
46 static void aceride_attach(device_t
, device_t
, void *);
48 struct aceride_softc
{
49 struct pciide_softc pciide_sc
;
50 struct pci_attach_args pcib_pa
;
53 CFATTACH_DECL_NEW(aceride
, sizeof(struct aceride_softc
),
54 aceride_match
, aceride_attach
, NULL
, NULL
);
56 static const struct pciide_product_desc pciide_acer_products
[] = {
57 { PCI_PRODUCT_ALI_M5229
,
59 "Acer Labs M5229 UDMA IDE Controller",
70 aceride_match(device_t parent
, cfdata_t match
, void *aux
)
72 struct pci_attach_args
*pa
= aux
;
74 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_ALI
&&
75 PCI_CLASS(pa
->pa_class
) == PCI_CLASS_MASS_STORAGE
&&
76 PCI_SUBCLASS(pa
->pa_class
) == PCI_SUBCLASS_MASS_STORAGE_IDE
) {
77 if (pciide_lookup_product(pa
->pa_id
, pciide_acer_products
))
84 aceride_attach(device_t parent
, device_t self
, void *aux
)
86 struct pci_attach_args
*pa
= aux
;
87 struct pciide_softc
*sc
= device_private(self
);
89 sc
->sc_wdcdev
.sc_atac
.atac_dev
= self
;
91 pciide_common_attach(sc
, pa
,
92 pciide_lookup_product(pa
->pa_id
, pciide_acer_products
));
96 acer_pcib_match(struct pci_attach_args
*pa
)
99 * we need to access the PCI config space of the pcib, see
102 if (PCI_CLASS(pa
->pa_class
) == PCI_CLASS_BRIDGE
&&
103 PCI_SUBCLASS(pa
->pa_class
) == PCI_SUBCLASS_BRIDGE_ISA
&&
104 PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_ALI
&&
105 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_ALI_M1543
)
111 acer_chip_map(struct pciide_softc
*sc
, struct pci_attach_args
*pa
)
113 struct pciide_channel
*cp
;
115 pcireg_t cr
, interface
;
116 bus_size_t cmdsize
, ctlsize
;
117 pcireg_t rev
= PCI_REVISION(pa
->pa_class
);
118 struct aceride_softc
*acer_sc
= (struct aceride_softc
*)sc
;
120 if (pciide_chipen(sc
, pa
) == 0)
123 aprint_verbose_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
124 "bus-master DMA support present");
125 pciide_mapreg_dma(sc
, pa
);
126 aprint_verbose("\n");
127 sc
->sc_wdcdev
.sc_atac
.atac_cap
= ATAC_CAP_DATA16
| ATAC_CAP_DATA32
;
129 sc
->sc_wdcdev
.sc_atac
.atac_cap
|= ATAC_CAP_DMA
;
131 sc
->sc_wdcdev
.sc_atac
.atac_cap
|= ATAC_CAP_UDMA
;
133 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 6;
134 else if (rev
>= 0xC4)
135 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 5;
136 else if (rev
>= 0xC2)
137 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 4;
139 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 2;
141 sc
->sc_wdcdev
.irqack
= pciide_irqack
;
144 sc
->sc_wdcdev
.sc_atac
.atac_pio_cap
= 4;
145 sc
->sc_wdcdev
.sc_atac
.atac_dma_cap
= 2;
146 sc
->sc_wdcdev
.sc_atac
.atac_set_modes
= acer_setup_channel
;
147 sc
->sc_wdcdev
.sc_atac
.atac_channels
= sc
->wdc_chanarray
;
148 sc
->sc_wdcdev
.sc_atac
.atac_nchannels
= PCIIDE_NUM_CHANNELS
;
150 pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
, ACER_CDRC
,
151 (pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, ACER_CDRC
) |
152 ACER_CDRC_DMA_EN
) & ~ACER_CDRC_FIFO_DISABLE
);
154 /* Enable "microsoft register bits" R/W. */
155 pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
, ACER_CCAR3
,
156 pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, ACER_CCAR3
) | ACER_CCAR3_PI
);
157 pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
, ACER_CCAR1
,
158 pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, ACER_CCAR1
) &
159 ~(ACER_CHANSTATUS_RO
|PCIIDE_CHAN_RO(0)|PCIIDE_CHAN_RO(1)));
160 pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
, ACER_CCAR2
,
161 pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, ACER_CCAR2
) &
162 ~ACER_CHANSTATUSREGS_RO
);
163 cr
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, PCI_CLASS_REG
);
164 cr
|= (PCIIDE_CHANSTATUS_EN
<< PCI_INTERFACE_SHIFT
);
168 * some BIOSes (port-cats ABLE) enable native mode, but don't
169 * setup everything correctly, so allow the forcing of
172 bool force_compat_mode
;
173 bool property_is_set
;
174 property_is_set
= prop_dictionary_get_bool(
175 device_properties(sc
->sc_wdcdev
.sc_atac
.atac_dev
),
176 "ali1543-ide-force-compat-mode",
178 if (property_is_set
&& force_compat_mode
) {
179 cr
&= ~((PCIIDE_INTERFACE_PCI(0)
180 | PCIIDE_INTERFACE_PCI(1))
181 << PCI_INTERFACE_SHIFT
);
185 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, PCI_CLASS_REG
, cr
);
186 /* Don't use cr, re-read the real register content instead */
187 interface
= PCI_INTERFACE(pci_conf_read(sc
->sc_pc
, sc
->sc_tag
,
190 /* From linux: enable "Cable Detection" */
192 pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
, ACER_0x4B
,
193 pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, ACER_0x4B
)
194 | ACER_0x4B_CDETECT
);
197 wdc_allocate_regs(&sc
->sc_wdcdev
);
199 /* install reset bug workaround */
200 if (pci_find_device(&acer_sc
->pcib_pa
, acer_pcib_match
) == 0) {
201 aprint_error_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
202 "WARNING: can't find pci-isa bridge\n");
204 sc
->sc_wdcdev
.reset
= acer_do_reset
;
207 for (channel
= 0; channel
< sc
->sc_wdcdev
.sc_atac
.atac_nchannels
;
209 cp
= &sc
->pciide_channels
[channel
];
210 if (pciide_chansetup(sc
, channel
, interface
) == 0)
212 if ((interface
& PCIIDE_CHAN_EN(channel
)) == 0) {
213 aprint_normal_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
214 "%s channel ignored (disabled)\n", cp
->name
);
215 cp
->ata_channel
.ch_flags
|= ATACH_DISABLED
;
218 /* newer controllers seems to lack the ACER_CHIDS. Sigh */
219 pciide_mapchan(pa
, cp
, interface
, &cmdsize
, &ctlsize
,
220 (rev
>= 0xC2) ? pciide_pci_intr
: acer_pci_intr
);
225 acer_do_reset(struct ata_channel
*chp
, int poll
)
227 struct pciide_softc
*sc
= CHAN_TO_PCIIDE(chp
);
228 struct aceride_softc
*acer_sc
= (struct aceride_softc
*)sc
;
232 * From OpenSolaris: after a reset we need to disable/enable the
233 * corresponding channel, or data corruption will occur in
237 wdc_do_reset(chp
, poll
);
238 reg
= pciide_pci_read(acer_sc
->pcib_pa
.pa_pc
, acer_sc
->pcib_pa
.pa_tag
,
240 pciide_pci_write(acer_sc
->pcib_pa
.pa_pc
, acer_sc
->pcib_pa
.pa_tag
,
241 ACER_PCIB_CTRL
, reg
& ~ACER_PCIB_CTRL_ENCHAN(chp
->ch_channel
));
243 pciide_pci_write(acer_sc
->pcib_pa
.pa_pc
, acer_sc
->pcib_pa
.pa_tag
,
244 ACER_PCIB_CTRL
, reg
);
248 acer_setup_channel(struct ata_channel
*chp
)
250 struct ata_drive_datas
*drvp
;
252 u_int32_t acer_fifo_udma
;
253 u_int32_t idedma_ctl
;
254 struct pciide_channel
*cp
= (struct pciide_channel
*)chp
;
255 struct pciide_softc
*sc
= CHAN_TO_PCIIDE(chp
);
258 acer_fifo_udma
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, ACER_FTH_UDMA
);
259 ATADEBUG_PRINT(("acer_setup_channel: old fifo/udma reg 0x%x\n",
260 acer_fifo_udma
), DEBUG_PROBE
);
261 /* setup DMA if needed */
262 pciide_channel_dma_setup(cp
);
264 if ((chp
->ch_drive
[0].drive_flags
| chp
->ch_drive
[1].drive_flags
) &
265 DRIVE_UDMA
) { /* check 80 pins cable */
266 if (pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, ACER_0x4A
) &
267 ACER_0x4A_80PIN(chp
->ch_channel
)) {
268 if (chp
->ch_drive
[0].UDMA_mode
> 2)
269 chp
->ch_drive
[0].UDMA_mode
= 2;
270 if (chp
->ch_drive
[1].UDMA_mode
> 2)
271 chp
->ch_drive
[1].UDMA_mode
= 2;
275 for (drive
= 0; drive
< 2; drive
++) {
276 drvp
= &chp
->ch_drive
[drive
];
277 /* If no drive, skip */
278 if ((drvp
->drive_flags
& DRIVE
) == 0)
280 ATADEBUG_PRINT(("acer_setup_channel: old timings reg for "
281 "channel %d drive %d 0x%x\n", chp
->ch_channel
, drive
,
282 pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
,
283 ACER_IDETIM(chp
->ch_channel
, drive
))), DEBUG_PROBE
);
284 /* clear FIFO/DMA mode */
285 acer_fifo_udma
&= ~(ACER_FTH_OPL(chp
->ch_channel
, drive
, 0x3) |
286 ACER_UDMA_EN(chp
->ch_channel
, drive
) |
287 ACER_UDMA_TIM(chp
->ch_channel
, drive
, 0x7));
289 /* add timing values, setup DMA if needed */
290 if ((drvp
->drive_flags
& DRIVE_DMA
) == 0 &&
291 (drvp
->drive_flags
& DRIVE_UDMA
) == 0) {
293 ACER_FTH_OPL(chp
->ch_channel
, drive
, 0x1);
297 acer_fifo_udma
|= ACER_FTH_OPL(chp
->ch_channel
, drive
, 0x2);
298 if (drvp
->drive_flags
& DRIVE_UDMA
) {
301 drvp
->drive_flags
&= ~DRIVE_DMA
;
303 acer_fifo_udma
|= ACER_UDMA_EN(chp
->ch_channel
, drive
);
305 ACER_UDMA_TIM(chp
->ch_channel
, drive
,
306 acer_udma
[drvp
->UDMA_mode
]);
307 /* XXX disable if one drive < UDMA3 ? */
308 if (drvp
->UDMA_mode
>= 3) {
309 pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
,
311 pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
,
312 ACER_0x4B
) | ACER_0x4B_UDMA66
);
317 * Timings will be used for both PIO and DMA,
318 * so adjust DMA mode if needed
320 if (drvp
->PIO_mode
> (drvp
->DMA_mode
+ 2))
321 drvp
->PIO_mode
= drvp
->DMA_mode
+ 2;
322 if (drvp
->DMA_mode
+ 2 > (drvp
->PIO_mode
))
323 drvp
->DMA_mode
= (drvp
->PIO_mode
> 2) ?
324 drvp
->PIO_mode
- 2 : 0;
325 if (drvp
->DMA_mode
== 0)
328 idedma_ctl
|= IDEDMA_CTL_DRV_DMA(drive
);
329 pio
: pciide_pci_write(sc
->sc_pc
, sc
->sc_tag
,
330 ACER_IDETIM(chp
->ch_channel
, drive
),
331 acer_pio
[drvp
->PIO_mode
]);
333 ATADEBUG_PRINT(("acer_setup_channel: new fifo/udma reg 0x%x\n",
334 acer_fifo_udma
), DEBUG_PROBE
);
335 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, ACER_FTH_UDMA
, acer_fifo_udma
);
336 if (idedma_ctl
!= 0) {
337 /* Add software bits in status register */
338 bus_space_write_1(sc
->sc_dma_iot
, cp
->dma_iohs
[IDEDMA_CTL
], 0,
344 acer_pci_intr(void *arg
)
346 struct pciide_softc
*sc
= arg
;
347 struct pciide_channel
*cp
;
348 struct ata_channel
*wdc_cp
;
353 chids
= pciide_pci_read(sc
->sc_pc
, sc
->sc_tag
, ACER_CHIDS
);
354 for (i
= 0; i
< sc
->sc_wdcdev
.sc_atac
.atac_nchannels
; i
++) {
355 cp
= &sc
->pciide_channels
[i
];
356 wdc_cp
= &cp
->ata_channel
;
357 /* If a compat channel skip. */
360 if (chids
& ACER_CHIDS_INT(i
)) {
361 crv
= wdcintr(wdc_cp
);
363 aprint_error("%s:%d: bogus intr\n",
365 sc
->sc_wdcdev
.sc_atac
.atac_dev
), i
);
366 pciide_irqack(wdc_cp
);