1 /* $NetBSD: slide.c,v 1.19 2008/03/18 20:46:37 cube Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
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: slide.c,v 1.19 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_sl82c105_reg.h>
44 static void sl82c105_chip_map(struct pciide_softc
*, struct pci_attach_args
*);
45 static void sl82c105_setup_channel(struct ata_channel
*);
47 static int slide_match(device_t
, cfdata_t
, void *);
48 static void slide_attach(device_t
, device_t
, void *);
50 CFATTACH_DECL_NEW(slide
, sizeof(struct pciide_softc
),
51 slide_match
, slide_attach
, NULL
, NULL
);
53 static const struct pciide_product_desc pciide_symphony_products
[] = {
54 { PCI_PRODUCT_SYMPHONY_82C105
,
56 "Symphony Labs 82C105 IDE controller",
66 static const struct pciide_product_desc pciide_winbond_products
[] = {
67 { PCI_PRODUCT_WINBOND_W83C553F_1
,
69 "Winbond W83C553F IDE controller",
80 slide_match(device_t parent
, cfdata_t match
, void *aux
)
82 struct pci_attach_args
*pa
= aux
;
84 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_SYMPHONY
) {
85 if (pciide_lookup_product(pa
->pa_id
, pciide_symphony_products
))
88 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_WINBOND
) {
89 if (pciide_lookup_product(pa
->pa_id
, pciide_winbond_products
))
96 slide_attach(device_t parent
, device_t self
, void *aux
)
98 struct pci_attach_args
*pa
= aux
;
99 struct pciide_softc
*sc
= device_private(self
);
100 const struct pciide_product_desc
*pp
= NULL
;
102 sc
->sc_wdcdev
.sc_atac
.atac_dev
= self
;
104 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_SYMPHONY
)
105 pp
= pciide_lookup_product(pa
->pa_id
, pciide_symphony_products
);
106 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_WINBOND
)
107 pp
= pciide_lookup_product(pa
->pa_id
, pciide_winbond_products
);
109 panic("slide_attach");
110 pciide_common_attach(sc
, pa
, pp
);
114 sl82c105_bugchk(struct pci_attach_args
*pa
)
117 if (PCI_VENDOR(pa
->pa_id
) != PCI_VENDOR_WINBOND
||
118 PCI_PRODUCT(pa
->pa_id
) != PCI_PRODUCT_WINBOND_W83C553F_0
)
121 if (PCI_REVISION(pa
->pa_class
) <= 0x05)
128 sl82c105_chip_map(struct pciide_softc
*sc
, struct pci_attach_args
*pa
)
130 struct pciide_channel
*cp
;
131 bus_size_t cmdsize
, ctlsize
;
132 pcireg_t interface
, idecr
;
135 if (pciide_chipen(sc
, pa
) == 0)
138 aprint_verbose_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
139 "bus-master DMA support present");
142 * Check to see if we're part of the Winbond 83c553 Southbridge.
143 * If so, we need to disable DMA on rev. <= 5 of that chip.
145 if (pci_find_device(pa
, sl82c105_bugchk
)) {
146 aprint_verbose(" but disabled due to 83c553 rev. <= 0x05");
149 pciide_mapreg_dma(sc
, pa
);
150 aprint_verbose("\n");
152 sc
->sc_wdcdev
.sc_atac
.atac_cap
= ATAC_CAP_DATA32
| ATAC_CAP_DATA16
;
153 sc
->sc_wdcdev
.sc_atac
.atac_pio_cap
= 4;
155 sc
->sc_wdcdev
.sc_atac
.atac_cap
|= ATAC_CAP_DMA
;
156 sc
->sc_wdcdev
.irqack
= pciide_irqack
;
157 sc
->sc_wdcdev
.sc_atac
.atac_dma_cap
= 2;
159 sc
->sc_wdcdev
.sc_atac
.atac_set_modes
= sl82c105_setup_channel
;
161 sc
->sc_wdcdev
.sc_atac
.atac_channels
= sc
->wdc_chanarray
;
162 sc
->sc_wdcdev
.sc_atac
.atac_nchannels
= PCIIDE_NUM_CHANNELS
;
164 idecr
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, SYMPH_IDECSR
);
166 interface
= PCI_INTERFACE(pa
->pa_class
);
168 wdc_allocate_regs(&sc
->sc_wdcdev
);
170 for (channel
= 0; channel
< sc
->sc_wdcdev
.sc_atac
.atac_nchannels
;
172 cp
= &sc
->pciide_channels
[channel
];
173 if (pciide_chansetup(sc
, channel
, interface
) == 0)
175 if ((channel
== 0 && (idecr
& IDECR_P0EN
) == 0) ||
176 (channel
== 1 && (idecr
& IDECR_P1EN
) == 0)) {
177 aprint_normal_dev(sc
->sc_wdcdev
.sc_atac
.atac_dev
,
178 "%s channel ignored (disabled)\n", cp
->name
);
179 cp
->ata_channel
.ch_flags
|= ATACH_DISABLED
;
182 pciide_mapchan(pa
, cp
, interface
, &cmdsize
, &ctlsize
,
188 sl82c105_setup_channel(struct ata_channel
*chp
)
190 struct ata_drive_datas
*drvp
;
191 struct pciide_channel
*cp
= CHAN_TO_PCHAN(chp
);
192 struct pciide_softc
*sc
= CHAN_TO_PCIIDE(chp
);
193 int pxdx_reg
, drive
, s
;
196 /* Set up DMA if needed. */
197 pciide_channel_dma_setup(cp
);
199 for (drive
= 0; drive
< 2; drive
++) {
200 pxdx_reg
= ((chp
->ch_channel
== 0) ? SYMPH_P0D0CR
204 pxdx
= pci_conf_read(sc
->sc_pc
, sc
->sc_tag
, pxdx_reg
);
206 pxdx
&= ~(PxDx_CMD_ON_MASK
|PxDx_CMD_OFF_MASK
);
207 pxdx
&= ~(PxDx_PWEN
|PxDx_RDYEN
|PxDx_RAEN
);
209 drvp
= &chp
->ch_drive
[drive
];
210 /* If no drive, skip. */
211 if ((drvp
->drive_flags
& DRIVE
) == 0) {
212 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, pxdx_reg
, pxdx
);
216 if (drvp
->drive_flags
& DRIVE_DMA
) {
218 * Timings will be used for both PIO and DMA,
219 * so adjust DMA mode if needed.
221 if (drvp
->PIO_mode
>= 3) {
222 if ((drvp
->DMA_mode
+ 2) > drvp
->PIO_mode
)
223 drvp
->DMA_mode
= drvp
->PIO_mode
- 2;
224 if (drvp
->DMA_mode
< 1) {
226 * Can't mix both PIO and DMA.
230 drvp
->drive_flags
&= ~DRIVE_DMA
;
235 * Can't mix both PIO and DMA. Disable
239 drvp
->drive_flags
&= ~DRIVE_DMA
;
244 if (drvp
->drive_flags
& DRIVE_DMA
) {
245 /* Use multi-word DMA. */
246 pxdx
|= symph_mw_dma_times
[drvp
->DMA_mode
].cmd_on
<<
248 pxdx
|= symph_mw_dma_times
[drvp
->DMA_mode
].cmd_off
;
250 pxdx
|= symph_pio_times
[drvp
->PIO_mode
].cmd_on
<<
252 pxdx
|= symph_pio_times
[drvp
->PIO_mode
].cmd_off
;
255 /* XXX PxDx_PWEN? PxDx_RDYEN? PxDx_RAEN? */
257 /* ...and set the mode for this drive. */
258 pci_conf_write(sc
->sc_pc
, sc
->sc_tag
, pxdx_reg
, pxdx
);