xref: /haiku/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
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 #if 0
120 	// XXX: 0x0f00 only confirmed on 0x0f30, 0x0f31
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 #endif
126 
127 	// XXX: 0x1604 only confirmed on 0x1616
128 	{0x1604, 0x1606, INTEL_MODEL_BDWM, "Broadwell GT1 ULT"},
129 	{0x1604, 0x160b, INTEL_MODEL_BDWM, "Broadwell GT1 Iris"},
130 	{0x1604, 0x160e, INTEL_MODEL_BDWM, "Broadwell GT1 ULX"},
131 	{0x1604, 0x1602, INTEL_MODEL_BDWM, "Broadwell GT1 ULT"},
132 	{0x1604, 0x160a, INTEL_MODEL_BDWS, "Broadwell GT1 Server"},
133 	{0x1604, 0x160d, INTEL_MODEL_BDW,  "Broadwell GT1 Workstation"},
134 	{0x1604, 0x1616, INTEL_MODEL_BDWM, "Broadwell GT2 ULT"},
135 	{0x1604, 0x161b, INTEL_MODEL_BDWM, "Broadwell GT2 ULT"},
136 	{0x1604, 0x161e, INTEL_MODEL_BDWM, "Broadwell GT2 ULX"},
137 	{0x1604, 0x1612, INTEL_MODEL_BDWM, "Broadwell GT2 Halo"},
138 	{0x1604, 0x161a, INTEL_MODEL_BDWS, "Broadwell GT2 Server"},
139 	{0x1604, 0x161d, INTEL_MODEL_BDW,  "Broadwell GT2 Workstation"},
140 	{0x1604, 0x1626, INTEL_MODEL_BDWM, "Broadwell GT3 ULT"},
141 	{0x1604, 0x162b, INTEL_MODEL_BDWM, "Broadwell GT3 Iris"},
142 	{0x1604, 0x162e, INTEL_MODEL_BDWM, "Broadwell GT3 ULX"},
143 	{0x1604, 0x1622, INTEL_MODEL_BDWM, "Broadwell GT3 ULT"},
144 	{0x1604, 0x162a, INTEL_MODEL_BDWS, "Broadwell GT3 Server"},
145 	{0x1604, 0x162d, INTEL_MODEL_BDW,  "Broadwell GT3 Workstation"},
146 
147 	// XXX: 0x1904 only confirmed on 0x1916
148 	{0x1904, 0x1902, INTEL_MODEL_SKY,  "Skylake GT1"},
149 	{0x1904, 0x1906, INTEL_MODEL_SKYM, "Skylake GT1"},
150 	{0x1904, 0x190a, INTEL_MODEL_SKYS, "Skylake GT1"},
151 	{0x1904, 0x190b, INTEL_MODEL_SKY,  "Skylake GT1"},
152 	{0x1904, 0x190e, INTEL_MODEL_SKYM, "Skylake GT1"},
153 	{0x191f, 0x1912, INTEL_MODEL_SKY,  "Skylake GT2"}, // confirmed
154 	{0x1904, 0x1916, INTEL_MODEL_SKYM, "Skylake GT2"},
155 	{0x1904, 0x191a, INTEL_MODEL_SKYS, "Skylake GT2"},
156 	{0x1904, 0x191b, INTEL_MODEL_SKY,  "Skylake GT2"},
157 	{0x1904, 0x191d, INTEL_MODEL_SKY,  "Skylake GT2"},
158 	{0x1904, 0x191e, INTEL_MODEL_SKYM, "Skylake GT2"},
159 	{0x1904, 0x1921, INTEL_MODEL_SKYM, "Skylake GT2F"},
160 	{0x1904, 0x1926, INTEL_MODEL_SKYM, "Skylake GT3"},
161 	{0x1904, 0x192a, INTEL_MODEL_SKYS, "Skylake GT3"},
162 	{0x1904, 0x192b, INTEL_MODEL_SKY,  "Skylake GT3"},
163 
164 	{0x5904, 0x5906, INTEL_MODEL_KBY,  "Kabylake ULT GT1"},
165 	{0x590f, 0x5902, INTEL_MODEL_KBY,  "Kabylake DT GT1"},
166 	{0x5904, 0x5916, INTEL_MODEL_KBYM, "Kabylake ULT GT2"},
167 	{0x590c, 0x5916, INTEL_MODEL_KBYM, "Kabylake ULT GT2"},
168 	{0x5904, 0x5921, INTEL_MODEL_KBYM, "Kabylake ULT GT2F"},
169 	{0x590c, 0x591c, INTEL_MODEL_KBY,  "Kabylake ULX GT2"},
170 	{0x590c, 0x591e, INTEL_MODEL_KBY,  "Kabylake ULX GT2"},
171 	{0x591f, 0x5912, INTEL_MODEL_KBY,  "Kabylake DT GT2"},
172 	{0x5914, 0x5917, INTEL_MODEL_KBYM, "Kabylake Mobile GT2"},
173 	{0x5910, 0x591b, INTEL_MODEL_KBYM, "Kabylake Halo GT2"},
174 	{0x5918, 0x591d, INTEL_MODEL_KBY,  "Kabylake WKS GT2"},
175 	{0x5904, 0x5926, INTEL_MODEL_KBY,  "Kabylake ULT GT3"},
176 	{0x5904, 0x5927, INTEL_MODEL_KBY,  "Kabylake ULT GT3"},
177 
178 	{0x3e0f, 0x3e90, INTEL_MODEL_CFL,  "CoffeeLake GT1"},
179 	{0x3e0f, 0x3e93, INTEL_MODEL_CFL,  "CoffeeLake GT1"},
180 	{0x3e1f, 0x3e91, INTEL_MODEL_CFL,  "CoffeeLake GT2"},
181 	{0x3ec2, 0x3e92, INTEL_MODEL_CFL,  "CoffeeLake GT2"},
182 	{0x3e18, 0x3e96, INTEL_MODEL_CFL,  "CoffeeLake GT2"},
183 	{0x3e30, 0x3e98, INTEL_MODEL_CFL,  "CoffeeLake GT2"},
184 	{0x3e31, 0x3e9a, INTEL_MODEL_CFL,  "CoffeeLake GT2"},
185 	{0x3ec4, 0x3e9b, INTEL_MODEL_CFLM, "CoffeeLake Halo GT2"},
186 	{0x3e10, 0x3eab, INTEL_MODEL_CFLM, "CoffeeLake Halo GT2"},
187 	{0x3ec4, 0x3eab, INTEL_MODEL_CFLM, "CoffeeLake Halo GT2"},
188 	{0x3ed0, 0x3ea5, INTEL_MODEL_CFL,  "CoffeeLake GT3"},
189 	{0x3ed0, 0x3ea6, INTEL_MODEL_CFL,  "CoffeeLake GT3"},
190 
191 	{0x9b64, 0x9ba4, INTEL_MODEL_CML,	"CometLake GT1"},
192 	{0x9b73, 0x9ba8, INTEL_MODEL_CML,	"CometLake GT1"},
193 	{0x9b71, 0x9b21, INTEL_MODEL_CMLM,	"CometLake U GT1"},
194 	{0x9b71, 0x9baa, INTEL_MODEL_CMLM,	"CometLake U GT1"},
195 	{0x9b54, 0x9bc4, INTEL_MODEL_CML,	"CometLake GT2"},
196 	{0x9b43, 0x9bc5, INTEL_MODEL_CML,	"CometLake GT2"},
197 	{0x9b53, 0x9bc5, INTEL_MODEL_CML,	"CometLake GT2"},
198 	{0x9b33, 0x9bc6, INTEL_MODEL_CML,	"CometLake GT2"},
199 	{0x9b53, 0x9bc8, INTEL_MODEL_CML,	"CometLake GT2"},
200 	{0x9b63, 0x9bc8, INTEL_MODEL_CML,	"CometLake GT2"},
201 	{0x9b53, 0x9be6, INTEL_MODEL_CML,	"CometLake GT2"},
202 	{0x9b44, 0x9bf6, INTEL_MODEL_CML,	"CometLake GT2"},
203 	{0x9b54, 0x9bf6, INTEL_MODEL_CML,	"CometLake GT2"},
204 	{0x9b61, 0x9b41, INTEL_MODEL_CMLM,	"CometLake U GT2"},
205 	{0x9b51, 0x9bca, INTEL_MODEL_CMLM,	"CometLake U GT2"},
206 	{0x9b61, 0x9bca, INTEL_MODEL_CMLM,	"CometLake U GT2"},
207 	{0x9b51, 0x9bcc, INTEL_MODEL_CMLM,	"CometLake U GT2"},
208 
209 	{0x4e22, 0x4e55, INTEL_MODEL_JSL, "JasperLake"},
210 	{0x4e24, 0x4e55, INTEL_MODEL_JSL, "JasperLake"},
211 	{0x4e12, 0x4e61, INTEL_MODEL_JSL, "JasperLake"},
212 	{0x4e26, 0x4e71, INTEL_MODEL_JSLM, "JasperLake"},
213 	{0x4e28, 0x4e71, INTEL_MODEL_JSLM, "JasperLake"},
214 
215 	{0x9a14, 0x9a49, INTEL_MODEL_TGLM, "TigerLake-LP GT2"},
216 };
217 
218 struct intel_info {
219 	pci_info	bridge;
220 	pci_info	display;
221 	DeviceType*	type;
222 
223 	uint32*		gtt_base;
224 	phys_addr_t	gtt_physical_base;
225 	area_id		gtt_area;
226 	size_t		gtt_entries;
227 	size_t		gtt_stolen_entries;
228 
229 	vuint32*	registers;
230 	area_id		registers_area;
231 
232 	addr_t		aperture_base;
233 	phys_addr_t	aperture_physical_base;
234 	area_id		aperture_area;
235 	size_t		aperture_size;
236 	size_t		aperture_stolen_size;
237 
238 	phys_addr_t	scratch_page;
239 	area_id		scratch_area;
240 };
241 
242 static intel_info sInfo;
243 static pci_module_info* sPCI;
244 
245 
246 static bool
247 has_display_device(pci_info &info, uint32 deviceID)
248 {
249 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK;
250 			index++) {
251 		if (info.vendor_id != VENDOR_ID_INTEL
252 			|| info.device_id != deviceID
253 			|| info.class_base != PCI_display)
254 			continue;
255 
256 		return true;
257 	}
258 
259 	return false;
260 }
261 
262 
263 static uint16
264 gtt_memory_config(intel_info &info)
265 {
266 	uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL;
267 	if (info.type->Generation() >= 6)
268 		controlRegister = SNB_GRAPHICS_MEMORY_CONTROL;
269 
270 	return get_pci_config(info.bridge, controlRegister, 2);
271 }
272 
273 
274 static size_t
275 determine_gtt_stolen(intel_info &info)
276 {
277 	uint16 memoryConfig = gtt_memory_config(info);
278 	size_t memorySize = 1 << 20; // 1 MB
279 
280 	if (info.type->InGroup(INTEL_GROUP_83x)) {
281 		// Older chips
282 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
283 			case i830_LOCAL_MEMORY_ONLY:
284 				// TODO: determine its size!
285 				ERROR("getting local memory size not implemented.\n");
286 				break;
287 			case i830_STOLEN_512K:
288 				memorySize >>= 1;
289 				break;
290 			case i830_STOLEN_1M:
291 				// default case
292 				break;
293 			case i830_STOLEN_8M:
294 				memorySize *= 8;
295 				break;
296 		}
297 	} else if (info.type->InGroup(INTEL_GROUP_SNB)
298 		|| info.type->InGroup(INTEL_GROUP_IVB)
299 		|| info.type->InGroup(INTEL_GROUP_HAS)) {
300 		switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) {
301 			case SNB_STOLEN_MEMORY_32MB:
302 				memorySize *= 32;
303 				break;
304 			case SNB_STOLEN_MEMORY_64MB:
305 				memorySize *= 64;
306 				break;
307 			case SNB_STOLEN_MEMORY_96MB:
308 				memorySize *= 96;
309 				break;
310 			case SNB_STOLEN_MEMORY_128MB:
311 				memorySize *= 128;
312 				break;
313 			case SNB_STOLEN_MEMORY_160MB:
314 				memorySize *= 160;
315 				break;
316 			case SNB_STOLEN_MEMORY_192MB:
317 				memorySize *= 192;
318 				break;
319 			case SNB_STOLEN_MEMORY_224MB:
320 				memorySize *= 224;
321 				break;
322 			case SNB_STOLEN_MEMORY_256MB:
323 				memorySize *= 256;
324 				break;
325 			case SNB_STOLEN_MEMORY_288MB:
326 				memorySize *= 288;
327 				break;
328 			case SNB_STOLEN_MEMORY_320MB:
329 				memorySize *= 320;
330 				break;
331 			case SNB_STOLEN_MEMORY_352MB:
332 				memorySize *= 352;
333 				break;
334 			case SNB_STOLEN_MEMORY_384MB:
335 				memorySize *= 384;
336 				break;
337 			case SNB_STOLEN_MEMORY_416MB:
338 				memorySize *= 416;
339 				break;
340 			case SNB_STOLEN_MEMORY_448MB:
341 				memorySize *= 448;
342 				break;
343 			case SNB_STOLEN_MEMORY_480MB:
344 				memorySize *= 480;
345 				break;
346 			case SNB_STOLEN_MEMORY_512MB:
347 				memorySize *= 512;
348 				break;
349 		}
350 	} else if (info.type->InGroup(INTEL_GROUP_BDW)
351 		|| info.type->InFamily(INTEL_FAMILY_LAKE)) {
352 		switch (memoryConfig & BDW_STOLEN_MEMORY_MASK) {
353 			case BDW_STOLEN_MEMORY_32MB:
354 				memorySize *= 32;
355 				break;
356 			case BDW_STOLEN_MEMORY_64MB:
357 				memorySize *= 64;
358 				break;
359 			case BDW_STOLEN_MEMORY_96MB:
360 				memorySize *= 96;
361 				break;
362 			case BDW_STOLEN_MEMORY_128MB:
363 				memorySize *= 128;
364 				break;
365 			case BDW_STOLEN_MEMORY_160MB:
366 				memorySize *= 160;
367 				break;
368 			case BDW_STOLEN_MEMORY_192MB:
369 				memorySize *= 192;
370 				break;
371 			case BDW_STOLEN_MEMORY_224MB:
372 				memorySize *= 224;
373 				break;
374 			case BDW_STOLEN_MEMORY_256MB:
375 				memorySize *= 256;
376 				break;
377 			case BDW_STOLEN_MEMORY_288MB:
378 				memorySize *= 288;
379 				break;
380 			case BDW_STOLEN_MEMORY_320MB:
381 				memorySize *= 320;
382 				break;
383 			case BDW_STOLEN_MEMORY_352MB:
384 				memorySize *= 352;
385 				break;
386 			case BDW_STOLEN_MEMORY_384MB:
387 				memorySize *= 384;
388 				break;
389 			case BDW_STOLEN_MEMORY_416MB:
390 				memorySize *= 416;
391 				break;
392 			case BDW_STOLEN_MEMORY_448MB:
393 				memorySize *= 448;
394 				break;
395 			case BDW_STOLEN_MEMORY_480MB:
396 				memorySize *= 480;
397 				break;
398 			case BDW_STOLEN_MEMORY_512MB:
399 				memorySize *= 512;
400 				break;
401 			case BDW_STOLEN_MEMORY_1024MB:
402 				memorySize *= 1024;
403 				break;
404 			case BDW_STOLEN_MEMORY_1536MB:
405 				memorySize *= 1536;
406 				break;
407 		}
408 		if(info.type->InGroup(INTEL_GROUP_BDW)) {
409 			if((memoryConfig & BDW_STOLEN_MEMORY_MASK) == BDW_STOLEN_MEMORY_2016MB) {
410 				memorySize *= 2016;
411 			}
412 		} else if(info.type->InFamily(INTEL_FAMILY_LAKE)) {
413 			switch(memoryConfig & BDW_STOLEN_MEMORY_MASK) {
414 				case SKL_STOLEN_MEMORY_4MB:
415 					memorySize *= 4;
416 					break;
417 				case SKL_STOLEN_MEMORY_8MB:
418 					memorySize *= 8;
419 					break;
420 				case SKL_STOLEN_MEMORY_12MB:
421 					memorySize *= 12;
422 					break;
423 				case SKL_STOLEN_MEMORY_16MB:
424 					memorySize *= 16;
425 					break;
426 				case SKL_STOLEN_MEMORY_20MB:
427 					memorySize *= 20;
428 					break;
429 				case SKL_STOLEN_MEMORY_24MB:
430 					memorySize *= 24;
431 					break;
432 				case SKL_STOLEN_MEMORY_28MB:
433 					memorySize *= 28;
434 					break;
435 				case SKL_STOLEN_MEMORY_32MB:
436 					memorySize *= 32;
437 					break;
438 				case SKL_STOLEN_MEMORY_36MB:
439 					memorySize *= 36;
440 					break;
441 				case SKL_STOLEN_MEMORY_40MB:
442 					memorySize *= 40;
443 					break;
444 				case SKL_STOLEN_MEMORY_44MB:
445 					memorySize *= 44;
446 					break;
447 				case SKL_STOLEN_MEMORY_48MB:
448 					memorySize *= 48;
449 					break;
450 				case SKL_STOLEN_MEMORY_52MB:
451 					memorySize *= 52;
452 					break;
453 				case SKL_STOLEN_MEMORY_56MB:
454 					memorySize *= 56;
455 					break;
456 				case SKL_STOLEN_MEMORY_60MB:
457 					memorySize *= 60;
458 					break;
459 			}
460 		}
461 	} else if (info.type->InGroup(INTEL_GROUP_85x)
462 		|| info.type->InFamily(INTEL_FAMILY_9xx)
463 		|| info.type->InGroup(INTEL_GROUP_ILK)) {
464 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
465 			case i855_STOLEN_MEMORY_4M:
466 				memorySize *= 4;
467 				break;
468 			case i855_STOLEN_MEMORY_8M:
469 				memorySize *= 8;
470 				break;
471 			case i855_STOLEN_MEMORY_16M:
472 				memorySize *= 16;
473 				break;
474 			case i855_STOLEN_MEMORY_32M:
475 				memorySize *= 32;
476 				break;
477 			case i855_STOLEN_MEMORY_48M:
478 				memorySize *= 48;
479 				break;
480 			case i855_STOLEN_MEMORY_64M:
481 				memorySize *= 64;
482 				break;
483 			case i855_STOLEN_MEMORY_128M:
484 				memorySize *= 128;
485 				break;
486 			case i855_STOLEN_MEMORY_256M:
487 				memorySize *= 256;
488 				break;
489 			case G4X_STOLEN_MEMORY_96MB:
490 				memorySize *= 96;
491 				break;
492 			case G4X_STOLEN_MEMORY_160MB:
493 				memorySize *= 160;
494 				break;
495 			case G4X_STOLEN_MEMORY_224MB:
496 				memorySize *= 224;
497 				break;
498 			case G4X_STOLEN_MEMORY_352MB:
499 				memorySize *= 352;
500 				break;
501 		}
502 	} else {
503 		// TODO: error out!
504 		memorySize = 4096;
505 	}
506 	return memorySize - 4096;
507 }
508 
509 
510 static size_t
511 determine_gtt_size(intel_info &info)
512 {
513 	uint16 memoryConfig = gtt_memory_config(info);
514 	size_t gttSize = 0;
515 
516 	if (info.type->IsModel(INTEL_MODEL_965)) {
517 		switch (memoryConfig & i965_GTT_MASK) {
518 			case i965_GTT_128K:
519 				gttSize = 128 << 10;
520 				break;
521 			case i965_GTT_256K:
522 				gttSize = 256 << 10;
523 				break;
524 			case i965_GTT_512K:
525 				gttSize = 512 << 10;
526 				break;
527 		}
528 	} else if (info.type->IsModel(INTEL_MODEL_G33)
529 	           || info.type->InGroup(INTEL_GROUP_PIN)) {
530 		switch (memoryConfig & G33_GTT_MASK) {
531 			case G33_GTT_1M:
532 				gttSize = 1 << 20;
533 				break;
534 			case G33_GTT_2M:
535 				gttSize = 2 << 20;
536 				break;
537 		}
538 	} else if (info.type->InGroup(INTEL_GROUP_G4x)
539 			|| info.type->InGroup(INTEL_GROUP_ILK)) {
540 		switch (memoryConfig & G4X_GTT_MASK) {
541 			case G4X_GTT_NONE:
542 				gttSize = 0;
543 				break;
544 			case G4X_GTT_1M_NO_IVT:
545 				gttSize = 1 << 20;
546 				break;
547 			case G4X_GTT_2M_NO_IVT:
548 			case G4X_GTT_2M_IVT:
549 				gttSize = 2 << 20;
550 				break;
551 			case G4X_GTT_3M_IVT:
552 				gttSize = 3 << 20;
553 				break;
554 			case G4X_GTT_4M_IVT:
555 				gttSize = 4 << 20;
556 				break;
557 		}
558 	} else if (info.type->InGroup(INTEL_GROUP_SNB)
559 			|| info.type->InGroup(INTEL_GROUP_IVB)
560 			|| info.type->InGroup(INTEL_GROUP_HAS)) {
561 		switch (memoryConfig & SNB_GTT_SIZE_MASK) {
562 			case SNB_GTT_SIZE_NONE:
563 				gttSize = 0;
564 				break;
565 			case SNB_GTT_SIZE_1MB:
566 				gttSize = 1 << 20;
567 				break;
568 			case SNB_GTT_SIZE_2MB:
569 				gttSize = 2 << 20;
570 				break;
571 		}
572 	} else if (info.type->InGroup(INTEL_GROUP_BDW)
573 			|| info.type->InFamily(INTEL_FAMILY_LAKE)) {
574 		switch (memoryConfig & BDW_GTT_SIZE_MASK) {
575 			case BDW_GTT_SIZE_NONE:
576 				gttSize = 0;
577 				break;
578 			case BDW_GTT_SIZE_2MB:
579 				gttSize = 2 << 20;
580 				break;
581 			case BDW_GTT_SIZE_4MB:
582 				gttSize = 4 << 20;
583 				break;
584 			case BDW_GTT_SIZE_8MB:
585 				gttSize = 8 << 20;
586 				break;
587 		}
588 	} else {
589 		// older models have the GTT as large as their frame buffer mapping
590 		// TODO: check if the i9xx version works with the i8xx chips as well
591 		size_t frameBufferSize = 0;
592 		if (info.type->InFamily(INTEL_FAMILY_8xx)) {
593 			if (info.type->InGroup(INTEL_GROUP_83x)
594 				&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
595 				frameBufferSize = 64 << 20;
596 			else
597 				frameBufferSize = 128 << 20;
598 		} else if (info.type->Generation() >= 3) {
599 			frameBufferSize = info.display.u.h0.base_register_sizes[2];
600 		}
601 
602 		TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
603 		gttSize = frameBufferSize / 1024;
604 	}
605 	return gttSize;
606 }
607 
608 
609 static void
610 set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
611 {
612 	if (info.type->Generation() >= 8) {
613 		// CHV + BXT
614 		physicalAddress |= (physicalAddress >> 28) & 0x07f0;
615 		// TODO: cache control?
616 	} else if (info.type->Generation() >= 6) {
617 		// SandyBridge, IronLake, IvyBridge, Haswell
618 		physicalAddress |= (physicalAddress >> 28) & 0x0ff0;
619 		physicalAddress |= 0x02; // cache control, l3 cacheable
620 	} else if (info.type->Generation() >= 4) {
621 		// Intel 9xx minus 91x, 94x, G33
622 		// possible high bits are stored in the lower end
623 		physicalAddress |= (physicalAddress >> 28) & 0x00f0;
624 		// TODO: cache control?
625 	}
626 
627 	// TODO: this is not 64-bit safe!
628 	write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
629 		(uint32)physicalAddress | GTT_ENTRY_VALID);
630 }
631 
632 
633 static void
634 intel_unmap(intel_info &info)
635 {
636 	delete_area(info.registers_area);
637 	delete_area(info.gtt_area);
638 	delete_area(info.scratch_area);
639 	delete_area(info.aperture_area);
640 	info.aperture_size = 0;
641 }
642 
643 
644 static status_t
645 intel_map(intel_info &info)
646 {
647 	int fbIndex = 0;
648 	int mmioIndex = 1;
649 	if (info.type->Generation() >= 3) {
650 		// for some reason Intel saw the need to change the order of the
651 		// mappings with the introduction of the i9xx family
652 		mmioIndex = 0;
653 		fbIndex = 2;
654 	}
655 
656 	phys_addr_t addr = info.display.u.h0.base_registers[mmioIndex];
657 	uint64 barSize = info.display.u.h0.base_register_sizes[mmioIndex];
658 	if ((info.display.u.h0.base_register_flags[mmioIndex] & PCI_address_type) == PCI_address_type_64) {
659 		addr |= (uint64)info.display.u.h0.base_registers[mmioIndex + 1] << 32;
660 		barSize |= (uint64)info.display.u.h0.base_register_sizes[mmioIndex + 1] << 32;
661 	}
662 
663 	AreaKeeper mmioMapper;
664 	info.registers_area = mmioMapper.Map("intel GMCH mmio", addr, barSize,
665 		B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.registers);
666 
667 	if (mmioMapper.InitCheck() < B_OK) {
668 		ERROR("could not map memory I/O!\n");
669 		return info.registers_area;
670 	}
671 
672 	// make sure bus master, memory-mapped I/O, and frame buffer is enabled
673 	set_pci_config(info.display, PCI_command, 2,
674 		get_pci_config(info.display, PCI_command, 2)
675 			| PCI_command_io | PCI_command_memory | PCI_command_master);
676 
677 	void* scratchAddress;
678 	AreaKeeper scratchCreator;
679 	info.scratch_area = scratchCreator.Create("intel GMCH scratch",
680 		&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
681 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
682 	if (scratchCreator.InitCheck() < B_OK) {
683 		ERROR("could not create scratch page!\n");
684 		return info.scratch_area;
685 	}
686 
687 	physical_entry entry;
688 	if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
689 		return B_ERROR;
690 
691 	// TODO: Review these
692 	if (info.type->InFamily(INTEL_FAMILY_8xx)) {
693 		info.gtt_physical_base = read32(info.registers
694 			+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
695 		if (info.gtt_physical_base == 0) {
696 			// TODO: not sure how this is supposed to work under Linux/FreeBSD,
697 			// but on my i865, this code is needed for Haiku.
698 			ERROR("Use GTT address fallback.\n");
699 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
700 				+ i830_GTT_BASE;
701 		}
702 	} else if (info.type->InGroup(INTEL_GROUP_91x)) {
703 		info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4);
704 	} else {
705 		// 945+?
706 		info.gtt_physical_base = addr + (2UL << 20);
707 	}
708 
709 	size_t gttSize = determine_gtt_size(info);
710 	size_t stolenSize = determine_gtt_stolen(info);
711 
712 	info.gtt_entries = gttSize / 4096;
713 	info.gtt_stolen_entries = stolenSize / 4096;
714 
715 	TRACE("GTT base %" B_PRIxPHYSADDR ", size %lu, entries %lu, stolen %lu\n",
716 		info.gtt_physical_base, gttSize, info.gtt_entries, stolenSize);
717 
718 	AreaKeeper gttMapper;
719 	info.gtt_area = gttMapper.Map("intel GMCH gtt",
720 		info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
721 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.gtt_base);
722 	if (gttMapper.InitCheck() < B_OK) {
723 		ERROR("could not map GTT!\n");
724 		return info.gtt_area;
725 	}
726 
727 	info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex];
728 	info.aperture_stolen_size = stolenSize;
729 	if ((info.display.u.h0.base_register_flags[fbIndex] & PCI_address_type) == PCI_address_type_64) {
730 		info.aperture_physical_base |= (uint64)info.display.u.h0.base_registers[fbIndex + 1] << 32;
731 		if (info.aperture_size == 0) {
732 			info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex]
733 				|= (uint64)info.display.u.h0.base_register_sizes[fbIndex + 1] << 32;
734 		}
735 	} else if (info.aperture_size == 0)
736 		info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
737 
738 	ERROR("detected %ld MB of stolen memory, aperture size %ld MB, "
739 		"GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
740 		info.aperture_size >> 20, gttSize >> 10);
741 
742 	ERROR("GTT base = 0x%" B_PRIxPHYSADDR "\n", info.gtt_physical_base);
743 	ERROR("MMIO base = 0x%" B_PRIx32 "\n",
744 		info.display.u.h0.base_registers[mmioIndex]);
745 	ERROR("GMR base = 0x%" B_PRIxPHYSADDR "\n", info.aperture_physical_base);
746 
747 	AreaKeeper apertureMapper;
748 	info.aperture_area = apertureMapper.Map("intel graphics aperture",
749 		info.aperture_physical_base, info.aperture_size,
750 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
751 		B_READ_AREA | B_WRITE_AREA, (void**)&info.aperture_base);
752 	if (apertureMapper.InitCheck() < B_OK) {
753 		// try again without write combining
754 		ERROR("enabling write combined mode failed.\n");
755 
756 		info.aperture_area = apertureMapper.Map("intel graphics aperture",
757 			info.aperture_physical_base, info.aperture_size,
758 			B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA,
759 			(void**)&info.aperture_base);
760 	}
761 	if (apertureMapper.InitCheck() < B_OK) {
762 		ERROR("could not map graphics aperture!\n");
763 		return info.aperture_area;
764 	}
765 
766 	info.scratch_page = entry.address;
767 
768 	gttMapper.Detach();
769 	mmioMapper.Detach();
770 	scratchCreator.Detach();
771 	apertureMapper.Detach();
772 
773 	return B_OK;
774 }
775 
776 
777 //	#pragma mark - module interface
778 
779 
780 status_t
781 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
782 	void** _aperture)
783 {
784 	// TODO: we currently only support a single AGP bridge!
785 	if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device
786 			|| function != sInfo.bridge.function)
787 		&& (bus != sInfo.display.bus || device != sInfo.display.device
788 			|| function != sInfo.display.function))
789 		return B_BAD_VALUE;
790 
791 	sInfo.aperture_size = size;
792 
793 	if (intel_map(sInfo) < B_OK)
794 		return B_ERROR;
795 
796 	uint16 gmchControl = get_pci_config(sInfo.bridge,
797 		INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED;
798 	set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl);
799 
800 	write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL,
801 		sInfo.gtt_physical_base | PAGE_TABLE_ENABLED);
802 	read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL);
803 
804 	if (sInfo.scratch_page != 0) {
805 		for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) {
806 			set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page);
807 		}
808 		read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
809 	}
810 
811 	asm("wbinvd;");
812 
813 	*_aperture = NULL;
814 	return B_OK;
815 }
816 
817 
818 void
819 intel_delete_aperture(void* aperture)
820 {
821 	intel_unmap(sInfo);
822 }
823 
824 
825 static status_t
826 intel_get_aperture_info(void* aperture, aperture_info* info)
827 {
828 	if (info == NULL)
829 		return B_BAD_VALUE;
830 
831 	info->base = sInfo.aperture_base;
832 	info->physical_base = sInfo.aperture_physical_base;
833 	info->size = sInfo.aperture_size;
834 	info->reserved_size = sInfo.aperture_stolen_size;
835 
836 	return B_OK;
837 }
838 
839 
840 status_t
841 intel_set_aperture_size(void* aperture, size_t size)
842 {
843 	return B_ERROR;
844 }
845 
846 
847 static status_t
848 intel_bind_page(void* aperture, uint32 offset, phys_addr_t physicalAddress)
849 {
850 	//TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress);
851 
852 	set_gtt_entry(sInfo, offset, physicalAddress);
853 	return B_OK;
854 }
855 
856 
857 static status_t
858 intel_unbind_page(void* aperture, uint32 offset)
859 {
860 	//TRACE("unbind_page(offset %lx)\n", offset);
861 
862 	if (sInfo.scratch_page != 0)
863 		set_gtt_entry(sInfo, offset, sInfo.scratch_page);
864 
865 	return B_OK;
866 }
867 
868 
869 void
870 intel_flush_tlbs(void* aperture)
871 {
872 	read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
873 	asm("wbinvd;");
874 }
875 
876 
877 //	#pragma mark -
878 
879 
880 static status_t
881 intel_init()
882 {
883 	TRACE("bus manager init\n");
884 
885 	if (get_module(B_PCI_MODULE_NAME, (module_info**)&sPCI) != B_OK)
886 		return B_ERROR;
887 
888 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK;
889 			index++) {
890 		if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL
891 			|| sInfo.bridge.class_base != PCI_bridge)
892 			continue;
893 
894 		// check device
895 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
896 				/ sizeof(kSupportedDevices[0]); i++) {
897 			if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
898 				sInfo.type = new DeviceType(kSupportedDevices[i].type);
899 				if (has_display_device(sInfo.display,
900 						kSupportedDevices[i].display_id)) {
901 					TRACE("found intel bridge\n");
902 					return B_OK;
903 				}
904 			}
905 		}
906 	}
907 
908 	return ENODEV;
909 }
910 
911 
912 static void
913 intel_uninit()
914 {
915 	if (sInfo.type)
916 		delete sInfo.type;
917 }
918 
919 
920 static int32
921 intel_std_ops(int32 op, ...)
922 {
923 	switch (op) {
924 		case B_MODULE_INIT:
925 			return intel_init();
926 		case B_MODULE_UNINIT:
927 			intel_uninit();
928 			return B_OK;
929 	}
930 
931 	return B_BAD_VALUE;
932 }
933 
934 
935 static struct agp_gart_bus_module_info sIntelModuleInfo = {
936 	{
937 		"busses/agp_gart/intel/v0",
938 		0,
939 		intel_std_ops
940 	},
941 
942 	intel_create_aperture,
943 	intel_delete_aperture,
944 
945 	intel_get_aperture_info,
946 	intel_set_aperture_size,
947 	intel_bind_page,
948 	intel_unbind_page,
949 	intel_flush_tlbs
950 };
951 
952 module_info* modules[] = {
953 	(module_info*)&sIntelModuleInfo,
954 	NULL
955 };
956