xref: /haiku/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp (revision 385ee03ba83b7a40d315e17b03031b3ca37820c0)
1 /*
2  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2011-2016, Haiku, Inc. All Rights Reserved.
4  * Distributed under the terms of the MIT License.
5  *
6  * Authors:
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Jerome Duval, jerome.duval@gmail.com
9  *		Adrien Destugues, pulkomandy@gmail.com
10  *		Michael Lotz, mmlr@mlotz.ch
11  *		Alexander von Gluck IV, kallisti5@unixzen.com
12  */
13 
14 
15 #include <AreaKeeper.h>
16 #include <intel_extreme.h>
17 
18 #include <stdlib.h>
19 
20 #include <AGP.h>
21 #include <KernelExport.h>
22 #include <PCI.h>
23 
24 #include <new>
25 
26 
27 #define TRACE_INTEL
28 #ifdef TRACE_INTEL
29 #	define TRACE(x...) dprintf("intel_gart: " x)
30 #else
31 #	define TRACE(x...) ;
32 #endif
33 #define ERROR(x...) dprintf("intel_gart: " x)
34 
35 #ifndef __HAIKU__
36 #	define B_KERNEL_READ_AREA	0
37 #	define B_KERNEL_WRITE_AREA	0
38 #endif
39 
40 /* read and write to PCI config space */
41 #define get_pci_config(info, offset, size) \
42 	(sPCI->read_pci_config((info).bus, (info).device, (info).function, \
43 		(offset), (size)))
44 #define set_pci_config(info, offset, size, value) \
45 	(sPCI->write_pci_config((info).bus, (info).device, (info).function, \
46 		(offset), (size), (value)))
47 #define write32(address, data) \
48 	(*((volatile uint32*)(address)) = (data))
49 #define read32(address) \
50 	(*((volatile uint32*)(address)))
51 
52 
53 // PCI "Host bridge" is most cases :-)
54 const struct supported_device {
55 	uint32		bridge_id;
56 	uint32		display_id;
57 	int32		type;
58 	const char	*name;
59 } kSupportedDevices[] = {
60 	{0x3575, 0x3577, INTEL_GROUP_83x, "i830GM"},
61 	{0x2560, 0x2562, INTEL_GROUP_83x, "i845G"},
62 	{0x3580, 0x3582, INTEL_GROUP_85x, "i855G"},
63 	{0x358c, 0x358e, INTEL_GROUP_85x, "i855G"},
64 	{0x2570, 0x2572, INTEL_GROUP_85x, "i865G"},
65 
66 //	{0x2792, INTEL_GROUP_91x, "i910"},
67 //	{0x258a, INTEL_GROUP_91x, "i915"},
68 	{0x2580, 0x2582, INTEL_MODEL_915, "i915G"},
69 	{0x2590, 0x2592, INTEL_MODEL_915M, "i915GM"},
70 	{0x2770, 0x2772, INTEL_MODEL_945, "i945G"},
71 	{0x27a0, 0x27a2, INTEL_MODEL_945M, "i945GM"},
72 	{0x27ac, 0x27ae, INTEL_MODEL_945M, "i945GME"},
73 
74 	{0x2970, 0x2972, INTEL_MODEL_965, "i946GZ"},
75 	{0x2980, 0x2982, INTEL_MODEL_965, "G35"},
76 	{0x2990, 0x2992, INTEL_MODEL_965, "i965Q"},
77 	{0x29a0, 0x29a2, INTEL_MODEL_965, "i965G"},
78 	{0x2a00, 0x2a02, INTEL_MODEL_965, "i965GM"},
79 	{0x2a10, 0x2a12, INTEL_MODEL_965, "i965GME"},
80 
81 	{0x29b0, 0x29b2, INTEL_MODEL_G33, "G33"},
82 	{0x29c0, 0x29c2, INTEL_MODEL_G33, "Q35"},
83 	{0x29d0, 0x29d2, INTEL_MODEL_G33, "Q33"},
84 
85 	{0x2a40, 0x2a42, INTEL_MODEL_GM45, "GM45"},
86 	{0x2e00, 0x2e02, INTEL_MODEL_G45, "IGD"},
87 	{0x2e10, 0x2e12, INTEL_MODEL_G45, "Q45"},
88 	{0x2e20, 0x2e22, INTEL_MODEL_G45, "G45"},
89 	{0x2e30, 0x2e32, INTEL_MODEL_G45, "G41"},
90 	{0x2e40, 0x2e42, INTEL_MODEL_G45, "B43"},
91 	{0x2e90, 0x2e92, INTEL_MODEL_G45, "B43"},
92 
93 	{0xa000, 0xa001, INTEL_MODEL_PINE, "Atom D4xx"},
94 	{0xa000, 0xa002, INTEL_MODEL_PINE, "Atom D5xx"},
95 	{0xa010, 0xa011, INTEL_MODEL_PINEM, "Atom N4xx"},
96 	{0xa010, 0xa012, INTEL_MODEL_PINEM, "Atom N5xx"},
97 
98 	{0x0040, 0x0042, INTEL_MODEL_ILKG, "IronLake Desktop"},
99 	{0x0044, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
100 	{0x0062, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
101 	{0x006a, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"},
102 
103 	{0x0100, 0x0102, INTEL_MODEL_SNBG, "SandyBridge Desktop GT1"},
104 	{0x0100, 0x0112, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2"},
105 	{0x0100, 0x0122, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2+"},
106 	{0x0104, 0x0106, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT1"},
107 	{0x0104, 0x0116, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2"},
108 	{0x0104, 0x0126, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2+"},
109 	{0x0108, 0x010a, INTEL_MODEL_SNBGS, "SandyBridge Server"},
110 
111 	{0x0150, 0x0152, INTEL_MODEL_IVBG, "IvyBridge Desktop GT1"},
112 	{0x0150, 0x0162, INTEL_MODEL_IVBG, "IvyBridge Desktop GT2"},
113 	{0x0154, 0x0156, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT1"},
114 	{0x0154, 0x0166, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT2"},
115 	{0x0158, 0x015a, INTEL_MODEL_IVBGS, "IvyBridge Server GT1"},
116 	{0x0158, 0x016a, INTEL_MODEL_IVBGS, "IvyBridge Server GT2"},
117 
118 	{0x0c00, 0x0412, INTEL_MODEL_HAS, "Haswell Desktop"},
119 	{0x0c04, 0x0416, INTEL_MODEL_HASM, "Haswell Mobile"},
120 	{0x0d04, 0x0d26, INTEL_MODEL_HASM, "Haswell Mobile"},
121 	{0x0a04, 0x0a16, INTEL_MODEL_HASM, "Haswell Mobile"},
122 
123 	// XXX: 0x0f00 only confirmed on 0x0f30, 0x0f31
124 	{0x0f00, 0x0155, INTEL_MODEL_VLV, "ValleyView Desktop"},
125 	{0x0f00, 0x0f30, INTEL_MODEL_VLVM, "ValleyView Mobile"},
126 	{0x0f00, 0x0f31, INTEL_MODEL_VLVM, "ValleyView Mobile"},
127 	{0x0f00, 0x0f32, INTEL_MODEL_VLVM, "ValleyView Mobile"},
128 	{0x0f00, 0x0f33, INTEL_MODEL_VLVM, "ValleyView Mobile"},
129 	{0x0f00, 0x0157, INTEL_MODEL_VLVM, "ValleyView Mobile"},
130 
131 	// XXX: 0x1904 only confirmed on 0x1916
132 	{0x1904, 0x1902, INTEL_MODEL_SKY,  "Skylake GT1"},
133 	{0x1904, 0x1906, INTEL_MODEL_SKYM, "Skylake GT1"},
134 	{0x1904, 0x190a, INTEL_MODEL_SKYS, "Skylake GT1"},
135 	{0x1904, 0x190b, INTEL_MODEL_SKY,  "Skylake GT1"},
136 	{0x1904, 0x190e, INTEL_MODEL_SKYM, "Skylake GT1"},
137 	{0x1904, 0x1912, INTEL_MODEL_SKY,  "Skylake GT2"},
138 	{0x1904, 0x1916, INTEL_MODEL_SKYM, "Skylake GT2"},
139 	{0x1904, 0x191a, INTEL_MODEL_SKYS, "Skylake GT2"},
140 	{0x1904, 0x191b, INTEL_MODEL_SKY,  "Skylake GT2"},
141 	{0x1904, 0x191d, INTEL_MODEL_SKY,  "Skylake GT2"},
142 	{0x1904, 0x191e, INTEL_MODEL_SKYM, "Skylake GT2"},
143 	{0x1904, 0x1921, INTEL_MODEL_SKYM, "Skylake GT2F"},
144 	{0x1904, 0x1926, INTEL_MODEL_SKYM, "Skylake GT3"},
145 	{0x1904, 0x192a, INTEL_MODEL_SKYS, "Skylake GT3"},
146 	{0x1904, 0x192b, INTEL_MODEL_SKY,  "Skylake GT3"},
147 };
148 
149 struct intel_info {
150 	pci_info	bridge;
151 	pci_info	display;
152 	DeviceType*	type;
153 
154 	uint32*		gtt_base;
155 	phys_addr_t	gtt_physical_base;
156 	area_id		gtt_area;
157 	size_t		gtt_entries;
158 	size_t		gtt_stolen_entries;
159 
160 	vuint32*	registers;
161 	area_id		registers_area;
162 
163 	addr_t		aperture_base;
164 	phys_addr_t	aperture_physical_base;
165 	area_id		aperture_area;
166 	size_t		aperture_size;
167 	size_t		aperture_stolen_size;
168 
169 	phys_addr_t	scratch_page;
170 	area_id		scratch_area;
171 };
172 
173 static intel_info sInfo;
174 static pci_module_info* sPCI;
175 
176 
177 static bool
178 has_display_device(pci_info &info, uint32 deviceID)
179 {
180 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK;
181 			index++) {
182 		if (info.vendor_id != VENDOR_ID_INTEL
183 			|| info.device_id != deviceID
184 			|| info.class_base != PCI_display)
185 			continue;
186 
187 		return true;
188 	}
189 
190 	return false;
191 }
192 
193 
194 static uint16
195 gtt_memory_config(intel_info &info)
196 {
197 	uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL;
198 	if (info.type->InGroup(INTEL_GROUP_SNB))
199 		controlRegister = SNB_GRAPHICS_MEMORY_CONTROL;
200 
201 	return get_pci_config(info.bridge, controlRegister, 2);
202 }
203 
204 
205 static size_t
206 determine_gtt_stolen(intel_info &info)
207 {
208 	uint16 memoryConfig = gtt_memory_config(info);
209 	size_t memorySize = 1 << 20; // 1 MB
210 
211 	if (info.type->InGroup(INTEL_GROUP_83x)) {
212 		// Older chips
213 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
214 			case i830_LOCAL_MEMORY_ONLY:
215 				// TODO: determine its size!
216 				ERROR("getting local memory size not implemented.\n");
217 				break;
218 			case i830_STOLEN_512K:
219 				memorySize >>= 1;
220 				break;
221 			case i830_STOLEN_1M:
222 				// default case
223 				break;
224 			case i830_STOLEN_8M:
225 				memorySize *= 8;
226 				break;
227 		}
228 	} else if (info.type->InGroup(INTEL_GROUP_SNB)) {
229 		switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) {
230 			case SNB_STOLEN_MEMORY_32MB:
231 				memorySize *= 32;
232 				break;
233 			case SNB_STOLEN_MEMORY_64MB:
234 				memorySize *= 64;
235 				break;
236 			case SNB_STOLEN_MEMORY_96MB:
237 				memorySize *= 96;
238 				break;
239 			case SNB_STOLEN_MEMORY_128MB:
240 				memorySize *= 128;
241 				break;
242 			case SNB_STOLEN_MEMORY_160MB:
243 				memorySize *= 160;
244 				break;
245 			case SNB_STOLEN_MEMORY_192MB:
246 				memorySize *= 192;
247 				break;
248 			case SNB_STOLEN_MEMORY_224MB:
249 				memorySize *= 224;
250 				break;
251 			case SNB_STOLEN_MEMORY_256MB:
252 				memorySize *= 256;
253 				break;
254 			case SNB_STOLEN_MEMORY_288MB:
255 				memorySize *= 288;
256 				break;
257 			case SNB_STOLEN_MEMORY_320MB:
258 				memorySize *= 320;
259 				break;
260 			case SNB_STOLEN_MEMORY_352MB:
261 				memorySize *= 352;
262 				break;
263 			case SNB_STOLEN_MEMORY_384MB:
264 				memorySize *= 384;
265 				break;
266 			case SNB_STOLEN_MEMORY_416MB:
267 				memorySize *= 416;
268 				break;
269 			case SNB_STOLEN_MEMORY_448MB:
270 				memorySize *= 448;
271 				break;
272 			case SNB_STOLEN_MEMORY_480MB:
273 				memorySize *= 480;
274 				break;
275 			case SNB_STOLEN_MEMORY_512MB:
276 				memorySize *= 512;
277 				break;
278 		}
279 	} else if (info.type->InGroup(INTEL_GROUP_85x)
280 		|| info.type->InFamily(INTEL_FAMILY_9xx)
281         || info.type->InFamily(INTEL_FAMILY_SER5)
282         || info.type->InFamily(INTEL_FAMILY_SOC0)
283         || info.type->InFamily(INTEL_FAMILY_POVR)) {
284 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
285 			case i855_STOLEN_MEMORY_4M:
286 				memorySize *= 4;
287 				break;
288 			case i855_STOLEN_MEMORY_8M:
289 				memorySize *= 8;
290 				break;
291 			case i855_STOLEN_MEMORY_16M:
292 				memorySize *= 16;
293 				break;
294 			case i855_STOLEN_MEMORY_32M:
295 				memorySize *= 32;
296 				break;
297 			case i855_STOLEN_MEMORY_48M:
298 				memorySize *= 48;
299 				break;
300 			case i855_STOLEN_MEMORY_64M:
301 				memorySize *= 64;
302 				break;
303 			case i855_STOLEN_MEMORY_128M:
304 				memorySize *= 128;
305 				break;
306 			case i855_STOLEN_MEMORY_256M:
307 				memorySize *= 256;
308 				break;
309 			case G4X_STOLEN_MEMORY_96MB:
310 				memorySize *= 96;
311 				break;
312 			case G4X_STOLEN_MEMORY_160MB:
313 				memorySize *= 160;
314 				break;
315 			case G4X_STOLEN_MEMORY_224MB:
316 				memorySize *= 224;
317 				break;
318 			case G4X_STOLEN_MEMORY_352MB:
319 				memorySize *= 352;
320 				break;
321 		}
322 	} else {
323 		// TODO: error out!
324 		memorySize = 4096;
325 	}
326 	return memorySize - 4096;
327 }
328 
329 
330 static size_t
331 determine_gtt_size(intel_info &info)
332 {
333 	uint16 memoryConfig = gtt_memory_config(info);
334 	size_t gttSize = 0;
335 
336 	if (info.type->IsModel(INTEL_MODEL_965)) {
337 		switch (memoryConfig & i965_GTT_MASK) {
338 			case i965_GTT_128K:
339 				gttSize = 128 << 10;
340 				break;
341 			case i965_GTT_256K:
342 				gttSize = 256 << 10;
343 				break;
344 			case i965_GTT_512K:
345 				gttSize = 512 << 10;
346 				break;
347 		}
348 	} else if (info.type->IsModel(INTEL_MODEL_G33)
349 	           || info.type->InGroup(INTEL_GROUP_PIN)) {
350 		switch (memoryConfig & G33_GTT_MASK) {
351 			case G33_GTT_1M:
352 				gttSize = 1 << 20;
353 				break;
354 			case G33_GTT_2M:
355 				gttSize = 2 << 20;
356 				break;
357 		}
358 	} else if (info.type->InGroup(INTEL_GROUP_G4x)
359 			|| info.type->InGroup(INTEL_GROUP_ILK)) {
360 		switch (memoryConfig & G4X_GTT_MASK) {
361 			case G4X_GTT_NONE:
362 				gttSize = 0;
363 				break;
364 			case G4X_GTT_1M_NO_IVT:
365 				gttSize = 1 << 20;
366 				break;
367 			case G4X_GTT_2M_NO_IVT:
368 			case G4X_GTT_2M_IVT:
369 				gttSize = 2 << 20;
370 				break;
371 			case G4X_GTT_3M_IVT:
372 				gttSize = 3 << 20;
373 				break;
374 			case G4X_GTT_4M_IVT:
375 				gttSize = 4 << 20;
376 				break;
377 		}
378 	} else if (info.type->InGroup(INTEL_GROUP_SNB)) {
379 		switch (memoryConfig & SNB_GTT_SIZE_MASK) {
380 			case SNB_GTT_SIZE_NONE:
381 				gttSize = 0;
382 				break;
383 			case SNB_GTT_SIZE_1MB:
384 				gttSize = 1 << 20;
385 				break;
386 			case SNB_GTT_SIZE_2MB:
387 				gttSize = 2 << 20;
388 				break;
389 		}
390 	} else {
391 		// older models have the GTT as large as their frame buffer mapping
392 		// TODO: check if the i9xx version works with the i8xx chips as well
393 		size_t frameBufferSize = 0;
394 		if (info.type->InFamily(INTEL_FAMILY_8xx)) {
395 			if (info.type->InGroup(INTEL_GROUP_83x)
396 				&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
397 				frameBufferSize = 64 << 20;
398 			else
399 				frameBufferSize = 128 << 20;
400 		} else if (info.type->Generation() >= 3) {
401 			frameBufferSize = info.display.u.h0.base_register_sizes[2];
402 		}
403 
404 		TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
405 		gttSize = frameBufferSize / 1024;
406 	}
407 	return gttSize;
408 }
409 
410 
411 static void
412 set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
413 {
414 	if (info.type->Generation() >= 8) {
415 		// CHV + BXT
416 		physicalAddress |= (physicalAddress >> 28) & 0x07f0;
417 		// TODO: cache control?
418 	} else if (info.type->Generation() >= 6) {
419 		// SandyBridge, IronLake, IvyBridge, Haswell
420 		physicalAddress |= (physicalAddress >> 28) & 0x0ff0;
421 		physicalAddress |= 0x02; // cache control, l3 cacheable
422 	} else if (info.type->Generation() >= 4) {
423 		// Intel 9xx minus 91x, 94x, G33
424 		// possible high bits are stored in the lower end
425 		physicalAddress |= (physicalAddress >> 28) & 0x00f0;
426 		// TODO: cache control?
427 	}
428 
429 	// TODO: this is not 64-bit safe!
430 	write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
431 		(uint32)physicalAddress | GTT_ENTRY_VALID);
432 }
433 
434 
435 static void
436 intel_unmap(intel_info &info)
437 {
438 	delete_area(info.registers_area);
439 	delete_area(info.gtt_area);
440 	delete_area(info.scratch_area);
441 	delete_area(info.aperture_area);
442 	info.aperture_size = 0;
443 }
444 
445 
446 static status_t
447 intel_map(intel_info &info)
448 {
449 	int fbIndex = 0;
450 	int mmioIndex = 1;
451 	if (info.type->Generation() >= 3) {
452 		// for some reason Intel saw the need to change the order of the
453 		// mappings with the introduction of the i9xx family
454 		mmioIndex = 0;
455 		fbIndex = 2;
456 	}
457 
458 	AreaKeeper mmioMapper;
459 	info.registers_area = mmioMapper.Map("intel GMCH mmio",
460 		info.display.u.h0.base_registers[mmioIndex],
461 		info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS,
462 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.registers);
463 
464 	if (mmioMapper.InitCheck() < B_OK) {
465 		ERROR("could not map memory I/O!\n");
466 		return info.registers_area;
467 	}
468 
469 	// make sure bus master, memory-mapped I/O, and frame buffer is enabled
470 	set_pci_config(info.display, PCI_command, 2,
471 		get_pci_config(info.display, PCI_command, 2)
472 			| PCI_command_io | PCI_command_memory | PCI_command_master);
473 
474 	void* scratchAddress;
475 	AreaKeeper scratchCreator;
476 	info.scratch_area = scratchCreator.Create("intel GMCH scratch",
477 		&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
478 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
479 	if (scratchCreator.InitCheck() < B_OK) {
480 		ERROR("could not create scratch page!\n");
481 		return info.scratch_area;
482 	}
483 
484 	physical_entry entry;
485 	if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
486 		return B_ERROR;
487 
488 	// TODO: Review these
489 	if (info.type->InFamily(INTEL_FAMILY_8xx)) {
490 		info.gtt_physical_base = read32(info.registers
491 			+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
492 		if (info.gtt_physical_base == 0) {
493 			// TODO: not sure how this is supposed to work under Linux/FreeBSD,
494 			// but on my i865, this code is needed for Haiku.
495 			ERROR("Use GTT address fallback.\n");
496 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
497 				+ i830_GTT_BASE;
498 		}
499 	} else if (info.type->InGroup(INTEL_GROUP_91x)) {
500 		info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4);
501 	} else {
502 		// 945+?
503 		info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
504 			+ (2UL << 20);
505 	}
506 
507 	size_t gttSize = determine_gtt_size(info);
508 	size_t stolenSize = determine_gtt_stolen(info);
509 
510 	info.gtt_entries = gttSize / 4096;
511 	info.gtt_stolen_entries = stolenSize / 4096;
512 
513 	TRACE("GTT base %" B_PRIxPHYSADDR ", size %lu, entries %lu, stolen %lu\n",
514 		info.gtt_physical_base, gttSize, info.gtt_entries, stolenSize);
515 
516 	AreaKeeper gttMapper;
517 	info.gtt_area = gttMapper.Map("intel GMCH gtt",
518 		info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
519 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.gtt_base);
520 	if (gttMapper.InitCheck() < B_OK) {
521 		ERROR("could not map GTT!\n");
522 		return info.gtt_area;
523 	}
524 
525 	info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex];
526 	info.aperture_stolen_size = stolenSize;
527 	if (info.aperture_size == 0)
528 		info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
529 
530 	ERROR("detected %ld MB of stolen memory, aperture size %ld MB, "
531 		"GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
532 		info.aperture_size >> 20, gttSize >> 10);
533 
534 	ERROR("GTT base = 0x%" B_PRIxPHYSADDR "\n", info.gtt_physical_base);
535 	ERROR("MMIO base = 0x%" B_PRIx32 "\n",
536 		info.display.u.h0.base_registers[mmioIndex]);
537 	ERROR("GMR base = 0x%" B_PRIxPHYSADDR "\n", info.aperture_physical_base);
538 
539 	AreaKeeper apertureMapper;
540 	info.aperture_area = apertureMapper.Map("intel graphics aperture",
541 		info.aperture_physical_base, info.aperture_size,
542 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
543 		B_READ_AREA | B_WRITE_AREA, (void**)&info.aperture_base);
544 	if (apertureMapper.InitCheck() < B_OK) {
545 		// try again without write combining
546 		ERROR("enabling write combined mode failed.\n");
547 
548 		info.aperture_area = apertureMapper.Map("intel graphics aperture",
549 			info.aperture_physical_base, info.aperture_size,
550 			B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA,
551 			(void**)&info.aperture_base);
552 	}
553 	if (apertureMapper.InitCheck() < B_OK) {
554 		ERROR("could not map graphics aperture!\n");
555 		return info.aperture_area;
556 	}
557 
558 	info.scratch_page = entry.address;
559 
560 	gttMapper.Detach();
561 	mmioMapper.Detach();
562 	scratchCreator.Detach();
563 	apertureMapper.Detach();
564 
565 	return B_OK;
566 }
567 
568 
569 //	#pragma mark - module interface
570 
571 
572 status_t
573 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
574 	void** _aperture)
575 {
576 	// TODO: we currently only support a single AGP bridge!
577 	if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device
578 			|| function != sInfo.bridge.function)
579 		&& (bus != sInfo.display.bus || device != sInfo.display.device
580 			|| function != sInfo.display.function))
581 		return B_BAD_VALUE;
582 
583 	sInfo.aperture_size = size;
584 
585 	if (intel_map(sInfo) < B_OK)
586 		return B_ERROR;
587 
588 	uint16 gmchControl = get_pci_config(sInfo.bridge,
589 		INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED;
590 	set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl);
591 
592 	write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL,
593 		sInfo.gtt_physical_base | PAGE_TABLE_ENABLED);
594 	read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL);
595 
596 	if (sInfo.scratch_page != 0) {
597 		for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) {
598 			set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page);
599 		}
600 		read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
601 	}
602 
603 	asm("wbinvd;");
604 
605 	*_aperture = NULL;
606 	return B_OK;
607 }
608 
609 
610 void
611 intel_delete_aperture(void* aperture)
612 {
613 	intel_unmap(sInfo);
614 }
615 
616 
617 static status_t
618 intel_get_aperture_info(void* aperture, aperture_info* info)
619 {
620 	if (info == NULL)
621 		return B_BAD_VALUE;
622 
623 	info->base = sInfo.aperture_base;
624 	info->physical_base = sInfo.aperture_physical_base;
625 	info->size = sInfo.aperture_size;
626 	info->reserved_size = sInfo.aperture_stolen_size;
627 
628 	return B_OK;
629 }
630 
631 
632 status_t
633 intel_set_aperture_size(void* aperture, size_t size)
634 {
635 	return B_ERROR;
636 }
637 
638 
639 static status_t
640 intel_bind_page(void* aperture, uint32 offset, phys_addr_t physicalAddress)
641 {
642 	//TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress);
643 
644 	set_gtt_entry(sInfo, offset, physicalAddress);
645 	return B_OK;
646 }
647 
648 
649 static status_t
650 intel_unbind_page(void* aperture, uint32 offset)
651 {
652 	//TRACE("unbind_page(offset %lx)\n", offset);
653 
654 	if (sInfo.scratch_page != 0)
655 		set_gtt_entry(sInfo, offset, sInfo.scratch_page);
656 
657 	return B_OK;
658 }
659 
660 
661 void
662 intel_flush_tlbs(void* aperture)
663 {
664 	read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
665 	asm("wbinvd;");
666 }
667 
668 
669 //	#pragma mark -
670 
671 
672 static status_t
673 intel_init()
674 {
675 	TRACE("bus manager init\n");
676 
677 	if (get_module(B_PCI_MODULE_NAME, (module_info**)&sPCI) != B_OK)
678 		return B_ERROR;
679 
680 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK;
681 			index++) {
682 		if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL
683 			|| sInfo.bridge.class_base != PCI_bridge)
684 			continue;
685 
686 		// check device
687 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
688 				/ sizeof(kSupportedDevices[0]); i++) {
689 			if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
690 				sInfo.type = new DeviceType(kSupportedDevices[i].type);
691 				if (has_display_device(sInfo.display,
692 						kSupportedDevices[i].display_id)) {
693 					TRACE("found intel bridge\n");
694 					return B_OK;
695 				}
696 			}
697 		}
698 	}
699 
700 	return ENODEV;
701 }
702 
703 
704 static void
705 intel_uninit()
706 {
707 	if (sInfo.type)
708 		delete sInfo.type;
709 }
710 
711 
712 static int32
713 intel_std_ops(int32 op, ...)
714 {
715 	switch (op) {
716 		case B_MODULE_INIT:
717 			return intel_init();
718 		case B_MODULE_UNINIT:
719 			intel_uninit();
720 			return B_OK;
721 	}
722 
723 	return B_BAD_VALUE;
724 }
725 
726 
727 static struct agp_gart_bus_module_info sIntelModuleInfo = {
728 	{
729 		"busses/agp_gart/intel/v0",
730 		0,
731 		intel_std_ops
732 	},
733 
734 	intel_create_aperture,
735 	intel_delete_aperture,
736 
737 	intel_get_aperture_info,
738 	intel_set_aperture_size,
739 	intel_bind_page,
740 	intel_unbind_page,
741 	intel_flush_tlbs
742 };
743 
744 module_info* modules[] = {
745 	(module_info*)&sIntelModuleInfo,
746 	NULL
747 };
748