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