1 | /* $NetBSD: acardide.c,v 1.31 2013/10/07 19:51:55 jakllsch Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2001 Izumi Tsutsui. All rights reserved. |
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 | * |
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. |
25 | */ |
26 | |
27 | #include <sys/cdefs.h> |
28 | __KERNEL_RCSID(0, "$NetBSD: acardide.c,v 1.31 2013/10/07 19:51:55 jakllsch Exp $" ); |
29 | |
30 | #include <sys/param.h> |
31 | #include <sys/systm.h> |
32 | |
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_acard_reg.h> |
38 | |
39 | static void acard_chip_map(struct pciide_softc*, const struct pci_attach_args*); |
40 | static void acard_setup_channel(struct ata_channel*); |
41 | #if 0 /* XXX !! */ |
42 | static int acard_pci_intr(void *); |
43 | #endif |
44 | |
45 | static int acardide_match(device_t, cfdata_t, void *); |
46 | static void acardide_attach(device_t, device_t, void *); |
47 | |
48 | CFATTACH_DECL_NEW(acardide, sizeof(struct pciide_softc), |
49 | acardide_match, acardide_attach, pciide_detach, NULL); |
50 | |
51 | static const struct pciide_product_desc pciide_acard_products[] = { |
52 | { PCI_PRODUCT_ACARD_ATP850U, |
53 | 0, |
54 | "Acard ATP850U Ultra33 IDE Controller" , |
55 | acard_chip_map, |
56 | }, |
57 | { PCI_PRODUCT_ACARD_ATP860, |
58 | 0, |
59 | "Acard ATP860 Ultra66 IDE Controller" , |
60 | acard_chip_map, |
61 | }, |
62 | { PCI_PRODUCT_ACARD_ATP860A, |
63 | 0, |
64 | "Acard ATP860-A Ultra66 IDE Controller" , |
65 | acard_chip_map, |
66 | }, |
67 | { PCI_PRODUCT_ACARD_ATP865, |
68 | 0, |
69 | "Acard ATP865 Ultra133 IDE Controller" , |
70 | acard_chip_map, |
71 | }, |
72 | { PCI_PRODUCT_ACARD_ATP865A, |
73 | 0, |
74 | "Acard ATP865-A Ultra133 IDE Controller" , |
75 | acard_chip_map, |
76 | }, |
77 | { 0, |
78 | 0, |
79 | NULL, |
80 | NULL |
81 | } |
82 | }; |
83 | |
84 | static int |
85 | acardide_match(device_t parent, cfdata_t match, void *aux) |
86 | { |
87 | struct pci_attach_args *pa = aux; |
88 | |
89 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ACARD) { |
90 | if (pciide_lookup_product(pa->pa_id, pciide_acard_products)) |
91 | return (2); |
92 | } |
93 | return (0); |
94 | } |
95 | |
96 | static void |
97 | acardide_attach(device_t parent, device_t self, void *aux) |
98 | { |
99 | struct pci_attach_args *pa = aux; |
100 | struct pciide_softc *sc = device_private(self); |
101 | |
102 | sc->sc_wdcdev.sc_atac.atac_dev = self; |
103 | |
104 | pciide_common_attach(sc, pa, |
105 | pciide_lookup_product(pa->pa_id, pciide_acard_products)); |
106 | |
107 | } |
108 | |
109 | #define ACARD_IS_850(sc) \ |
110 | ((sc)->sc_pp->ide_product == PCI_PRODUCT_ACARD_ATP850U) |
111 | |
112 | static void |
113 | acard_chip_map(struct pciide_softc *sc, const struct pci_attach_args *pa) |
114 | { |
115 | struct pciide_channel *cp; |
116 | int i; |
117 | pcireg_t interface; |
118 | |
119 | if (pciide_chipen(sc, pa) == 0) |
120 | return; |
121 | |
122 | /* |
123 | * when the chip is in native mode it identifies itself as a |
124 | * 'misc mass storage'. Fake interface in this case. |
125 | */ |
126 | if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) { |
127 | interface = PCI_INTERFACE(pa->pa_class); |
128 | } else { |
129 | interface = PCIIDE_INTERFACE_BUS_MASTER_DMA | |
130 | PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1); |
131 | } |
132 | |
133 | aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev, |
134 | "bus-master DMA support present" ); |
135 | pciide_mapreg_dma(sc, pa); |
136 | aprint_verbose("\n" ); |
137 | sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16 | ATAC_CAP_DATA32; |
138 | |
139 | if (sc->sc_dma_ok) { |
140 | sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA | ATAC_CAP_UDMA; |
141 | sc->sc_wdcdev.irqack = pciide_irqack; |
142 | } |
143 | sc->sc_wdcdev.sc_atac.atac_pio_cap = 4; |
144 | sc->sc_wdcdev.sc_atac.atac_dma_cap = 2; |
145 | switch (sc->sc_pp->ide_product) { |
146 | case PCI_PRODUCT_ACARD_ATP860: |
147 | case PCI_PRODUCT_ACARD_ATP860A: |
148 | sc->sc_wdcdev.sc_atac.atac_udma_cap = 4; |
149 | break; |
150 | case PCI_PRODUCT_ACARD_ATP865: |
151 | case PCI_PRODUCT_ACARD_ATP865A: |
152 | sc->sc_wdcdev.sc_atac.atac_udma_cap = 6; |
153 | break; |
154 | default: |
155 | sc->sc_wdcdev.sc_atac.atac_udma_cap = 2; |
156 | break; |
157 | } |
158 | |
159 | sc->sc_wdcdev.sc_atac.atac_set_modes = acard_setup_channel; |
160 | sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray; |
161 | sc->sc_wdcdev.sc_atac.atac_nchannels = 2; |
162 | sc->sc_wdcdev.wdc_maxdrives = 2; |
163 | |
164 | wdc_allocate_regs(&sc->sc_wdcdev); |
165 | |
166 | for (i = 0; i < sc->sc_wdcdev.sc_atac.atac_nchannels; i++) { |
167 | cp = &sc->pciide_channels[i]; |
168 | if (pciide_chansetup(sc, i, interface) == 0) |
169 | continue; |
170 | pciide_mapchan(pa, cp, interface, pciide_pci_intr); |
171 | } |
172 | if (!ACARD_IS_850(sc)) { |
173 | u_int32_t reg; |
174 | reg = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL); |
175 | reg &= ~ATP860_CTRL_INT; |
176 | pci_conf_write(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL, reg); |
177 | } |
178 | } |
179 | |
180 | static void |
181 | acard_setup_channel(struct ata_channel *chp) |
182 | { |
183 | struct ata_drive_datas *drvp; |
184 | struct atac_softc *atac = chp->ch_atac; |
185 | struct pciide_channel *cp = CHAN_TO_PCHAN(chp); |
186 | struct pciide_softc *sc = CHAN_TO_PCIIDE(chp); |
187 | int channel = chp->ch_channel; |
188 | int drive, s; |
189 | u_int32_t idetime, udma_mode; |
190 | u_int32_t idedma_ctl; |
191 | |
192 | /* setup DMA if needed */ |
193 | pciide_channel_dma_setup(cp); |
194 | |
195 | if (ACARD_IS_850(sc)) { |
196 | idetime = 0; |
197 | udma_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP850_UDMA); |
198 | udma_mode &= ~ATP850_UDMA_MASK(channel); |
199 | } else { |
200 | idetime = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP860_IDETIME); |
201 | idetime &= ~ATP860_SETTIME_MASK(channel); |
202 | udma_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP860_UDMA); |
203 | udma_mode &= ~ATP860_UDMA_MASK(channel); |
204 | |
205 | /* check 80 pins cable */ |
206 | if ((chp->ch_drive[0].drive_flags & ATA_DRIVE_UDMA) || |
207 | (chp->ch_drive[1].drive_flags & ATA_DRIVE_UDMA)) { |
208 | if (pci_conf_read(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL) |
209 | & ATP860_CTRL_80P(chp->ch_channel)) { |
210 | if (chp->ch_drive[0].UDMA_mode > 2) |
211 | chp->ch_drive[0].UDMA_mode = 2; |
212 | if (chp->ch_drive[1].UDMA_mode > 2) |
213 | chp->ch_drive[1].UDMA_mode = 2; |
214 | } |
215 | } |
216 | } |
217 | |
218 | idedma_ctl = 0; |
219 | |
220 | /* Per drive settings */ |
221 | for (drive = 0; drive < 2; drive++) { |
222 | drvp = &chp->ch_drive[drive]; |
223 | /* If no drive, skip */ |
224 | if (drvp->drive_type == ATA_DRIVET_NONE) |
225 | continue; |
226 | /* add timing values, setup DMA if needed */ |
227 | if ((atac->atac_cap & ATAC_CAP_UDMA) && |
228 | (drvp->drive_flags & ATA_DRIVE_UDMA)) { |
229 | /* use Ultra/DMA */ |
230 | if (ACARD_IS_850(sc)) { |
231 | idetime |= ATP850_SETTIME(drive, |
232 | acard_act_udma[drvp->UDMA_mode], |
233 | acard_rec_udma[drvp->UDMA_mode]); |
234 | udma_mode |= ATP850_UDMA_MODE(channel, drive, |
235 | acard_udma_conf[drvp->UDMA_mode]); |
236 | } else { |
237 | idetime |= ATP860_SETTIME(channel, drive, |
238 | acard_act_udma[drvp->UDMA_mode], |
239 | acard_rec_udma[drvp->UDMA_mode]); |
240 | udma_mode |= ATP860_UDMA_MODE(channel, drive, |
241 | acard_udma_conf[drvp->UDMA_mode]); |
242 | } |
243 | idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); |
244 | } else if ((atac->atac_cap & ATAC_CAP_DMA) && |
245 | (drvp->drive_flags & ATA_DRIVE_DMA)) { |
246 | /* use Multiword DMA */ |
247 | s = splbio(); |
248 | drvp->drive_flags &= ~ATA_DRIVE_UDMA; |
249 | splx(s); |
250 | if (ACARD_IS_850(sc)) { |
251 | idetime |= ATP850_SETTIME(drive, |
252 | acard_act_dma[drvp->DMA_mode], |
253 | acard_rec_dma[drvp->DMA_mode]); |
254 | } else { |
255 | idetime |= ATP860_SETTIME(channel, drive, |
256 | acard_act_dma[drvp->DMA_mode], |
257 | acard_rec_dma[drvp->DMA_mode]); |
258 | } |
259 | idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive); |
260 | } else { |
261 | /* PIO only */ |
262 | s = splbio(); |
263 | drvp->drive_flags &= ~(ATA_DRIVE_UDMA | ATA_DRIVE_DMA); |
264 | splx(s); |
265 | if (ACARD_IS_850(sc)) { |
266 | idetime |= ATP850_SETTIME(drive, |
267 | acard_act_pio[drvp->PIO_mode], |
268 | acard_rec_pio[drvp->PIO_mode]); |
269 | } else { |
270 | idetime |= ATP860_SETTIME(channel, drive, |
271 | acard_act_pio[drvp->PIO_mode], |
272 | acard_rec_pio[drvp->PIO_mode]); |
273 | } |
274 | pci_conf_write(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL, |
275 | pci_conf_read(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL) |
276 | | ATP8x0_CTRL_EN(channel)); |
277 | } |
278 | } |
279 | |
280 | if (idedma_ctl != 0) { |
281 | /* Add software bits in status register */ |
282 | bus_space_write_1(sc->sc_dma_iot, cp->dma_iohs[IDEDMA_CTL], 0, |
283 | idedma_ctl); |
284 | } |
285 | |
286 | if (ACARD_IS_850(sc)) { |
287 | pci_conf_write(sc->sc_pc, sc->sc_tag, |
288 | ATP850_IDETIME(channel), idetime); |
289 | pci_conf_write(sc->sc_pc, sc->sc_tag, ATP850_UDMA, udma_mode); |
290 | } else { |
291 | pci_conf_write(sc->sc_pc, sc->sc_tag, ATP860_IDETIME, idetime); |
292 | pci_conf_write(sc->sc_pc, sc->sc_tag, ATP860_UDMA, udma_mode); |
293 | } |
294 | } |
295 | |
296 | #if 0 /* XXX !! */ |
297 | static int |
298 | acard_pci_intr(void *arg) |
299 | { |
300 | struct pciide_softc *sc = arg; |
301 | struct pciide_channel *cp; |
302 | struct ata_channel *wdc_cp; |
303 | int rv = 0; |
304 | int dmastat, i, crv; |
305 | |
306 | for (i = 0; i < sc->sc_wdcdev.sc_atac.atac_nchannels; i++) { |
307 | cp = &sc->pciide_channels[i]; |
308 | dmastat = bus_space_read_1(sc->sc_dma_iot, |
309 | cp->dma_iohs[IDEDMA_CTL], 0); |
310 | if ((dmastat & IDEDMA_CTL_INTR) == 0) |
311 | continue; |
312 | wdc_cp = &cp->ata_channel; |
313 | if ((wdc_cp->ch_flags & ATACH_IRQ_WAIT) == 0) { |
314 | (void)wdcintr(wdc_cp); |
315 | bus_space_write_1(sc->sc_dma_iot, |
316 | cp->dma_iohs[IDEDMA_CTL], 0, dmastat); |
317 | continue; |
318 | } |
319 | crv = wdcintr(wdc_cp); |
320 | if (crv == 0) { |
321 | printf("%s:%d: bogus intr\n" , |
322 | device_xname(sc->sc_wdcdev.sc_atac.atac_dev), i); |
323 | bus_space_write_1(sc->sc_dma_iot, |
324 | cp->dma_iohs[IDEDMA_CTL], 0, dmastat); |
325 | } else if (crv == 1) |
326 | rv = 1; |
327 | else if (rv == 0) |
328 | rv = crv; |
329 | } |
330 | return rv; |
331 | } |
332 | #endif |
333 | |