pchb.c revision 1.7 1 /* $NetBSD: pchb.c,v 1.7 2008/02/28 18:51:18 drochner Exp $ */
2
3 /*-
4 * Copyright (c) 1996, 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: pchb.c,v 1.7 2008/02/28 18:51:18 drochner Exp $");
41
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46
47 #include <machine/bus.h>
48
49 #include <dev/pci/pcivar.h>
50 #include <dev/pci/pcireg.h>
51
52 #include <dev/pci/pcidevs.h>
53
54 #include <dev/pci/agpreg.h>
55 #include <dev/pci/agpvar.h>
56
57 #include <arch/x86/pci/pchbvar.h>
58
59 #include "rnd.h"
60
61 #define PCISET_BRIDGETYPE_MASK 0x3
62 #define PCISET_TYPE_COMPAT 0x1
63 #define PCISET_TYPE_AUX 0x2
64
65 #define PCISET_BUSCONFIG_REG 0x48
66 #define PCISET_BRIDGE_NUMBER(reg) (((reg) >> 8) & 0xff)
67 #define PCISET_PCI_BUS_NUMBER(reg) (((reg) >> 16) & 0xff)
68
69 /* XXX should be in dev/ic/i82443reg.h */
70 #define I82443BX_SDRAMC_REG 0x74 /* upper 16 bits */
71
72 /* XXX should be in dev/ic/i82424{reg.var}.h */
73 #define I82424_CPU_BCTL_REG 0x53
74 #define I82424_PCI_BCTL_REG 0x54
75
76 #define I82424_BCTL_CPUMEM_POSTEN 0x01
77 #define I82424_BCTL_CPUPCI_POSTEN 0x02
78 #define I82424_BCTL_PCIMEM_BURSTEN 0x01
79 #define I82424_BCTL_PCI_BURSTEN 0x02
80
81 int pchbmatch(struct device *, struct cfdata *, void *);
82 void pchbattach(struct device *, struct device *, void *);
83 int pchbdetach(device_t, int);
84
85 static bool pchb_resume(device_t);
86 static bool pchb_suspend(device_t);
87
88 CFATTACH_DECL(pchb, sizeof(struct pchb_softc),
89 pchbmatch, pchbattach, pchbdetach, NULL);
90
91 int
92 pchbmatch(struct device *parent, struct cfdata *match, void *aux)
93 {
94 struct pci_attach_args *pa = aux;
95
96 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
97 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
98 return 1;
99
100 return 0;
101 }
102
103 void
104 pchbattach(struct device *parent, struct device *self, void *aux)
105 {
106 #if NRND > 0
107 struct pchb_softc *sc = (void *) self;
108 #endif
109 struct pci_attach_args *pa = aux;
110 char devinfo[256];
111 struct pcibus_attach_args pba;
112 struct agpbus_attach_args apa;
113 pcireg_t bcreg;
114 u_char bdnum, pbnum = 0; /* XXX: gcc */
115 pcitag_t tag;
116 int doattach, attachflags, has_agp;
117
118 aprint_naive("\n");
119 aprint_normal("\n");
120
121 doattach = 0;
122 has_agp = 0;
123 attachflags = pa->pa_flags;
124
125 /*
126 * Print out a description, and configure certain chipsets which
127 * have auxiliary PCI buses.
128 */
129
130 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
131 aprint_normal("%s: %s (rev. 0x%02x)\n", self->dv_xname, devinfo,
132 PCI_REVISION(pa->pa_class));
133
134 switch (PCI_VENDOR(pa->pa_id)) {
135 /*
136 * i386 stuff.
137 */
138 case PCI_VENDOR_SERVERWORKS:
139 pbnum = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x44) & 0xff;
140
141 if (pbnum == 0)
142 break;
143
144 /*
145 * This host bridge has a second PCI bus.
146 * Configure it.
147 */
148 switch (PCI_PRODUCT(pa->pa_id)) {
149 case PCI_PRODUCT_SERVERWORKS_CSB5:
150 case PCI_PRODUCT_SERVERWORKS_CSB6:
151 /* These devices show up as host bridges, but are
152 really southbridges. */
153 break;
154 case PCI_PRODUCT_SERVERWORKS_CMIC_HE:
155 case PCI_PRODUCT_SERVERWORKS_CMIC_LE:
156 case PCI_PRODUCT_SERVERWORKS_CMIC_SL:
157 /* CNBs and CIOBs are connected to these using a
158 private bus. The bus number register is that of
159 the first PCI bus hanging off the CIOB. We let
160 the CIOB attachment handle configuring the PCI
161 buses. */
162 break;
163 default:
164 aprint_error("%s: unknown ServerWorks chip ID "
165 "0x%04x; trying to attach PCI buses behind it\n",
166 self->dv_xname, PCI_PRODUCT(pa->pa_id));
167 /* FALLTHROUGH */
168 case PCI_PRODUCT_SERVERWORKS_CNB20_LE_AGP:
169 case PCI_PRODUCT_SERVERWORKS_CNB30_LE_PCI:
170 case PCI_PRODUCT_SERVERWORKS_CNB20_LE_PCI:
171 case PCI_PRODUCT_SERVERWORKS_CNB20_HE_PCI:
172 case PCI_PRODUCT_SERVERWORKS_CNB20_HE_AGP:
173 case PCI_PRODUCT_SERVERWORKS_CIOB_X:
174 case PCI_PRODUCT_SERVERWORKS_CNB30_HE:
175 case PCI_PRODUCT_SERVERWORKS_CNB20_HE_PCI2:
176 case PCI_PRODUCT_SERVERWORKS_CIOB_X2:
177 case PCI_PRODUCT_SERVERWORKS_CIOB_E:
178 switch (attachflags &
179 (PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED)) {
180 case 0:
181 /* Doesn't smell like there's anything there. */
182 break;
183 case PCI_FLAGS_MEM_ENABLED:
184 attachflags |= PCI_FLAGS_IO_ENABLED;
185 /* FALLTHROUGH */
186 default:
187 doattach = 1;
188 break;
189 }
190 break;
191 }
192 break;
193 case PCI_VENDOR_INTEL:
194 switch (PCI_PRODUCT(pa->pa_id)) {
195 case PCI_PRODUCT_INTEL_82452_PB:
196 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x40);
197 pbnum = PCISET_BRIDGE_NUMBER(bcreg);
198 if (pbnum != 0xff) {
199 pbnum++;
200 doattach = 1;
201 }
202 break;
203 case PCI_PRODUCT_INTEL_82443BX_AGP:
204 case PCI_PRODUCT_INTEL_82443BX_NOAGP:
205 /*
206 * http://www.intel.com/design/chipsets/specupdt/290639.htm
207 * says this bug is fixed in steppings >= C0 (erratum 11),
208 * so don't tweak the bits in that case.
209 */
210 if (!(PCI_REVISION(pa->pa_class) >= 0x03)) {
211 /*
212 * BIOS BUG WORKAROUND! The 82443BX
213 * datasheet indicates that the only
214 * legal setting for the "Idle/Pipeline
215 * DRAM Leadoff Timing (IPLDT)" parameter
216 * (bits 9:8) is 01. Unfortunately, some
217 * BIOSs do not set these bits properly.
218 */
219 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
220 I82443BX_SDRAMC_REG);
221 if ((bcreg & 0x03000000) != 0x01000000) {
222 aprint_verbose("%s: fixing "
223 "Idle/Pipeline DRAM "
224 "Leadoff Timing\n", self->dv_xname);
225 bcreg &= ~0x03000000;
226 bcreg |= 0x01000000;
227 pci_conf_write(pa->pa_pc, pa->pa_tag,
228 I82443BX_SDRAMC_REG, bcreg);
229 }
230 }
231 break;
232
233 case PCI_PRODUCT_INTEL_PCI450_PB:
234 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
235 PCISET_BUSCONFIG_REG);
236 bdnum = PCISET_BRIDGE_NUMBER(bcreg);
237 pbnum = PCISET_PCI_BUS_NUMBER(bcreg);
238 switch (bdnum & PCISET_BRIDGETYPE_MASK) {
239 default:
240 aprint_error("%s: bdnum=%x (reserved)\n",
241 self->dv_xname, bdnum);
242 break;
243 case PCISET_TYPE_COMPAT:
244 aprint_verbose(
245 "%s: Compatibility PB (bus %d)\n",
246 self->dv_xname, pbnum);
247 break;
248 case PCISET_TYPE_AUX:
249 aprint_verbose("%s: Auxiliary PB (bus %d)\n",
250 self->dv_xname, pbnum);
251 /*
252 * This host bridge has a second PCI bus.
253 * Configure it.
254 */
255 doattach = 1;
256 break;
257 }
258 break;
259 case PCI_PRODUCT_INTEL_CDC:
260 bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
261 I82424_CPU_BCTL_REG);
262 if (bcreg & I82424_BCTL_CPUPCI_POSTEN) {
263 bcreg &= ~I82424_BCTL_CPUPCI_POSTEN;
264 pci_conf_write(pa->pa_pc, pa->pa_tag,
265 I82424_CPU_BCTL_REG, bcreg);
266 aprint_verbose(
267 "%s: disabled CPU-PCI write posting\n",
268 self->dv_xname);
269 }
270 break;
271 case PCI_PRODUCT_INTEL_82451NX_PXB:
272 /*
273 * The NX chipset supports up to 2 "PXB" chips
274 * which can drive 2 PCI buses each. Each bus
275 * shows up as logical PCI device, with fixed
276 * device numbers between 18 and 21.
277 * See the datasheet at
278 ftp://download.intel.com/design/chipsets/datashts/24377102.pdf
279 * for details.
280 * (It would be easier to attach all the buses
281 * at the MIOC, but less aesthetical imho.)
282 */
283 if ((attachflags &
284 (PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED)) ==
285 PCI_FLAGS_MEM_ENABLED)
286 attachflags |= PCI_FLAGS_IO_ENABLED;
287
288 pbnum = 0;
289 switch (pa->pa_device) {
290 case 18: /* PXB 0 bus A - primary bus */
291 break;
292 case 19: /* PXB 0 bus B */
293 /* read SUBA0 from MIOC */
294 tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
295 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
296 pbnum = ((bcreg & 0x0000ff00) >> 8) + 1;
297 break;
298 case 20: /* PXB 1 bus A */
299 /* read BUSNO1 from MIOC */
300 tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
301 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
302 pbnum = (bcreg & 0xff000000) >> 24;
303 break;
304 case 21: /* PXB 1 bus B */
305 /* read SUBA1 from MIOC */
306 tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
307 bcreg = pci_conf_read(pa->pa_pc, tag, 0xd4);
308 pbnum = (bcreg & 0x000000ff) + 1;
309 break;
310 }
311 if (pbnum != 0)
312 doattach = 1;
313 break;
314
315 /*
316 * i386 and amd64 stuff.
317 */
318 case PCI_PRODUCT_INTEL_82810_MCH:
319 case PCI_PRODUCT_INTEL_82810_DC100_MCH:
320 case PCI_PRODUCT_INTEL_82810E_MCH:
321 case PCI_PRODUCT_INTEL_82815_FULL_HUB:
322 case PCI_PRODUCT_INTEL_82830MP_IO_1:
323 case PCI_PRODUCT_INTEL_82845G_DRAM:
324 case PCI_PRODUCT_INTEL_82855GM_MCH:
325 case PCI_PRODUCT_INTEL_82865_HB:
326 case PCI_PRODUCT_INTEL_82915G_HB:
327 case PCI_PRODUCT_INTEL_82915GM_HB:
328 case PCI_PRODUCT_INTEL_82945P_MCH:
329 case PCI_PRODUCT_INTEL_82945GM_HB:
330 case PCI_PRODUCT_INTEL_82965Q_HB:
331 case PCI_PRODUCT_INTEL_82965G_HB:
332 case PCI_PRODUCT_INTEL_82965PM_HB:
333 case PCI_PRODUCT_INTEL_82Q35_HB:
334 case PCI_PRODUCT_INTEL_82G33_HB:
335 case PCI_PRODUCT_INTEL_82Q33_HB:
336 /*
337 * The host bridge is either in GFX mode (internal
338 * graphics) or in AGP mode. In GFX mode, we pretend
339 * to have AGP because the graphics memory access
340 * is very similar and the AGP GATT code will
341 * deal with this. In the latter case, the
342 * pci_get_capability(PCI_CAP_AGP) test below will
343 * fire, so we do no harm by already setting the flag.
344 */
345 has_agp = 1;
346 break;
347 }
348 break;
349 }
350
351 #if NRND > 0
352 /*
353 * Attach a random number generator, if there is one.
354 */
355 pchb_attach_rnd(sc, pa);
356 #endif
357
358 if (!pmf_device_register(self, pchb_suspend, pchb_resume))
359 aprint_error_dev(self, "couldn't establish power handler\n");
360
361 /*
362 * If we haven't detected AGP yet (via a product ID),
363 * then check for AGP capability on the device.
364 */
365 if (has_agp ||
366 pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
367 NULL, NULL) != 0) {
368 apa.apa_pci_args = *pa;
369 config_found_ia(self, "agpbus", &apa, agpbusprint);
370 }
371
372 if (doattach) {
373 pba.pba_iot = pa->pa_iot;
374 pba.pba_memt = pa->pa_memt;
375 pba.pba_dmat = pa->pa_dmat;
376 pba.pba_dmat64 = pa->pa_dmat64;
377 pba.pba_pc = pa->pa_pc;
378 pba.pba_flags = attachflags;
379 pba.pba_bus = pbnum;
380 pba.pba_bridgetag = NULL;
381 pba.pba_pc = pa->pa_pc;
382 pba.pba_intrswiz = 0;
383 memset(&pba.pba_intrtag, 0, sizeof(pba.pba_intrtag));
384 config_found_ia(self, "pcibus", &pba, pcibusprint);
385 }
386 }
387
388 int
389 pchbdetach(device_t self, int flags)
390 {
391 int rc;
392 #if NRND > 0
393 struct pchb_softc *sc = device_private(self);
394 #endif
395
396 if ((rc = config_detach_children(self, flags)) != 0)
397 return rc;
398
399 pmf_device_deregister(self);
400
401 #if NRND > 0
402 /*
403 * Attach a random number generator, if there is one.
404 */
405 pchb_detach_rnd(sc);
406 #endif
407 return 0;
408 }
409
410 static bool
411 pchb_suspend(device_t dv)
412 {
413 struct pchb_softc *sc = device_private(dv);
414 pci_chipset_tag_t pc;
415 pcitag_t tag;
416 int off;
417
418 pc = sc->sc_pc;
419 tag = sc->sc_tag;
420
421 for (off = 0x40; off <= 0xff; off += 4)
422 sc->sc_pciconfext[(off - 0x40) / 4] = pci_conf_read(pc, tag, off);
423
424 return true;
425 }
426
427 static bool
428 pchb_resume(device_t dv)
429 {
430 struct pchb_softc *sc = device_private(dv);
431 pci_chipset_tag_t pc;
432 pcitag_t tag;
433 int off;
434
435 pc = sc->sc_pc;
436 tag = sc->sc_tag;
437
438 for (off = 0x40; off <= 0xff; off += 4)
439 pci_conf_write(pc, tag, off, sc->sc_pciconfext[(off - 0x40) / 4]);
440
441 return true;
442 }
443