FreeBSD/Linux Kernel Cross Reference
sys/dev/pci/aceride.c
1 /* $NetBSD: aceride.c,v 1.6 2004/01/03 22:56:53 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Manuel Bouyer.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34
35 #include <dev/pci/pcivar.h>
36 #include <dev/pci/pcidevs.h>
37 #include <dev/pci/pciidereg.h>
38 #include <dev/pci/pciidevar.h>
39 #include <dev/pci/pciide_acer_reg.h>
40
41 static void acer_chip_map(struct pciide_softc*, struct pci_attach_args*);
42 static void acer_setup_channel(struct wdc_channel*);
43 static int acer_pci_intr(void *);
44
45 static int aceride_match(struct device *, struct cfdata *, void *);
46 static void aceride_attach(struct device *, struct device *, void *);
47
48 CFATTACH_DECL(aceride, sizeof(struct pciide_softc),
49 aceride_match, aceride_attach, NULL, NULL);
50
51 static const struct pciide_product_desc pciide_acer_products[] = {
52 { PCI_PRODUCT_ALI_M5229,
53 0,
54 "Acer Labs M5229 UDMA IDE Controller",
55 acer_chip_map,
56 },
57 { 0,
58 0,
59 NULL,
60 NULL
61 }
62 };
63
64 static int
65 aceride_match(struct device *parent, struct cfdata *match, void *aux)
66 {
67 struct pci_attach_args *pa = aux;
68
69 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
70 PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
71 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
72 if (pciide_lookup_product(pa->pa_id, pciide_acer_products))
73 return (2);
74 }
75 return (0);
76 }
77
78 static void
79 aceride_attach(struct device *parent, struct device *self, void *aux)
80 {
81 struct pci_attach_args *pa = aux;
82 struct pciide_softc *sc = (struct pciide_softc *)self;
83
84 pciide_common_attach(sc, pa,
85 pciide_lookup_product(pa->pa_id, pciide_acer_products));
86
87 }
88
89 static void
90 acer_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
91 {
92 struct pciide_channel *cp;
93 int channel;
94 pcireg_t cr, interface;
95 bus_size_t cmdsize, ctlsize;
96 pcireg_t rev = PCI_REVISION(pa->pa_class);
97
98 if (pciide_chipen(sc, pa) == 0)
99 return;
100
101 aprint_normal("%s: bus-master DMA support present",
102 sc->sc_wdcdev.sc_dev.dv_xname);
103 pciide_mapreg_dma(sc, pa);
104 aprint_normal("\n");
105 sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
106 WDC_CAPABILITY_MODE;
107 if (sc->sc_dma_ok) {
108 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA;
109 if (rev >= 0x20) {
110 sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
111 if (rev >= 0xC4)
112 sc->sc_wdcdev.UDMA_cap = 5;
113 else if (rev >= 0xC2)
114 sc->sc_wdcdev.UDMA_cap = 4;
115 else
116 sc->sc_wdcdev.UDMA_cap = 2;
117 }
118 sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
119 sc->sc_wdcdev.irqack = pciide_irqack;
120 }
121
122 sc->sc_wdcdev.PIO_cap = 4;
123 sc->sc_wdcdev.DMA_cap = 2;
124 sc->sc_wdcdev.set_modes = acer_setup_channel;
125 sc->sc_wdcdev.channels = sc->wdc_chanarray;
126 sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
127
128 pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CDRC,
129 (pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CDRC) |
130 ACER_CDRC_DMA_EN) & ~ACER_CDRC_FIFO_DISABLE);
131
132 /* Enable "microsoft register bits" R/W. */
133 pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR3,
134 pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR3) | ACER_CCAR3_PI);
135 pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR1,
136 pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR1) &
137 ~(ACER_CHANSTATUS_RO|PCIIDE_CHAN_RO(0)|PCIIDE_CHAN_RO(1)));
138 pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR2,
139 pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR2) &
140 ~ACER_CHANSTATUSREGS_RO);
141 cr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG);
142 cr |= (PCIIDE_CHANSTATUS_EN << PCI_INTERFACE_SHIFT);
143 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr);
144 /* Don't use cr, re-read the real register content instead */
145 interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag,
146 PCI_CLASS_REG));
147
148 /* From linux: enable "Cable Detection" */
149 if (rev >= 0xC2) {
150 pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_0x4B,
151 pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_0x4B)
152 | ACER_0x4B_CDETECT);
153 }
154
155 for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
156 cp = &sc->pciide_channels[channel];
157 if (pciide_chansetup(sc, channel, interface) == 0)
158 continue;
159 if ((interface & PCIIDE_CHAN_EN(channel)) == 0) {
160 aprint_normal("%s: %s channel ignored (disabled)\n",
161 sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
162 cp->wdc_channel.ch_flags |= WDCF_DISABLED;
163 continue;
164 }
165 /* newer controllers seems to lack the ACER_CHIDS. Sigh */
166 pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
167 (rev >= 0xC2) ? pciide_pci_intr : acer_pci_intr);
168 }
169 }
170
171 static void
172 acer_setup_channel(struct wdc_channel *chp)
173 {
174 struct ata_drive_datas *drvp;
175 int drive;
176 u_int32_t acer_fifo_udma;
177 u_int32_t idedma_ctl;
178 struct pciide_channel *cp = (struct pciide_channel*)chp;
179 struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.ch_wdc;
180
181 idedma_ctl = 0;
182 acer_fifo_udma = pci_conf_read(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA);
183 WDCDEBUG_PRINT(("acer_setup_channel: old fifo/udma reg 0x%x\n",
184 acer_fifo_udma), DEBUG_PROBE);
185 /* setup DMA if needed */
186 pciide_channel_dma_setup(cp);
187
188 if ((chp->ch_drive[0].drive_flags | chp->ch_drive[1].drive_flags) &
189 DRIVE_UDMA) { /* check 80 pins cable */
190 if (pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_0x4A) &
191 ACER_0x4A_80PIN(chp->ch_channel)) {
192 if (chp->ch_drive[0].UDMA_mode > 2)
193 chp->ch_drive[0].UDMA_mode = 2;
194 if (chp->ch_drive[1].UDMA_mode > 2)
195 chp->ch_drive[1].UDMA_mode = 2;
196 }
197 }
198
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)
203 continue;
204 WDCDEBUG_PRINT(("acer_setup_channel: old timings reg for "
205 "channel %d drive %d 0x%x\n", chp->ch_channel, drive,
206 pciide_pci_read(sc->sc_pc, sc->sc_tag,
207 ACER_IDETIM(chp->ch_channel, drive))), DEBUG_PROBE);
208 /* clear FIFO/DMA mode */
209 acer_fifo_udma &= ~(ACER_FTH_OPL(chp->ch_channel, drive, 0x3) |
210 ACER_UDMA_EN(chp->ch_channel, drive) |
211 ACER_UDMA_TIM(chp->ch_channel, drive, 0x7));
212
213 /* add timing values, setup DMA if needed */
214 if ((drvp->drive_flags & DRIVE_DMA) == 0 &&
215 (drvp->drive_flags & DRIVE_UDMA) == 0) {
216 acer_fifo_udma |=
217 ACER_FTH_OPL(chp->ch_channel, drive, 0x1);
218 goto pio;
219 }
220
221 acer_fifo_udma |= ACER_FTH_OPL(chp->ch_channel, drive, 0x2);
222 if (drvp->drive_flags & DRIVE_UDMA) {
223 /* use Ultra/DMA */
224 drvp->drive_flags &= ~DRIVE_DMA;
225 acer_fifo_udma |= ACER_UDMA_EN(chp->ch_channel, drive);
226 acer_fifo_udma |=
227 ACER_UDMA_TIM(chp->ch_channel, drive,
228 acer_udma[drvp->UDMA_mode]);
229 /* XXX disable if one drive < UDMA3 ? */
230 if (drvp->UDMA_mode >= 3) {
231 pciide_pci_write(sc->sc_pc, sc->sc_tag,
232 ACER_0x4B,
233 pciide_pci_read(sc->sc_pc, sc->sc_tag,
234 ACER_0x4B) | ACER_0x4B_UDMA66);
235 }
236 } else {
237 /*
238 * use Multiword DMA
239 * Timings will be used for both PIO and DMA,
240 * so adjust DMA mode if needed
241 */
242 if (drvp->PIO_mode > (drvp->DMA_mode + 2))
243 drvp->PIO_mode = drvp->DMA_mode + 2;
244 if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
245 drvp->DMA_mode = (drvp->PIO_mode > 2) ?
246 drvp->PIO_mode - 2 : 0;
247 if (drvp->DMA_mode == 0)
248 drvp->PIO_mode = 0;
249 }
250 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
251 pio: pciide_pci_write(sc->sc_pc, sc->sc_tag,
252 ACER_IDETIM(chp->ch_channel, drive),
253 acer_pio[drvp->PIO_mode]);
254 }
255 WDCDEBUG_PRINT(("acer_setup_channel: new fifo/udma reg 0x%x\n",
256 acer_fifo_udma), DEBUG_PROBE);
257 pci_conf_write(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA, acer_fifo_udma);
258 if (idedma_ctl != 0) {
259 /* Add software bits in status register */
260 bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0,
261 idedma_ctl);
262 }
263 }
264
265 static int
266 acer_pci_intr(void *arg)
267 {
268 struct pciide_softc *sc = arg;
269 struct pciide_channel *cp;
270 struct wdc_channel *wdc_cp;
271 int i, rv, crv;
272 u_int32_t chids;
273
274 rv = 0;
275 chids = pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CHIDS);
276 for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
277 cp = &sc->pciide_channels[i];
278 wdc_cp = &cp->wdc_channel;
279 /* If a compat channel skip. */
280 if (cp->compat)
281 continue;
282 if (chids & ACER_CHIDS_INT(i)) {
283 crv = wdcintr(wdc_cp);
284 if (crv == 0)
285 printf("%s:%d: bogus intr\n",
286 sc->sc_wdcdev.sc_dev.dv_xname, i);
287 else
288 rv = 1;
289 }
290 }
291 return rv;
292 }
Cache object: edfe7f17db786032d013ed6911460ebe
|