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