xref: /netbsd-src/sys/arch/x86/pci/pchb.c (revision 7fa608457b817eca6e0977b37f758ae064f3c99c)
1 /*	$NetBSD: pchb.c,v 1.2 2007/10/30 12:20:03 jnemeth 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.2 2007/10/30 12:20:03 jnemeth 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	0x76
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 
84 CFATTACH_DECL(pchb, sizeof(struct pchb_softc),
85     pchbmatch, pchbattach, NULL, NULL);
86 
87 int
88 pchbmatch(struct device *parent, struct cfdata *match, void *aux)
89 {
90 	struct pci_attach_args *pa = aux;
91 
92 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
93 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
94 		return 1;
95 
96 	return 0;
97 }
98 
99 void
100 pchbattach(struct device *parent, struct device *self, void *aux)
101 {
102 #if NRND > 0
103 	struct pchb_softc *sc = (void *) self;
104 #endif
105 	struct pci_attach_args *pa = aux;
106 	char devinfo[256];
107 	struct pcibus_attach_args pba;
108 	struct agpbus_attach_args apa;
109 	pcireg_t bcreg;
110 	u_char bdnum, pbnum = 0; /* XXX: gcc */
111 	pcitag_t tag;
112 	int doattach, attachflags, has_agp;
113 
114 	aprint_naive("\n");
115 	aprint_normal("\n");
116 
117 	doattach = 0;
118 	has_agp = 0;
119 	attachflags = pa->pa_flags;
120 
121 	/*
122 	 * Print out a description, and configure certain chipsets which
123 	 * have auxiliary PCI buses.
124 	 */
125 
126 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
127 	aprint_normal("%s: %s (rev. 0x%02x)\n", self->dv_xname, devinfo,
128 	    PCI_REVISION(pa->pa_class));
129 
130 	switch (PCI_VENDOR(pa->pa_id)) {
131 	/*
132 	 * i386 stuff.
133 	 */
134 	case PCI_VENDOR_SERVERWORKS:
135 		pbnum = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x44) & 0xff;
136 
137 		if (pbnum == 0)
138 			break;
139 
140 		/*
141 		 * This host bridge has a second PCI bus.
142 		 * Configure it.
143 		 */
144 		switch (PCI_PRODUCT(pa->pa_id)) {
145 		case PCI_PRODUCT_SERVERWORKS_CSB5:
146 		case PCI_PRODUCT_SERVERWORKS_CSB6:
147 			/* These devices show up as host bridges, but are
148 			   really southbridges. */
149 			break;
150 		case PCI_PRODUCT_SERVERWORKS_CMIC_HE:
151 		case PCI_PRODUCT_SERVERWORKS_CMIC_LE:
152 		case PCI_PRODUCT_SERVERWORKS_CMIC_SL:
153 			/* CNBs and CIOBs are connected to these using a
154 			   private bus.  The bus number register is that of
155 			   the first PCI bus hanging off the CIOB.  We let
156 			   the CIOB attachment handle configuring the PCI
157 			   buses. */
158 			break;
159 		default:
160 			aprint_error("%s: unknown ServerWorks chip ID "
161 			    "0x%04x; trying to attach PCI buses behind it\n",
162 			    self->dv_xname, PCI_PRODUCT(pa->pa_id));
163 			/* FALLTHROUGH */
164 		case PCI_PRODUCT_SERVERWORKS_CNB20_LE_AGP:
165 		case PCI_PRODUCT_SERVERWORKS_CNB30_LE_PCI:
166 		case PCI_PRODUCT_SERVERWORKS_CNB20_LE_PCI:
167 		case PCI_PRODUCT_SERVERWORKS_CNB20_HE_PCI:
168 		case PCI_PRODUCT_SERVERWORKS_CNB20_HE_AGP:
169 		case PCI_PRODUCT_SERVERWORKS_CIOB_X:
170 		case PCI_PRODUCT_SERVERWORKS_CNB30_HE:
171 		case PCI_PRODUCT_SERVERWORKS_CNB20_HE_PCI2:
172 		case PCI_PRODUCT_SERVERWORKS_CIOB_X2:
173 		case PCI_PRODUCT_SERVERWORKS_CIOB_E:
174 			switch (attachflags &
175 			    (PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED)) {
176 			case 0:
177 				/* Doesn't smell like there's anything there. */
178 				break;
179 			case PCI_FLAGS_MEM_ENABLED:
180 				attachflags |= PCI_FLAGS_IO_ENABLED;
181 				/* FALLTHROUGH */
182 			default:
183 				doattach = 1;
184 				break;
185 			}
186 			break;
187 		}
188 		break;
189 	case PCI_VENDOR_INTEL:
190 		switch (PCI_PRODUCT(pa->pa_id)) {
191 		case PCI_PRODUCT_INTEL_82452_PB:
192 			bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x40);
193 			pbnum = PCISET_BRIDGE_NUMBER(bcreg);
194 			if (pbnum != 0xff) {
195 				pbnum++;
196 				doattach = 1;
197 			}
198 			break;
199 		case PCI_PRODUCT_INTEL_82443BX_AGP:
200 		case PCI_PRODUCT_INTEL_82443BX_NOAGP:
201 		/*
202 		 * http://www.intel.com/design/chipsets/specupdt/290639.htm
203 		 * says this bug is fixed in steppings >= C0 (erratum 11),
204 		 * so don't tweak the bits in that case.
205 		 */
206 			if (!(PCI_REVISION(pa->pa_class) >= 0x03)) {
207 				/*
208 				 * BIOS BUG WORKAROUND!  The 82443BX
209 				 * datasheet indicates that the only
210 				 * legal setting for the "Idle/Pipeline
211 				 * DRAM Leadoff Timing (IPLDT)" parameter
212 				 * (bits 9:8) is 01.  Unfortunately, some
213 				 * BIOSs do not set these bits properly.
214 				 */
215 				bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
216 				    I82443BX_SDRAMC_REG);
217 				if ((bcreg & 0x0300) != 0x0100) {
218 					aprint_verbose("%s: fixing "
219 					    "Idle/Pipeline DRAM "
220 					    "Leadoff Timing\n", self->dv_xname);
221 					bcreg &= ~0x0300;
222 					bcreg |=  0x0100;
223 					pci_conf_write(pa->pa_pc, pa->pa_tag,
224 					    I82443BX_SDRAMC_REG, bcreg);
225 				}
226 			}
227 			break;
228 
229 		case PCI_PRODUCT_INTEL_PCI450_PB:
230 			bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
231 					      PCISET_BUSCONFIG_REG);
232 			bdnum = PCISET_BRIDGE_NUMBER(bcreg);
233 			pbnum = PCISET_PCI_BUS_NUMBER(bcreg);
234 			switch (bdnum & PCISET_BRIDGETYPE_MASK) {
235 			default:
236 				aprint_error("%s: bdnum=%x (reserved)\n",
237 				       self->dv_xname, bdnum);
238 				break;
239 			case PCISET_TYPE_COMPAT:
240 				aprint_verbose(
241 				    "%s: Compatibility PB (bus %d)\n",
242 				    self->dv_xname, pbnum);
243 				break;
244 			case PCISET_TYPE_AUX:
245 				aprint_verbose("%s: Auxiliary PB (bus %d)\n",
246 				       self->dv_xname, pbnum);
247 				/*
248 				 * This host bridge has a second PCI bus.
249 				 * Configure it.
250 				 */
251 				doattach = 1;
252 				break;
253 			}
254 			break;
255 		case PCI_PRODUCT_INTEL_CDC:
256 			bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
257 					      I82424_CPU_BCTL_REG);
258 			if (bcreg & I82424_BCTL_CPUPCI_POSTEN) {
259 				bcreg &= ~I82424_BCTL_CPUPCI_POSTEN;
260 				pci_conf_write(pa->pa_pc, pa->pa_tag,
261 					       I82424_CPU_BCTL_REG, bcreg);
262 				aprint_verbose(
263 				    "%s: disabled CPU-PCI write posting\n",
264 				    self->dv_xname);
265 			}
266 			break;
267 		case PCI_PRODUCT_INTEL_82451NX_PXB:
268 			/*
269 			 * The NX chipset supports up to 2 "PXB" chips
270 			 * which can drive 2 PCI buses each. Each bus
271 			 * shows up as logical PCI device, with fixed
272 			 * device numbers between 18 and 21.
273 			 * See the datasheet at
274 		ftp://download.intel.com/design/chipsets/datashts/24377102.pdf
275 			 * for details.
276 			 * (It would be easier to attach all the buses
277 			 * at the MIOC, but less aesthetical imho.)
278 			 */
279 			if ((attachflags &
280 			    (PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED)) ==
281 			    PCI_FLAGS_MEM_ENABLED)
282 				attachflags |= PCI_FLAGS_IO_ENABLED;
283 
284 			pbnum = 0;
285 			switch (pa->pa_device) {
286 			case 18: /* PXB 0 bus A - primary bus */
287 				break;
288 			case 19: /* PXB 0 bus B */
289 				/* read SUBA0 from MIOC */
290 				tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
291 				bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
292 				pbnum = ((bcreg & 0x0000ff00) >> 8) + 1;
293 				break;
294 			case 20: /* PXB 1 bus A */
295 				/* read BUSNO1 from MIOC */
296 				tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
297 				bcreg = pci_conf_read(pa->pa_pc, tag, 0xd0);
298 				pbnum = (bcreg & 0xff000000) >> 24;
299 				break;
300 			case 21: /* PXB 1 bus B */
301 				/* read SUBA1 from MIOC */
302 				tag = pci_make_tag(pa->pa_pc, 0, 16, 0);
303 				bcreg = pci_conf_read(pa->pa_pc, tag, 0xd4);
304 				pbnum = (bcreg & 0x000000ff) + 1;
305 				break;
306 			}
307 			if (pbnum != 0)
308 				doattach = 1;
309 			break;
310 
311 		/*
312 		 * i386 and amd64 stuff.
313 		 */
314 		case PCI_PRODUCT_INTEL_82810_MCH:
315 		case PCI_PRODUCT_INTEL_82810_DC100_MCH:
316 		case PCI_PRODUCT_INTEL_82810E_MCH:
317 		case PCI_PRODUCT_INTEL_82815_FULL_HUB:
318 		case PCI_PRODUCT_INTEL_82830MP_IO_1:
319 		case PCI_PRODUCT_INTEL_82845G_DRAM:
320 		case PCI_PRODUCT_INTEL_82855GM_MCH:
321 		case PCI_PRODUCT_INTEL_82865_HB:
322 		case PCI_PRODUCT_INTEL_82915G_HB:
323 		case PCI_PRODUCT_INTEL_82915GM_HB:
324 		case PCI_PRODUCT_INTEL_82945P_MCH:
325 		case PCI_PRODUCT_INTEL_82945GM_HB:
326 		case PCI_PRODUCT_INTEL_82965Q_HB:
327 		case PCI_PRODUCT_INTEL_82965G_HB:
328 			/*
329 			 * The host bridge is either in GFX mode (internal
330 			 * graphics) or in AGP mode. In GFX mode, we pretend
331 			 * to have AGP because the graphics memory access
332 			 * is very similar and the AGP GATT code will
333 			 * deal with this. In the latter case, the
334 			 * pci_get_capability(PCI_CAP_AGP) test below will
335 			 * fire, so we do no harm by already setting the flag.
336 			 */
337 			has_agp = 1;
338 			break;
339 		}
340 		break;
341 	}
342 
343 #if NRND > 0
344 	/*
345 	 * Attach a random number generator, if there is one.
346 	 */
347 	pchb_attach_rnd(sc, pa);
348 #endif
349 
350 	/*
351 	 * If we haven't detected AGP yet (via a product ID),
352 	 * then check for AGP capability on the device.
353 	 */
354 	if (has_agp ||
355 	    pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
356 			       NULL, NULL) != 0) {
357 		apa.apa_pci_args = *pa;
358 		config_found_ia(self, "agpbus", &apa, agpbusprint);
359 	}
360 
361 	if (doattach) {
362 		pba.pba_iot = pa->pa_iot;
363 		pba.pba_memt = pa->pa_memt;
364 		pba.pba_dmat = pa->pa_dmat;
365 		pba.pba_dmat64 = pa->pa_dmat64;
366 		pba.pba_pc = pa->pa_pc;
367 		pba.pba_flags = attachflags;
368 		pba.pba_bus = pbnum;
369 		pba.pba_bridgetag = NULL;
370 		pba.pba_pc = pa->pa_pc;
371 		pba.pba_intrswiz = 0;
372 		memset(&pba.pba_intrtag, 0, sizeof(pba.pba_intrtag));
373 		config_found_ia(self, "pcibus", &pba, pcibusprint);
374 	}
375 }
376