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