xref: /haiku/src/add-ons/kernel/busses/agp_gart/intel_gart.cpp (revision 1345706a9ff6ad0dc041339a02d4259998b0765d)
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 	{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 	phys_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, phys_addr_t physicalAddress)
257 {
258 	// TODO: this is not 64-bit safe!
259 	write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
260 		(uint32)physicalAddress | GTT_ENTRY_VALID);
261 }
262 
263 
264 static void
265 intel_unmap(intel_info &info)
266 {
267 	delete_area(info.registers_area);
268 	delete_area(info.gtt_area);
269 	delete_area(info.scratch_area);
270 	delete_area(info.aperture_area);
271 	info.aperture_size = 0;
272 }
273 
274 
275 static status_t
276 intel_map(intel_info &info)
277 {
278 	int fbIndex = 0;
279 	int mmioIndex = 1;
280 	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
281 		// for some reason Intel saw the need to change the order of the mappings
282 		// with the introduction of the i9xx family
283 		mmioIndex = 0;
284 		fbIndex = 2;
285 	}
286 
287 	AreaKeeper mmioMapper;
288 	info.registers_area = mmioMapper.Map("intel GMCH mmio",
289 		(void *)info.display.u.h0.base_registers[mmioIndex],
290 		info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS,
291 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&info.registers);
292 	if (mmioMapper.InitCheck() < B_OK) {
293 		dprintf("agp_intel: could not map memory I/O!\n");
294 		return info.registers_area;
295 	}
296 
297 	// make sure bus master, memory-mapped I/O, and frame buffer is enabled
298 	set_pci_config(info.display, PCI_command, 2,
299 		get_pci_config(info.display, PCI_command, 2)
300 			| PCI_command_io | PCI_command_memory | PCI_command_master);
301 
302 	void *scratchAddress;
303 	AreaKeeper scratchCreator;
304 	info.scratch_area = scratchCreator.Create("intel GMCH scratch",
305 		&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
306 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
307 	if (scratchCreator.InitCheck() < B_OK) {
308 		dprintf("agp_intel: could not create scratch page!\n");
309 		return info.scratch_area;
310 	}
311 
312 	physical_entry entry;
313 	if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
314 		return B_ERROR;
315 
316 	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
317 		if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x) {
318 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
319 					+ (2UL << 20);
320 		} else
321 			info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4);
322 	} else {
323 		info.gtt_physical_base = read32(info.registers
324 			+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
325 		if (info.gtt_physical_base == 0) {
326 			// TODO: not sure how this is supposed to work under Linux/FreeBSD,
327 			// but on my i865, this code is needed for Haiku.
328 			dprintf("intel_gart: Use GTT address fallback.\n");
329 			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
330 				+ i830_GTT_BASE;
331 		}
332 	}
333 
334 	size_t gttSize, stolenSize;
335 	determine_memory_sizes(info, gttSize, stolenSize);
336 
337 	info.gtt_entries = gttSize / 4096;
338 	info.gtt_stolen_entries = stolenSize / 4096;
339 
340 	TRACE("GTT base %lx, size %lu, entries %lu, stolen %lu\n", info.gtt_physical_base,
341 		gttSize, info.gtt_entries, stolenSize);
342 
343 	AreaKeeper gttMapper;
344 	info.gtt_area = gttMapper.Map("intel GMCH gtt",
345 		(void *)info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
346 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&info.gtt_base);
347 	if (gttMapper.InitCheck() < B_OK) {
348 		dprintf("intel_gart: could not map GTT!\n");
349 		return info.gtt_area;
350 	}
351 
352 	info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex];
353 	info.aperture_stolen_size = stolenSize;
354 	if (info.aperture_size == 0)
355 		info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
356 
357 	dprintf("intel_gart: detected %ld MB of stolen memory, aperture "
358 		"size %ld MB, GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
359 		info.aperture_size >> 20, gttSize >> 10);
360 
361 	dprintf("intel_gart: GTT base = 0x%lx\n", info.gtt_physical_base);
362 	dprintf("intel_gart: MMIO base = 0x%lx\n", info.display.u.h0.base_registers[mmioIndex]);
363 	dprintf("intel_gart: GMR base = 0x%lx\n", info.aperture_physical_base);
364 
365 	AreaKeeper apertureMapper;
366 	info.aperture_area = apertureMapper.Map("intel graphics aperture",
367 		(void *)info.aperture_physical_base, info.aperture_size,
368 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
369 		B_READ_AREA | B_WRITE_AREA, (void **)&info.aperture_base);
370 	if (apertureMapper.InitCheck() < B_OK) {
371 		// try again without write combining
372 		dprintf(DEVICE_NAME ": enabling write combined mode failed.\n");
373 
374 		info.aperture_area = apertureMapper.Map("intel graphics aperture",
375 			(void *)info.aperture_physical_base, info.aperture_size,
376 			B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA,
377 			(void **)&info.aperture_base);
378 	}
379 	if (apertureMapper.InitCheck() < B_OK) {
380 		dprintf(DEVICE_NAME ": could not map graphics aperture!\n");
381 		return info.aperture_area;
382 	}
383 
384 	info.scratch_page = entry.address;
385 
386 	gttMapper.Detach();
387 	mmioMapper.Detach();
388 	scratchCreator.Detach();
389 	apertureMapper.Detach();
390 
391 	return B_OK;
392 }
393 
394 
395 //	#pragma mark - module interface
396 
397 
398 status_t
399 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
400 	void **_aperture)
401 {
402 	// TODO: we currently only support a single AGP bridge!
403 	if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device
404 			|| function != sInfo.bridge.function)
405 		&& (bus != sInfo.display.bus || device != sInfo.display.device
406 			|| function != sInfo.display.function))
407 		return B_BAD_VALUE;
408 
409 	sInfo.aperture_size = size;
410 
411 	if (intel_map(sInfo) < B_OK)
412 		return B_ERROR;
413 
414 	uint16 gmchControl = get_pci_config(sInfo.bridge,
415 		INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED;
416 	set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl);
417 
418 	write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL,
419 		sInfo.gtt_physical_base | PAGE_TABLE_ENABLED);
420 	read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL);
421 
422 	if (sInfo.scratch_page != 0) {
423 		for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) {
424 			set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page);
425 		}
426 		read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
427 	}
428 
429 	asm("wbinvd;");
430 
431 	*_aperture = NULL;
432 	return B_OK;
433 }
434 
435 
436 void
437 intel_delete_aperture(void *aperture)
438 {
439 	intel_unmap(sInfo);
440 }
441 
442 
443 static status_t
444 intel_get_aperture_info(void *aperture, aperture_info *info)
445 {
446 	if (info == NULL)
447 		return B_BAD_VALUE;
448 
449 	info->base = sInfo.aperture_base;
450 	info->physical_base = sInfo.aperture_physical_base;
451 	info->size = sInfo.aperture_size;
452 	info->reserved_size = sInfo.aperture_stolen_size;
453 
454 	return B_OK;
455 }
456 
457 
458 status_t
459 intel_set_aperture_size(void *aperture, size_t size)
460 {
461 	return B_ERROR;
462 }
463 
464 
465 static status_t
466 intel_bind_page(void *aperture, uint32 offset, phys_addr_t physicalAddress)
467 {
468 	//TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress);
469 
470 	set_gtt_entry(sInfo, offset, physicalAddress);
471 	return B_OK;
472 }
473 
474 
475 static status_t
476 intel_unbind_page(void *aperture, uint32 offset)
477 {
478 	//TRACE("unbind_page(offset %lx)\n", offset);
479 
480 	if (sInfo.scratch_page != 0)
481 		set_gtt_entry(sInfo, offset, sInfo.scratch_page);
482 
483 	return B_OK;
484 }
485 
486 
487 void
488 intel_flush_tlbs(void *aperture)
489 {
490 	read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
491 	asm("wbinvd;");
492 }
493 
494 
495 //	#pragma mark -
496 
497 
498 static status_t
499 intel_init()
500 {
501 	TRACE("bus manager init\n");
502 
503 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI) != B_OK)
504 		return B_ERROR;
505 
506 	bool found = false;
507 
508 	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK;
509 			index++) {
510 		if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL
511 			|| sInfo.bridge.class_base != PCI_bridge)
512 			continue;
513 
514 		// check device
515 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
516 				/ sizeof(kSupportedDevices[0]); i++) {
517 			if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
518 				sInfo.type = kSupportedDevices[i].type;
519 				found = has_display_device(sInfo.display,
520 					kSupportedDevices[i].display_id);
521 				break;
522 			}
523 		}
524 
525 		if (found)
526 			break;
527 	}
528 
529 	if (!found)
530 		return ENODEV;
531 
532 	TRACE("found intel bridge\n");
533 	return B_OK;
534 }
535 
536 
537 static void
538 intel_uninit()
539 {
540 }
541 
542 
543 static int32
544 intel_std_ops(int32 op, ...)
545 {
546 	switch (op) {
547 		case B_MODULE_INIT:
548 			return intel_init();
549 		case B_MODULE_UNINIT:
550 			intel_uninit();
551 			return B_OK;
552 	}
553 
554 	return B_BAD_VALUE;
555 }
556 
557 
558 static struct agp_gart_bus_module_info sIntelModuleInfo = {
559 	{
560 		"busses/agp_gart/intel/v0",
561 		0,
562 		intel_std_ops
563 	},
564 
565 	intel_create_aperture,
566 	intel_delete_aperture,
567 
568 	intel_get_aperture_info,
569 	intel_set_aperture_size,
570 	intel_bind_page,
571 	intel_unbind_page,
572 	intel_flush_tlbs
573 };
574 
575 module_info *modules[] = {
576 	(module_info *)&sIntelModuleInfo,
577 	NULL
578 };
579