1 /* $NetBSD: pciide_pnpbios.c,v 1.25 2008/03/18 20:46:36 cube Exp $ */
4 * Copyright (c) 1999 Soren S. Jorvang. All rights reserved.
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 AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * Handle the weird "almost PCI" IDE on Toshiba Porteges.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: pciide_pnpbios.c,v 1.25 2008/03/18 20:46:36 cube Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
40 #include <machine/bus.h>
42 #include <dev/ic/wdcreg.h>
43 #include <dev/isa/isavar.h>
44 #include <dev/isa/isadmavar.h>
46 #include <i386/pnpbios/pnpbiosvar.h>
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcivar.h>
50 #include <dev/pci/pcidevs.h>
52 #include <dev/pci/pciidereg.h>
53 #include <dev/pci/pciidevar.h>
55 static int pciide_pnpbios_match(device_t
, cfdata_t
, void *);
56 static void pciide_pnpbios_attach(device_t
, device_t
, void *);
58 extern void pciide_channel_dma_setup(struct pciide_channel
*);
59 extern int pciide_dma_init(void *, int, int, void *, size_t, int);
60 extern void pciide_dma_start(void *, int, int);
61 extern int pciide_dma_finish(void *, int, int, int);
62 extern int pciide_compat_intr (void *);
64 CFATTACH_DECL_NEW(pciide_pnpbios
, sizeof(struct pciide_softc
),
65 pciide_pnpbios_match
, pciide_pnpbios_attach
, NULL
, NULL
);
68 pciide_pnpbios_match(device_t parent
, cfdata_t match
, void *aux
)
70 struct pnpbiosdev_attach_args
*aa
= aux
;
72 if (strcmp(aa
->idstr
, "TOS7300") == 0)
79 pciide_pnpbios_attach(device_t parent
, device_t self
, void *aux
)
81 struct pciide_softc
*sc
= device_private(self
);
82 struct pnpbiosdev_attach_args
*aa
= aux
;
83 struct pciide_channel
*cp
;
84 struct ata_channel
*wdc_cp
;
86 bus_space_tag_t compat_iot
;
87 bus_space_handle_t cmd_baseioh
, ctl_ioh
;
91 sc
->sc_wdcdev
.sc_atac
.atac_dev
= self
;
93 aprint_naive(": disk controller\n");
95 pnpbios_print_devres(self
, aa
);
97 aprint_normal_dev(self
, "Toshiba Extended IDE Controller\n");
99 if (pnpbios_io_map(aa
->pbt
, aa
->resc
, 2, &sc
->sc_dma_iot
,
100 &sc
->sc_dma_ioh
) != 0) {
101 aprint_error_dev(self
, "unable to map DMA registers\n");
104 if (pnpbios_io_map(aa
->pbt
, aa
->resc
, 0, &compat_iot
,
105 &cmd_baseioh
) != 0) {
106 aprint_error_dev(self
, "unable to map command registers\n");
109 if (pnpbios_io_map(aa
->pbt
, aa
->resc
, 1, &compat_iot
,
111 aprint_error_dev(self
, "unable to map control register\n");
115 sc
->sc_dmat
= &pci_bus_dma_tag
;
117 cp
= &sc
->pciide_channels
[0];
118 sc
->wdc_chanarray
[0] = &cp
->ata_channel
;
119 cp
->ata_channel
.ch_channel
= 0;
120 cp
->ata_channel
.ch_atac
= &sc
->sc_wdcdev
.sc_atac
;
121 cp
->ata_channel
.ch_queue
= malloc(sizeof(struct ata_queue
),
123 cp
->ata_channel
.ch_ndrive
= 2;
124 if (cp
->ata_channel
.ch_queue
== NULL
) {
125 aprint_error_dev(self
, "unable to allocate memory for command "
131 for (i
= 0; i
< IDEDMA_NREGS
; i
++) {
133 if (size
> (IDEDMA_SCH_OFFSET
- i
))
134 size
= IDEDMA_SCH_OFFSET
- i
;
135 if (bus_space_subregion(sc
->sc_dma_iot
, sc
->sc_dma_ioh
,
136 i
, size
, &cp
->dma_iohs
[i
]) != 0) {
137 aprint_error_dev(self
, "can't subregion offset %d "
138 "size %lu", i
, (u_long
)size
);
142 sc
->sc_dma_maxsegsz
= IDEDMA_BYTE_COUNT_MAX
;
143 sc
->sc_dma_boundary
= IDEDMA_BYTE_COUNT_ALIGN
;
144 sc
->sc_wdcdev
.dma_arg
= sc
;
145 sc
->sc_wdcdev
.dma_init
= pciide_dma_init
;
146 sc
->sc_wdcdev
.dma_start
= pciide_dma_start
;
147 sc
->sc_wdcdev
.dma_finish
= pciide_dma_finish
;
148 sc
->sc_wdcdev
.irqack
= pciide_irqack
;
149 sc
->sc_wdcdev
.sc_atac
.atac_cap
|= ATAC_CAP_DMA
;
150 sc
->sc_wdcdev
.sc_atac
.atac_channels
= sc
->wdc_chanarray
;
151 sc
->sc_wdcdev
.sc_atac
.atac_nchannels
= 1;
152 sc
->sc_wdcdev
.sc_atac
.atac_cap
|= ATAC_CAP_DATA16
| ATAC_CAP_DATA32
;
153 sc
->sc_wdcdev
.sc_atac
.atac_pio_cap
= 0;
154 sc
->sc_wdcdev
.sc_atac
.atac_dma_cap
= 0; /* XXX */
155 sc
->sc_wdcdev
.sc_atac
.atac_udma_cap
= 0; /* XXX */
157 wdc_allocate_regs(&sc
->sc_wdcdev
);
159 wdc_cp
= &cp
->ata_channel
;
160 wdr
= CHAN_TO_WDC_REGS(wdc_cp
);
161 wdr
->cmd_iot
= compat_iot
;
162 wdr
->cmd_baseioh
= cmd_baseioh
;
164 for (i
= 0; i
< WDC_NREG
; i
++) {
165 if (bus_space_subregion(wdr
->cmd_iot
, wdr
->cmd_baseioh
, i
,
166 i
== 0 ? 4 : 1, &wdr
->cmd_iohs
[i
]) != 0) {
167 aprint_error_dev(self
, "unable to subregion "
168 "control register\n");
172 wdc_init_shadow_regs(wdc_cp
);
174 wdr
->ctl_iot
= wdr
->data32iot
= compat_iot
;
175 wdr
->ctl_ioh
= wdr
->data32ioh
= ctl_ioh
;
179 cp
->ih
= pnpbios_intr_establish(aa
->pbt
, aa
->resc
, 0, IPL_BIO
,
180 pciide_compat_intr
, cp
);
185 for (drive
= 0; drive
< cp
->ata_channel
.ch_ndrive
; drive
++) {
187 * we have not probed the drives yet,
188 * allocate ressources for all of them.
190 if (pciide_dma_table_setup(sc
, 0, drive
) != 0) {
191 /* Abort DMA setup */
193 "%s:%d:%d: can't allocate DMA maps, "
194 "using PIO transfers\n",
195 device_xname(self
), 0, drive
);
197 sc
->sc_wdcdev
.sc_atac
.atac_cap
&= ~ATAC_CAP_DMA
;
198 sc
->sc_wdcdev
.irqack
= NULL
;
202 idedma_ctl
|= IDEDMA_CTL_DRV_DMA(drive
);
204 if (idedma_ctl
!= 0) {
205 /* Add software bits in status register */
206 bus_space_write_1(sc
->sc_dma_iot
,
207 cp
->dma_iohs
[IDEDMA_CTL
], 0, idedma_ctl
);