siside.c revision 1.1 1 /* $NetBSD: siside.c,v 1.1 2003/10/08 11:51:59 bouyer Exp $ */
2
3
4 /*
5 * Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Manuel Bouyer.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37
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_sis_reg.h>
43
44 void sis_chip_map __P((struct pciide_softc*, struct pci_attach_args*));
45 void sis_setup_channel __P((struct channel_softc*));
46 void sis96x_setup_channel __P((struct channel_softc*));
47 static int sis_hostbr_match __P(( struct pci_attach_args *));
48 static int sis_south_match __P(( struct pci_attach_args *));
49
50 int siside_match __P((struct device *, struct cfdata *, void *));
51 void siside_attach __P((struct device *, struct device *, void *));
52
53 CFATTACH_DECL(siside, sizeof(struct pciide_softc),
54 siside_match, siside_attach, NULL, NULL);
55
56 const struct pciide_product_desc pciide_sis_products[] = {
57 { PCI_PRODUCT_SIS_5597_IDE,
58 0,
59 NULL,
60 sis_chip_map,
61 },
62 { 0,
63 0,
64 NULL,
65 NULL
66 }
67 };
68
69 int
70 siside_match(parent, match, aux)
71 struct device *parent;
72 struct cfdata *match;
73 void *aux;
74 {
75 struct pci_attach_args *pa = aux;
76
77 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS) {
78 if (pciide_lookup_product(pa->pa_id, pciide_sis_products))
79 return (2);
80 }
81 return (0);
82 }
83
84 void
85 siside_attach(parent, self, aux)
86 struct device *parent, *self;
87 void *aux;
88 {
89 struct pci_attach_args *pa = aux;
90 struct pciide_softc *sc = (struct pciide_softc *)self;
91
92 pciide_common_attach(sc, pa,
93 pciide_lookup_product(pa->pa_id, pciide_sis_products));
94
95 }
96
97 static struct sis_hostbr_type {
98 u_int16_t id;
99 u_int8_t rev;
100 u_int8_t udma_mode;
101 char *name;
102 u_int8_t type;
103 #define SIS_TYPE_NOUDMA 0
104 #define SIS_TYPE_66 1
105 #define SIS_TYPE_100OLD 2
106 #define SIS_TYPE_100NEW 3
107 #define SIS_TYPE_133OLD 4
108 #define SIS_TYPE_133NEW 5
109 #define SIS_TYPE_SOUTH 6
110 } sis_hostbr_type[] = {
111 /* Most infos here are from sos (at) freebsd.org */
112 {PCI_PRODUCT_SIS_530HB, 0x00, 4, "530", SIS_TYPE_66},
113 #if 0
114 /*
115 * controllers associated to a rev 0x2 530 Host to PCI Bridge
116 * have problems with UDMA (info provided by Christos)
117 */
118 {PCI_PRODUCT_SIS_530HB, 0x02, 0, "530 (buggy)", SIS_TYPE_NOUDMA},
119 #endif
120 {PCI_PRODUCT_SIS_540HB, 0x00, 4, "540", SIS_TYPE_66},
121 {PCI_PRODUCT_SIS_550HB, 0x00, 4, "550", SIS_TYPE_66},
122 {PCI_PRODUCT_SIS_620, 0x00, 4, "620", SIS_TYPE_66},
123 {PCI_PRODUCT_SIS_630, 0x00, 4, "630", SIS_TYPE_66},
124 {PCI_PRODUCT_SIS_630, 0x30, 5, "630S", SIS_TYPE_100NEW},
125 {PCI_PRODUCT_SIS_633, 0x00, 5, "633", SIS_TYPE_100NEW},
126 {PCI_PRODUCT_SIS_635, 0x00, 5, "635", SIS_TYPE_100NEW},
127 {PCI_PRODUCT_SIS_640, 0x00, 4, "640", SIS_TYPE_SOUTH},
128 {PCI_PRODUCT_SIS_645, 0x00, 6, "645", SIS_TYPE_SOUTH},
129 {PCI_PRODUCT_SIS_646, 0x00, 6, "645DX", SIS_TYPE_SOUTH},
130 {PCI_PRODUCT_SIS_648, 0x00, 6, "648", SIS_TYPE_SOUTH},
131 {PCI_PRODUCT_SIS_650, 0x00, 6, "650", SIS_TYPE_SOUTH},
132 {PCI_PRODUCT_SIS_651, 0x00, 6, "651", SIS_TYPE_SOUTH},
133 {PCI_PRODUCT_SIS_652, 0x00, 6, "652", SIS_TYPE_SOUTH},
134 {PCI_PRODUCT_SIS_655, 0x00, 6, "655", SIS_TYPE_SOUTH},
135 {PCI_PRODUCT_SIS_658, 0x00, 6, "658", SIS_TYPE_SOUTH},
136 {PCI_PRODUCT_SIS_730, 0x00, 5, "730", SIS_TYPE_100OLD},
137 {PCI_PRODUCT_SIS_733, 0x00, 5, "733", SIS_TYPE_100NEW},
138 {PCI_PRODUCT_SIS_735, 0x00, 5, "735", SIS_TYPE_100NEW},
139 {PCI_PRODUCT_SIS_740, 0x00, 5, "740", SIS_TYPE_SOUTH},
140 {PCI_PRODUCT_SIS_745, 0x00, 5, "745", SIS_TYPE_100NEW},
141 {PCI_PRODUCT_SIS_746, 0x00, 6, "746", SIS_TYPE_SOUTH},
142 {PCI_PRODUCT_SIS_748, 0x00, 6, "748", SIS_TYPE_SOUTH},
143 {PCI_PRODUCT_SIS_750, 0x00, 6, "750", SIS_TYPE_SOUTH},
144 {PCI_PRODUCT_SIS_751, 0x00, 6, "751", SIS_TYPE_SOUTH},
145 {PCI_PRODUCT_SIS_752, 0x00, 6, "752", SIS_TYPE_SOUTH},
146 {PCI_PRODUCT_SIS_755, 0x00, 6, "755", SIS_TYPE_SOUTH},
147 /*
148 * From sos (at) freebsd.org: the 0x961 ID will never be found in real world
149 * {PCI_PRODUCT_SIS_961, 0x00, 6, "961", SIS_TYPE_133NEW},
150 */
151 {PCI_PRODUCT_SIS_962, 0x00, 6, "962", SIS_TYPE_133NEW},
152 {PCI_PRODUCT_SIS_963, 0x00, 6, "963", SIS_TYPE_133NEW},
153 };
154
155 static struct sis_hostbr_type *sis_hostbr_type_match;
156
157 static int
158 sis_hostbr_match(pa)
159 struct pci_attach_args *pa;
160 {
161 int i;
162 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SIS)
163 return 0;
164 sis_hostbr_type_match = NULL;
165 for (i = 0;
166 i < sizeof(sis_hostbr_type) / sizeof(sis_hostbr_type[0]);
167 i++) {
168 if (PCI_PRODUCT(pa->pa_id) == sis_hostbr_type[i].id &&
169 PCI_REVISION(pa->pa_class) >= sis_hostbr_type[i].rev)
170 sis_hostbr_type_match = &sis_hostbr_type[i];
171 }
172 return (sis_hostbr_type_match != NULL);
173 }
174
175 static int sis_south_match(pa)
176 struct pci_attach_args *pa;
177 {
178 return(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS &&
179 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SIS_85C503 &&
180 PCI_REVISION(pa->pa_class) >= 0x10);
181 }
182
183 void
184 sis_chip_map(sc, pa)
185 struct pciide_softc *sc;
186 struct pci_attach_args *pa;
187 {
188 struct pciide_channel *cp;
189 int channel;
190 u_int8_t sis_ctr0 = pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_CTRL0);
191 pcireg_t interface = PCI_INTERFACE(pa->pa_class);
192 pcireg_t rev = PCI_REVISION(pa->pa_class);
193 bus_size_t cmdsize, ctlsize;
194
195 if (pciide_chipen(sc, pa) == 0)
196 return;
197
198 aprint_normal("%s: Silicon Integrated System ",
199 sc->sc_wdcdev.sc_dev.dv_xname);
200 pci_find_device(NULL, sis_hostbr_match);
201 if (sis_hostbr_type_match) {
202 if (sis_hostbr_type_match->type == SIS_TYPE_SOUTH) {
203 pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_57,
204 pciide_pci_read(sc->sc_pc, sc->sc_tag,
205 SIS_REG_57) & 0x7f);
206 if (PCI_PRODUCT(pci_conf_read(sc->sc_pc, sc->sc_tag,
207 PCI_ID_REG)) == SIS_PRODUCT_5518) {
208 aprint_normal("96X UDMA%d",
209 sis_hostbr_type_match->udma_mode);
210 sc->sis_type = SIS_TYPE_133NEW;
211 sc->sc_wdcdev.UDMA_cap =
212 sis_hostbr_type_match->udma_mode;
213 } else {
214 if (pci_find_device(NULL, sis_south_match)) {
215 sc->sis_type = SIS_TYPE_133OLD;
216 sc->sc_wdcdev.UDMA_cap =
217 sis_hostbr_type_match->udma_mode;
218 } else {
219 sc->sis_type = SIS_TYPE_100NEW;
220 sc->sc_wdcdev.UDMA_cap =
221 sis_hostbr_type_match->udma_mode;
222 }
223 }
224 } else {
225 sc->sis_type = sis_hostbr_type_match->type;
226 sc->sc_wdcdev.UDMA_cap =
227 sis_hostbr_type_match->udma_mode;
228 }
229 aprint_normal(sis_hostbr_type_match->name);
230 } else {
231 aprint_normal("5597/5598");
232 if (rev >= 0xd0) {
233 sc->sc_wdcdev.UDMA_cap = 2;
234 sc->sis_type = SIS_TYPE_66;
235 } else {
236 sc->sc_wdcdev.UDMA_cap = 0;
237 sc->sis_type = SIS_TYPE_NOUDMA;
238 }
239 }
240 aprint_normal(" IDE controller (rev. 0x%02x)\n",
241 PCI_REVISION(pa->pa_class));
242 aprint_normal("%s: bus-master DMA support present",
243 sc->sc_wdcdev.sc_dev.dv_xname);
244 pciide_mapreg_dma(sc, pa);
245 aprint_normal("\n");
246
247 sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
248 WDC_CAPABILITY_MODE;
249 if (sc->sc_dma_ok) {
250 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
251 sc->sc_wdcdev.irqack = pciide_irqack;
252 if (sc->sis_type >= SIS_TYPE_66)
253 sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
254 }
255
256 sc->sc_wdcdev.PIO_cap = 4;
257 sc->sc_wdcdev.DMA_cap = 2;
258
259 sc->sc_wdcdev.channels = sc->wdc_chanarray;
260 sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
261 switch(sc->sis_type) {
262 case SIS_TYPE_NOUDMA:
263 case SIS_TYPE_66:
264 case SIS_TYPE_100OLD:
265 sc->sc_wdcdev.set_modes = sis_setup_channel;
266 pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_MISC,
267 pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_MISC) |
268 SIS_MISC_TIM_SEL | SIS_MISC_FIFO_SIZE | SIS_MISC_GTC);
269 break;
270 case SIS_TYPE_100NEW:
271 case SIS_TYPE_133OLD:
272 sc->sc_wdcdev.set_modes = sis_setup_channel;
273 pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_49,
274 pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_49) | 0x01);
275 break;
276 case SIS_TYPE_133NEW:
277 sc->sc_wdcdev.set_modes = sis96x_setup_channel;
278 pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_50,
279 pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_50) & 0xf7);
280 pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_52,
281 pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_52) & 0xf7);
282 break;
283 }
284
285
286 for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
287 cp = &sc->pciide_channels[channel];
288 if (pciide_chansetup(sc, channel, interface) == 0)
289 continue;
290 if ((channel == 0 && (sis_ctr0 & SIS_CTRL0_CHAN0_EN) == 0) ||
291 (channel == 1 && (sis_ctr0 & SIS_CTRL0_CHAN1_EN) == 0)) {
292 aprint_normal("%s: %s channel ignored (disabled)\n",
293 sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
294 cp->wdc_channel.ch_flags |= WDCF_DISABLED;
295 continue;
296 }
297 pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
298 pciide_pci_intr);
299 }
300 }
301
302 void
303 sis96x_setup_channel(chp)
304 struct channel_softc *chp;
305 {
306 struct ata_drive_datas *drvp;
307 int drive;
308 u_int32_t sis_tim;
309 u_int32_t idedma_ctl;
310 int regtim;
311 struct pciide_channel *cp = (struct pciide_channel*)chp;
312 struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
313
314 sis_tim = 0;
315 idedma_ctl = 0;
316 /* setup DMA if needed */
317 pciide_channel_dma_setup(cp);
318
319 for (drive = 0; drive < 2; drive++) {
320 regtim = SIS_TIM133(
321 pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_57),
322 chp->channel, drive);
323 drvp = &chp->ch_drive[drive];
324 /* If no drive, skip */
325 if ((drvp->drive_flags & DRIVE) == 0)
326 continue;
327 /* add timing values, setup DMA if needed */
328 if (drvp->drive_flags & DRIVE_UDMA) {
329 /* use Ultra/DMA */
330 drvp->drive_flags &= ~DRIVE_DMA;
331 if (pciide_pci_read(sc->sc_pc, sc->sc_tag,
332 SIS96x_REG_CBL(chp->channel)) & SIS96x_REG_CBL_33) {
333 if (drvp->UDMA_mode > 2)
334 drvp->UDMA_mode = 2;
335 }
336 sis_tim |= sis_udma133new_tim[drvp->UDMA_mode];
337 sis_tim |= sis_pio133new_tim[drvp->PIO_mode];
338 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
339 } else if (drvp->drive_flags & DRIVE_DMA) {
340 /*
341 * use Multiword DMA
342 * Timings will be used for both PIO and DMA,
343 * so adjust DMA mode if needed
344 */
345 if (drvp->PIO_mode > (drvp->DMA_mode + 2))
346 drvp->PIO_mode = drvp->DMA_mode + 2;
347 if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
348 drvp->DMA_mode = (drvp->PIO_mode > 2) ?
349 drvp->PIO_mode - 2 : 0;
350 sis_tim |= sis_dma133new_tim[drvp->DMA_mode];
351 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
352 } else {
353 sis_tim |= sis_pio133new_tim[drvp->PIO_mode];
354 }
355 WDCDEBUG_PRINT(("sis96x_setup_channel: new timings reg for "
356 "channel %d drive %d: 0x%x (reg 0x%x)\n",
357 chp->channel, drive, sis_tim, regtim), DEBUG_PROBE);
358 pci_conf_write(sc->sc_pc, sc->sc_tag, regtim, sis_tim);
359 }
360 if (idedma_ctl != 0) {
361 /* Add software bits in status register */
362 bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
363 IDEDMA_CTL+ (IDEDMA_SCH_OFFSET * chp->channel),
364 idedma_ctl);
365 }
366 }
367
368 void
369 sis_setup_channel(chp)
370 struct channel_softc *chp;
371 {
372 struct ata_drive_datas *drvp;
373 int drive;
374 u_int32_t sis_tim;
375 u_int32_t idedma_ctl;
376 struct pciide_channel *cp = (struct pciide_channel*)chp;
377 struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
378
379 WDCDEBUG_PRINT(("sis_setup_channel: old timings reg for "
380 "channel %d 0x%x\n", chp->channel,
381 pci_conf_read(sc->sc_pc, sc->sc_tag, SIS_TIM(chp->channel))),
382 DEBUG_PROBE);
383 sis_tim = 0;
384 idedma_ctl = 0;
385 /* setup DMA if needed */
386 pciide_channel_dma_setup(cp);
387
388 for (drive = 0; drive < 2; drive++) {
389 drvp = &chp->ch_drive[drive];
390 /* If no drive, skip */
391 if ((drvp->drive_flags & DRIVE) == 0)
392 continue;
393 /* add timing values, setup DMA if needed */
394 if ((drvp->drive_flags & DRIVE_DMA) == 0 &&
395 (drvp->drive_flags & DRIVE_UDMA) == 0)
396 goto pio;
397
398 if (drvp->drive_flags & DRIVE_UDMA) {
399 /* use Ultra/DMA */
400 drvp->drive_flags &= ~DRIVE_DMA;
401 if (pciide_pci_read(sc->sc_pc, sc->sc_tag,
402 SIS_REG_CBL) & SIS_REG_CBL_33(chp->channel)) {
403 if (drvp->UDMA_mode > 2)
404 drvp->UDMA_mode = 2;
405 }
406 switch (sc->sis_type) {
407 case SIS_TYPE_66:
408 case SIS_TYPE_100OLD:
409 sis_tim |= sis_udma66_tim[drvp->UDMA_mode] <<
410 SIS_TIM66_UDMA_TIME_OFF(drive);
411 break;
412 case SIS_TYPE_100NEW:
413 sis_tim |=
414 sis_udma100new_tim[drvp->UDMA_mode] <<
415 SIS_TIM100_UDMA_TIME_OFF(drive);
416 case SIS_TYPE_133OLD:
417 sis_tim |=
418 sis_udma133old_tim[drvp->UDMA_mode] <<
419 SIS_TIM100_UDMA_TIME_OFF(drive);
420 break;
421 default:
422 aprint_error("unknown SiS IDE type %d\n",
423 sc->sis_type);
424 }
425 } else {
426 /*
427 * use Multiword DMA
428 * Timings will be used for both PIO and DMA,
429 * so adjust DMA mode if needed
430 */
431 if (drvp->PIO_mode > (drvp->DMA_mode + 2))
432 drvp->PIO_mode = drvp->DMA_mode + 2;
433 if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
434 drvp->DMA_mode = (drvp->PIO_mode > 2) ?
435 drvp->PIO_mode - 2 : 0;
436 if (drvp->DMA_mode == 0)
437 drvp->PIO_mode = 0;
438 }
439 idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
440 pio: switch (sc->sis_type) {
441 case SIS_TYPE_NOUDMA:
442 case SIS_TYPE_66:
443 case SIS_TYPE_100OLD:
444 sis_tim |= sis_pio_act[drvp->PIO_mode] <<
445 SIS_TIM66_ACT_OFF(drive);
446 sis_tim |= sis_pio_rec[drvp->PIO_mode] <<
447 SIS_TIM66_REC_OFF(drive);
448 break;
449 case SIS_TYPE_100NEW:
450 case SIS_TYPE_133OLD:
451 sis_tim |= sis_pio_act[drvp->PIO_mode] <<
452 SIS_TIM100_ACT_OFF(drive);
453 sis_tim |= sis_pio_rec[drvp->PIO_mode] <<
454 SIS_TIM100_REC_OFF(drive);
455 break;
456 default:
457 aprint_error("unknown SiS IDE type %d\n",
458 sc->sis_type);
459 }
460 }
461 WDCDEBUG_PRINT(("sis_setup_channel: new timings reg for "
462 "channel %d 0x%x\n", chp->channel, sis_tim), DEBUG_PROBE);
463 pci_conf_write(sc->sc_pc, sc->sc_tag, SIS_TIM(chp->channel), sis_tim);
464 if (idedma_ctl != 0) {
465 /* Add software bits in status register */
466 bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
467 IDEDMA_CTL+ (IDEDMA_SCH_OFFSET * chp->channel),
468 idedma_ctl);
469 }
470 }
471