xref: /haiku/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp (revision a6e73cb9e8addfe832c064bfcb68067f1c2fa3eb)
1 /*
2  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <AreaKeeper.h>
8 #include <intel_extreme.h>
9 
10 #include <stdlib.h>
11 
12 #include <AGP.h>
13 #include <KernelExport.h>
14 #include <PCI.h>
15 
16 
17 //#define TRACE_INTEL
18 #ifdef TRACE_INTEL
19 #	define TRACE(x...) dprintf("\33[33magp-intel:\33[0m " x)
20 #else
21 #	define TRACE(x...) ;
22 #endif
23 
24 #ifndef __HAIKU__
25 #	define B_KERNEL_READ_AREA	0
26 #	define B_KERNEL_WRITE_AREA	0
27 #endif
28 
29 /* read and write to PCI config space */
30 #define get_pci_config(info, offset, size) \
31 	(sPCI->read_pci_config((info).bus, (info).device, (info).function, \
32 		(offset), (size)))
33 #define set_pci_config(info, offset, size, value) \
34 	(sPCI->write_pci_config((info).bus, (info).device, (info).function, \
35 		(offset), (size), (value)))
36 #define write32(address, data) \
37 	(*((volatile uint32 *)(address)) = (data))
38 #define read32(address) \
39 	(*((volatile uint32 *)(address)))
40 
41 
42 const struct supported_device {
43 	uint32		bridge_id;
44 	uint32		display_id;
45 	uint32		type;
46 	const char	*name;
47 } kSupportedDevices[] = {
48 	{0x3575, 0x3577, INTEL_TYPE_83x, "i830GM"},
49 	{0x2560, 0x2562, INTEL_TYPE_83x, "i845G"},
50 	{0x3580, 0x3582, INTEL_TYPE_85x, "i855G"},
51 	{0x358c, 0x358e, INTEL_TYPE_85x, "i855G"},
52 	{0x2570, 0x2572, INTEL_TYPE_85x, "i865G"},
53 
54 //	{0x2792, INTEL_TYPE_91x, "i910"},
55 //	{0x258a, INTEL_TYPE_91x, "i915"},
56 	{0x2580, 0x2582, INTEL_TYPE_915, "i915G"},
57 	{0x2590, 0x2592, INTEL_TYPE_915M, "i915GM"},
58 	{0x2770, 0x2772, INTEL_TYPE_945, "i945G"},
59 	{0x27a0, 0x27a2, INTEL_TYPE_945M, "i945GM"},
60 	{0x27ac, 0x27ae, INTEL_TYPE_945M, "i945GME"},
61 
62 	{0x2970, 0x2972, INTEL_TYPE_965, "i946GZ"},
63 	{0x2980, 0x2982, INTEL_TYPE_965, "G35"},
64 	{0x2990, 0x2992, INTEL_TYPE_965, "i965Q"},
65 	{0x29a0, 0x29a2, INTEL_TYPE_965, "i965G"},
66 	{0x2a00, 0x2a02, INTEL_TYPE_965, "i965GM"},
67 	{0x2a10, 0x2a12, INTEL_TYPE_965, "i965GME"},
68 
69 	{0x29b0, 0x29b2, INTEL_TYPE_G33, "G33"},
70 	{0x29c0, 0x29c2, INTEL_TYPE_G33, "Q35"},
71 	{0x29d0, 0x29d2, INTEL_TYPE_G33, "Q33"},
72 
73 	{0x2a40, 0x2a42, INTEL_TYPE_GM45, "GM45"},
74 	{0x2e00, 0x2e02, INTEL_TYPE_G45, "IGD"},
75 	{0x2e10, 0x2e12, INTEL_TYPE_G45, "Q45"},
76 	{0x2e20, 0x2e22, INTEL_TYPE_G45, "G45"},
77 	{0x2e30, 0x2e32, INTEL_TYPE_G45, "G41"},
78 	{0x2e40, 0x2e42, INTEL_TYPE_G45, "B43"},
79 	{0x2e90, 0x2e92, INTEL_TYPE_G45, "B43"},
80 
81 	{0xa000, 0xa001, INTEL_TYPE_IGDG, "Atom_Dx10"},
82 	{0xa010, 0xa011, INTEL_TYPE_IGDGM, "Atom_N4x0"},
83 };
84 
85 struct intel_info {
86 	pci_info	bridge;
87 	pci_info	display;
88 	uint32		type;
89 
90 	uint32		*gtt_base;
91 	addr_t		gtt_physical_base;
92 	area_id		gtt_area;
93 	size_t		gtt_entries;
94 	size_t		gtt_stolen_entries;
95 
96 	vuint32		*registers;
97 	area_id		registers_area;
98 
99 	addr_t		aperture_base;
100 	addr_t		aperture_physical_base;
101 	area_id		aperture_area;
102 	size_t		aperture_size;
103 	size_t		aperture_stolen_size;
104 
105 	phys_addr_t	scratch_page;
106 	area_id		scratch_area;
107 };
108 
109 static intel_info sInfo;
110 static pci_module_info *sPCI;
111 
112 
113 static bool
114 has_display_device(pci_info &info, uint32 deviceID)
115 {
116 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK;
117 			index++) {
118 		if (info.vendor_id != VENDOR_ID_INTEL
119 			|| info.device_id != deviceID
120 			|| info.class_base != PCI_display)
121 			continue;
122 
123 		return true;
124 	}
125 
126 	return false;
127 }
128 
129 
130 static void
131 determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
132 {
133 	// read stolen memory from the PCI configuration of the PCI bridge
134 	uint16 memoryConfig = get_pci_config(info.bridge,
135 		INTEL_GRAPHICS_MEMORY_CONTROL, 2);
136 	size_t memorySize = 1 << 20; // 1 MB
137 	gttSize = 0;
138 	stolenSize = 0;
139 
140 	if (info.type == INTEL_TYPE_965) {
141 		switch (memoryConfig & i965_GTT_MASK) {
142 			case i965_GTT_128K:
143 				gttSize = 128 << 10;
144 				break;
145 			case i965_GTT_256K:
146 				gttSize = 256 << 10;
147 				break;
148 			case i965_GTT_512K:
149 				gttSize = 512 << 10;
150 				break;
151 		}
152 	} else if (info.type == INTEL_TYPE_G33
153 	           || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_IGD) {
154 		switch (memoryConfig & G33_GTT_MASK) {
155 			case G33_GTT_1M:
156 				gttSize = 1 << 20;
157 				break;
158 			case G33_GTT_2M:
159 				gttSize = 2 << 20;
160 				break;
161 		}
162 	} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x) {
163 		switch (memoryConfig & G4X_GTT_MASK) {
164 			case G4X_GTT_NONE:
165 				gttSize = 0;
166 				break;
167 			case G4X_GTT_1M_NO_IVT:
168 				gttSize = 1 << 20;
169 				break;
170 			case G4X_GTT_2M_NO_IVT:
171 			case G4X_GTT_2M_IVT:
172 				gttSize = 2 << 20;
173 				break;
174 			case G4X_GTT_3M_IVT:
175 				gttSize = 3 << 20;
176 				break;
177 			case G4X_GTT_4M_IVT:
178 				gttSize = 4 << 20;
179 				break;
180 		}
181 	} else {
182 		// older models have the GTT as large as their frame buffer mapping
183 		// TODO: check if the i9xx version works with the i8xx chips as well
184 		size_t frameBufferSize = 0;
185 		if ((info.type & INTEL_TYPE_8xx) != 0) {
186 			if (info.type == INTEL_TYPE_83x
187 				&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
188 				frameBufferSize = 64 << 20;
189 			else
190 				frameBufferSize = 128 << 20;
191 		} else if ((info.type & INTEL_TYPE_9xx) != 0)
192 			frameBufferSize = info.display.u.h0.base_register_sizes[2];
193 
194 		TRACE(("frame buffer size %lu MB\n", frameBufferSize >> 20));
195 		gttSize = frameBufferSize / 1024;
196 	}
197 
198 	// TODO: test with different models!
199 
200 	if (info.type == INTEL_TYPE_83x) {
201 		// Older chips
202 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
203 			case i830_LOCAL_MEMORY_ONLY:
204 				// TODO: determine its size!
205 				dprintf("intel_gart: getting local memory size not implemented.\n");
206 				break;
207 			case i830_STOLEN_512K:
208 				memorySize >>= 1;
209 				break;
210 			case i830_STOLEN_1M:
211 				// default case
212 				break;
213 			case i830_STOLEN_8M:
214 				memorySize *= 8;
215 				break;
216 		}
217 	} else if (info.type == INTEL_TYPE_85x
218 		|| (info.type & INTEL_TYPE_9xx) == INTEL_TYPE_9xx) {
219 		switch (memoryConfig & STOLEN_MEMORY_MASK) {
220 			case i855_STOLEN_MEMORY_4M:
221 				memorySize *= 4;
222 				break;
223 			case i855_STOLEN_MEMORY_8M:
224 				memorySize *= 8;
225 				break;
226 			case i855_STOLEN_MEMORY_16M:
227 				memorySize *= 16;
228 				break;
229 			case i855_STOLEN_MEMORY_32M:
230 				memorySize *= 32;
231 				break;
232 			case i855_STOLEN_MEMORY_48M:
233 				memorySize *= 48;
234 				break;
235 			case i855_STOLEN_MEMORY_64M:
236 				memorySize *= 64;
237 				break;
238 			case i855_STOLEN_MEMORY_128M:
239 				memorySize *= 128;
240 				break;
241 			case i855_STOLEN_MEMORY_256M:
242 				memorySize *= 256;
243 				break;
244 			case G4X_STOLEN_MEMORY_96MB:
245 				memorySize *= 96;
246 				break;
247 			case G4X_STOLEN_MEMORY_160MB:
248 				memorySize *= 160;
249 				break;
250 			case G4X_STOLEN_MEMORY_224MB:
251 				memorySize *= 224;
252 				break;
253 			case G4X_STOLEN_MEMORY_352MB:
254 				memorySize *= 352;
255 				break;
256 		}
257 	} else {
258 		// TODO: error out!
259 		memorySize = 4096;
260 	}
261 
262 	stolenSize = memorySize - 4096;
263 }
264 
265 
266 static void
267 set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
268 {
269 	// TODO: this is not 64-bit safe!
270 	write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
271 		(uint32)physicalAddress | GTT_ENTRY_VALID);
272 }
273 
274 
275 static void
276 intel_unmap(intel_info &info)
277 {
278 	delete_area(info.registers_area);
279 	delete_area(info.gtt_area);
280 	delete_area(info.scratch_area);
281 	delete_area(info.aperture_area);
282 	info.aperture_size = 0;
283 }
284 
285 
286 static status_t
287 intel_map(intel_info &info)
288 {
289 	int fbIndex = 0;
290 	int mmioIndex = 1;
291 	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
292 		// for some reason Intel saw the need to change the order of the mappings
293 		// with the introduction of the i9xx family
294 		mmioIndex = 0;
295 		fbIndex = 2;
296 	}
297 
298 	AreaKeeper mmioMapper;
299 	info.registers_area = mmioMapper.Map("intel GMCH mmio",
300 		(void *)info.display.u.h0.base_registers[mmioIndex],
301 		info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS,
302 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&info.registers);
303 	if (mmioMapper.InitCheck() < B_OK) {
304 		dprintf("agp_intel: could not map memory I/O!\n");
305 		return info.registers_area;
306 	}
307 
308 	// make sure bus master, memory-mapped I/O, and frame buffer is enabled
309 	set_pci_config(info.display, PCI_command, 2,
310 		get_pci_config(info.display, PCI_command, 2)
311 			| PCI_command_io | PCI_command_memory | PCI_command_master);
312 
313 	void *scratchAddress;
314 	AreaKeeper scratchCreator;
315 	info.scratch_area = scratchCreator.Create("intel GMCH scratch",
316 		&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
317 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
318 	if (scratchCreator.InitCheck() < B_OK) {
319 		dprintf("agp_intel: could not create scratch page!\n");
320 		return info.scratch_area;
321 	}
322 
323 	physical_entry entry;
324 	if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
325 		return B_ERROR;
326 
327 	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
328 		if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x) {
329 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
330 					+ (2UL << 20);
331 		} else
332 			info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4);
333 	} else {
334 		info.gtt_physical_base = read32(info.registers
335 			+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
336 		if (info.gtt_physical_base == 0) {
337 			// TODO: not sure how this is supposed to work under Linux/FreeBSD,
338 			// but on my i865, this code is needed for Haiku.
339 			dprintf("intel_gart: Use GTT address fallback.\n");
340 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
341 				+ i830_GTT_BASE;
342 		}
343 	}
344 
345 	size_t gttSize, stolenSize;
346 	determine_memory_sizes(info, gttSize, stolenSize);
347 
348 	info.gtt_entries = gttSize / 4096;
349 	info.gtt_stolen_entries = stolenSize / 4096;
350 
351 	TRACE("GTT base %lx, size %lu, entries %lu, stolen %lu\n", info.gtt_physical_base,
352 		gttSize, info.gtt_entries, stolenSize);
353 
354 	AreaKeeper gttMapper;
355 	info.gtt_area = gttMapper.Map("intel GMCH gtt",
356 		(void *)info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
357 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&info.gtt_base);
358 	if (gttMapper.InitCheck() < B_OK) {
359 		dprintf("intel_gart: could not map GTT!\n");
360 		return info.gtt_area;
361 	}
362 
363 	info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex];
364 	info.aperture_stolen_size = stolenSize;
365 	if (info.aperture_size == 0)
366 		info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
367 
368 	dprintf("intel_gart: detected %ld MB of stolen memory, aperture "
369 		"size %ld MB, GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
370 		info.aperture_size >> 20, gttSize >> 10);
371 
372 	dprintf("intel_gart: GTT base = 0x%lx\n", info.gtt_physical_base);
373 	dprintf("intel_gart: MMIO base = 0x%lx\n", info.display.u.h0.base_registers[mmioIndex]);
374 	dprintf("intel_gart: GMR base = 0x%lx\n", info.aperture_physical_base);
375 
376 	AreaKeeper apertureMapper;
377 	info.aperture_area = apertureMapper.Map("intel graphics aperture",
378 		(void *)info.aperture_physical_base, info.aperture_size,
379 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
380 		B_READ_AREA | B_WRITE_AREA, (void **)&info.aperture_base);
381 	if (apertureMapper.InitCheck() < B_OK) {
382 		// try again without write combining
383 		dprintf(DEVICE_NAME ": enabling write combined mode failed.\n");
384 
385 		info.aperture_area = apertureMapper.Map("intel graphics aperture",
386 			(void *)info.aperture_physical_base, info.aperture_size,
387 			B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA,
388 			(void **)&info.aperture_base);
389 	}
390 	if (apertureMapper.InitCheck() < B_OK) {
391 		dprintf(DEVICE_NAME ": could not map graphics aperture!\n");
392 		return info.aperture_area;
393 	}
394 
395 	info.scratch_page = entry.address;
396 
397 	gttMapper.Detach();
398 	mmioMapper.Detach();
399 	scratchCreator.Detach();
400 	apertureMapper.Detach();
401 
402 	return B_OK;
403 }
404 
405 
406 //	#pragma mark - module interface
407 
408 
409 status_t
410 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
411 	void **_aperture)
412 {
413 	// TODO: we currently only support a single AGP bridge!
414 	if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device
415 			|| function != sInfo.bridge.function)
416 		&& (bus != sInfo.display.bus || device != sInfo.display.device
417 			|| function != sInfo.display.function))
418 		return B_BAD_VALUE;
419 
420 	sInfo.aperture_size = size;
421 
422 	if (intel_map(sInfo) < B_OK)
423 		return B_ERROR;
424 
425 	uint16 gmchControl = get_pci_config(sInfo.bridge,
426 		INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED;
427 	set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl);
428 
429 	write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL,
430 		sInfo.gtt_physical_base | PAGE_TABLE_ENABLED);
431 	read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL);
432 
433 	if (sInfo.scratch_page != 0) {
434 		for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) {
435 			set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page);
436 		}
437 		read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
438 	}
439 
440 	asm("wbinvd;");
441 
442 	*_aperture = NULL;
443 	return B_OK;
444 }
445 
446 
447 void
448 intel_delete_aperture(void *aperture)
449 {
450 	intel_unmap(sInfo);
451 }
452 
453 
454 static status_t
455 intel_get_aperture_info(void *aperture, aperture_info *info)
456 {
457 	if (info == NULL)
458 		return B_BAD_VALUE;
459 
460 	info->base = sInfo.aperture_base;
461 	info->physical_base = sInfo.aperture_physical_base;
462 	info->size = sInfo.aperture_size;
463 	info->reserved_size = sInfo.aperture_stolen_size;
464 
465 	return B_OK;
466 }
467 
468 
469 status_t
470 intel_set_aperture_size(void *aperture, size_t size)
471 {
472 	return B_ERROR;
473 }
474 
475 
476 static status_t
477 intel_bind_page(void *aperture, uint32 offset, phys_addr_t physicalAddress)
478 {
479 	//TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress);
480 
481 	set_gtt_entry(sInfo, offset, physicalAddress);
482 	return B_OK;
483 }
484 
485 
486 static status_t
487 intel_unbind_page(void *aperture, uint32 offset)
488 {
489 	//TRACE("unbind_page(offset %lx)\n", offset);
490 
491 	if (sInfo.scratch_page != 0)
492 		set_gtt_entry(sInfo, offset, sInfo.scratch_page);
493 
494 	return B_OK;
495 }
496 
497 
498 void
499 intel_flush_tlbs(void *aperture)
500 {
501 	read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
502 	asm("wbinvd;");
503 }
504 
505 
506 //	#pragma mark -
507 
508 
509 static status_t
510 intel_init()
511 {
512 	TRACE("bus manager init\n");
513 
514 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI) != B_OK)
515 		return B_ERROR;
516 
517 	bool found = false;
518 
519 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK;
520 			index++) {
521 		if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL
522 			|| sInfo.bridge.class_base != PCI_bridge)
523 			continue;
524 
525 		// check device
526 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
527 				/ sizeof(kSupportedDevices[0]); i++) {
528 			if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
529 				sInfo.type = kSupportedDevices[i].type;
530 				found = has_display_device(sInfo.display,
531 					kSupportedDevices[i].display_id);
532 				break;
533 			}
534 		}
535 
536 		if (found)
537 			break;
538 	}
539 
540 	if (!found)
541 		return ENODEV;
542 
543 	TRACE("found intel bridge\n");
544 	return B_OK;
545 }
546 
547 
548 static void
549 intel_uninit()
550 {
551 }
552 
553 
554 static int32
555 intel_std_ops(int32 op, ...)
556 {
557 	switch (op) {
558 		case B_MODULE_INIT:
559 			return intel_init();
560 		case B_MODULE_UNINIT:
561 			intel_uninit();
562 			return B_OK;
563 	}
564 
565 	return B_BAD_VALUE;
566 }
567 
568 
569 static struct agp_gart_bus_module_info sIntelModuleInfo = {
570 	{
571 		"busses/agp_gart/intel/v0",
572 		0,
573 		intel_std_ops
574 	},
575 
576 	intel_create_aperture,
577 	intel_delete_aperture,
578 
579 	intel_get_aperture_info,
580 	intel_set_aperture_size,
581 	intel_bind_page,
582 	intel_unbind_page,
583 	intel_flush_tlbs
584 };
585 
586 module_info *modules[] = {
587 	(module_info *)&sIntelModuleInfo,
588 	NULL
589 };
590