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
42const 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	{0x0040, 0x0042, INTEL_TYPE_ILKG, "IronLake Desktop"},
85	{0x0044, 0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
86	{0x0062, 0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
87	{0x006a, 0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
88
89	{0x0100, 0x0102, INTEL_TYPE_SNBG, "SandyBridge Desktop GT1"},
90	{0x0100, 0x0112, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2"},
91	{0x0100, 0x0122, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2+"},
92	{0x0104, 0x0106, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT1"},
93	{0x0104, 0x0116, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2"},
94	{0x0104, 0x0126, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2+"},
95	{0x0108, 0x010a, INTEL_TYPE_SNBGS, "SandyBridge Server"},
96
97	{0x0150, 0x0152, INTEL_TYPE_IVBG, "IvyBridge Desktop GT1"},
98	{0x0150, 0x0162, INTEL_TYPE_IVBG, "IvyBridge Desktop GT2"},
99	{0x0154, 0x0156, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT1"},
100	{0x0154, 0x0166, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT2"},
101	{0x0158, 0x015a, INTEL_TYPE_IVBGS, "IvyBridge Server GT1"},
102	{0x0158, 0x016a, INTEL_TYPE_IVBGS, "IvyBridge Server GT2"}
103};
104
105struct intel_info {
106	pci_info	bridge;
107	pci_info	display;
108	uint32		type;
109
110	uint32		*gtt_base;
111	addr_t		gtt_physical_base;
112	area_id		gtt_area;
113	size_t		gtt_entries;
114	size_t		gtt_stolen_entries;
115
116	vuint32		*registers;
117	area_id		registers_area;
118
119	addr_t		aperture_base;
120	addr_t		aperture_physical_base;
121	area_id		aperture_area;
122	size_t		aperture_size;
123	size_t		aperture_stolen_size;
124
125	phys_addr_t	scratch_page;
126	area_id		scratch_area;
127};
128
129static intel_info sInfo;
130static pci_module_info* sPCI;
131
132
133static bool
134has_display_device(pci_info &info, uint32 deviceID)
135{
136	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK;
137			index++) {
138		if (info.vendor_id != VENDOR_ID_INTEL
139			|| info.device_id != deviceID
140			|| info.class_base != PCI_display)
141			continue;
142
143		return true;
144	}
145
146	return false;
147}
148
149
150static void
151determine_memory_sizes(intel_info &info, size_t &gttSize, size_t &stolenSize)
152{
153	// read stolen memory from the PCI configuration of the PCI bridge
154	uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL;
155	if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB)
156		controlRegister = SNB_GRAPHICS_MEMORY_CONTROL;
157
158	uint16 memoryConfig = get_pci_config(info.bridge, controlRegister, 2);
159	size_t memorySize = 1 << 20; // 1 MB
160	gttSize = 0;
161	stolenSize = 0;
162
163	if (info.type == INTEL_TYPE_965) {
164		switch (memoryConfig & i965_GTT_MASK) {
165			case i965_GTT_128K:
166				gttSize = 128 << 10;
167				break;
168			case i965_GTT_256K:
169				gttSize = 256 << 10;
170				break;
171			case i965_GTT_512K:
172				gttSize = 512 << 10;
173				break;
174		}
175	} else if (info.type == INTEL_TYPE_G33
176	           || (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_IGD) {
177		switch (memoryConfig & G33_GTT_MASK) {
178			case G33_GTT_1M:
179				gttSize = 1 << 20;
180				break;
181			case G33_GTT_2M:
182				gttSize = 2 << 20;
183				break;
184		}
185	} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
186			|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK) {
187		switch (memoryConfig & G4X_GTT_MASK) {
188			case G4X_GTT_NONE:
189				gttSize = 0;
190				break;
191			case G4X_GTT_1M_NO_IVT:
192				gttSize = 1 << 20;
193				break;
194			case G4X_GTT_2M_NO_IVT:
195			case G4X_GTT_2M_IVT:
196				gttSize = 2 << 20;
197				break;
198			case G4X_GTT_3M_IVT:
199				gttSize = 3 << 20;
200				break;
201			case G4X_GTT_4M_IVT:
202				gttSize = 4 << 20;
203				break;
204		}
205	} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
206		switch (memoryConfig & SNB_GTT_SIZE_MASK) {
207			case SNB_GTT_SIZE_NONE:
208				gttSize = 0;
209				break;
210			case SNB_GTT_SIZE_1MB:
211				gttSize = 1 << 20;
212				break;
213			case SNB_GTT_SIZE_2MB:
214				gttSize = 2 << 20;
215				break;
216		}
217	} else {
218		// older models have the GTT as large as their frame buffer mapping
219		// TODO: check if the i9xx version works with the i8xx chips as well
220		size_t frameBufferSize = 0;
221		if ((info.type & INTEL_TYPE_8xx) != 0) {
222			if (info.type == INTEL_TYPE_83x
223				&& (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M)
224				frameBufferSize = 64 << 20;
225			else
226				frameBufferSize = 128 << 20;
227		} else if ((info.type & INTEL_TYPE_9xx) != 0)
228			frameBufferSize = info.display.u.h0.base_register_sizes[2];
229
230		TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20);
231		gttSize = frameBufferSize / 1024;
232	}
233
234	// TODO: test with different models!
235
236	if (info.type == INTEL_TYPE_83x) {
237		// Older chips
238		switch (memoryConfig & STOLEN_MEMORY_MASK) {
239			case i830_LOCAL_MEMORY_ONLY:
240				// TODO: determine its size!
241				dprintf("intel_gart: getting local memory size not "
242					"implemented.\n");
243				break;
244			case i830_STOLEN_512K:
245				memorySize >>= 1;
246				break;
247			case i830_STOLEN_1M:
248				// default case
249				break;
250			case i830_STOLEN_8M:
251				memorySize *= 8;
252				break;
253		}
254	} else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
255		switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) {
256			case SNB_STOLEN_MEMORY_32MB:
257				memorySize *= 32;
258				break;
259			case SNB_STOLEN_MEMORY_64MB:
260				memorySize *= 64;
261				break;
262			case SNB_STOLEN_MEMORY_96MB:
263				memorySize *= 96;
264				break;
265			case SNB_STOLEN_MEMORY_128MB:
266				memorySize *= 128;
267				break;
268			case SNB_STOLEN_MEMORY_160MB:
269				memorySize *= 160;
270				break;
271			case SNB_STOLEN_MEMORY_192MB:
272				memorySize *= 192;
273				break;
274			case SNB_STOLEN_MEMORY_224MB:
275				memorySize *= 224;
276				break;
277			case SNB_STOLEN_MEMORY_256MB:
278				memorySize *= 256;
279				break;
280			case SNB_STOLEN_MEMORY_288MB:
281				memorySize *= 288;
282				break;
283			case SNB_STOLEN_MEMORY_320MB:
284				memorySize *= 320;
285				break;
286			case SNB_STOLEN_MEMORY_352MB:
287				memorySize *= 352;
288				break;
289			case SNB_STOLEN_MEMORY_384MB:
290				memorySize *= 384;
291				break;
292			case SNB_STOLEN_MEMORY_416MB:
293				memorySize *= 416;
294				break;
295			case SNB_STOLEN_MEMORY_448MB:
296				memorySize *= 448;
297				break;
298			case SNB_STOLEN_MEMORY_480MB:
299				memorySize *= 480;
300				break;
301			case SNB_STOLEN_MEMORY_512MB:
302				memorySize *= 512;
303				break;
304		}
305	} else if (info.type == INTEL_TYPE_85x
306		|| (info.type & INTEL_TYPE_9xx) == INTEL_TYPE_9xx) {
307		switch (memoryConfig & STOLEN_MEMORY_MASK) {
308			case i855_STOLEN_MEMORY_4M:
309				memorySize *= 4;
310				break;
311			case i855_STOLEN_MEMORY_8M:
312				memorySize *= 8;
313				break;
314			case i855_STOLEN_MEMORY_16M:
315				memorySize *= 16;
316				break;
317			case i855_STOLEN_MEMORY_32M:
318				memorySize *= 32;
319				break;
320			case i855_STOLEN_MEMORY_48M:
321				memorySize *= 48;
322				break;
323			case i855_STOLEN_MEMORY_64M:
324				memorySize *= 64;
325				break;
326			case i855_STOLEN_MEMORY_128M:
327				memorySize *= 128;
328				break;
329			case i855_STOLEN_MEMORY_256M:
330				memorySize *= 256;
331				break;
332			case G4X_STOLEN_MEMORY_96MB:
333				memorySize *= 96;
334				break;
335			case G4X_STOLEN_MEMORY_160MB:
336				memorySize *= 160;
337				break;
338			case G4X_STOLEN_MEMORY_224MB:
339				memorySize *= 224;
340				break;
341			case G4X_STOLEN_MEMORY_352MB:
342				memorySize *= 352;
343				break;
344		}
345	} else {
346		// TODO: error out!
347		memorySize = 4096;
348	}
349
350	stolenSize = memorySize - 4096;
351}
352
353
354static void
355set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress)
356{
357	// TODO: this is not 64-bit safe!
358	write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT),
359		(uint32)physicalAddress | GTT_ENTRY_VALID);
360}
361
362
363static void
364intel_unmap(intel_info &info)
365{
366	delete_area(info.registers_area);
367	delete_area(info.gtt_area);
368	delete_area(info.scratch_area);
369	delete_area(info.aperture_area);
370	info.aperture_size = 0;
371}
372
373
374static status_t
375intel_map(intel_info &info)
376{
377	int fbIndex = 0;
378	int mmioIndex = 1;
379	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
380		// for some reason Intel saw the need to change the order of the
381		// mappings with the introduction of the i9xx family
382		mmioIndex = 0;
383		fbIndex = 2;
384	}
385
386	AreaKeeper mmioMapper;
387	info.registers_area = mmioMapper.Map("intel GMCH mmio",
388		(void*)info.display.u.h0.base_registers[mmioIndex],
389		info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS,
390		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.registers);
391	if (mmioMapper.InitCheck() < B_OK) {
392		dprintf("agp_intel: could not map memory I/O!\n");
393		return info.registers_area;
394	}
395
396	// make sure bus master, memory-mapped I/O, and frame buffer is enabled
397	set_pci_config(info.display, PCI_command, 2,
398		get_pci_config(info.display, PCI_command, 2)
399			| PCI_command_io | PCI_command_memory | PCI_command_master);
400
401	void* scratchAddress;
402	AreaKeeper scratchCreator;
403	info.scratch_area = scratchCreator.Create("intel GMCH scratch",
404		&scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK,
405		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
406	if (scratchCreator.InitCheck() < B_OK) {
407		dprintf("agp_intel: could not create scratch page!\n");
408		return info.scratch_area;
409	}
410
411	physical_entry entry;
412	if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK)
413		return B_ERROR;
414
415	if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) {
416		if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x
417			|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_ILK
418			|| (info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_SNB) {
419			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
420					+ (2UL << 20);
421		} else
422			info.gtt_physical_base
423				= get_pci_config(info.display, i915_GTT_BASE, 4);
424	} else {
425		info.gtt_physical_base = read32(info.registers
426			+ INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED;
427		if (info.gtt_physical_base == 0) {
428			// TODO: not sure how this is supposed to work under Linux/FreeBSD,
429			// but on my i865, this code is needed for Haiku.
430			dprintf("intel_gart: Use GTT address fallback.\n");
431			info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex]
432				+ i830_GTT_BASE;
433		}
434	}
435
436	size_t gttSize, stolenSize;
437	determine_memory_sizes(info, gttSize, stolenSize);
438
439	info.gtt_entries = gttSize / 4096;
440	info.gtt_stolen_entries = stolenSize / 4096;
441
442	TRACE("GTT base %lx, size %lu, entries %lu, stolen %lu\n",
443		info.gtt_physical_base, gttSize, info.gtt_entries, stolenSize);
444
445	AreaKeeper gttMapper;
446	info.gtt_area = gttMapper.Map("intel GMCH gtt",
447		(void*)info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS,
448		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.gtt_base);
449	if (gttMapper.InitCheck() < B_OK) {
450		dprintf("intel_gart: could not map GTT!\n");
451		return info.gtt_area;
452	}
453
454	info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex];
455	info.aperture_stolen_size = stolenSize;
456	if (info.aperture_size == 0)
457		info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex];
458
459	dprintf("intel_gart: detected %ld MB of stolen memory, aperture "
460		"size %ld MB, GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20,
461		info.aperture_size >> 20, gttSize >> 10);
462
463	dprintf("intel_gart: GTT base = 0x%lx\n", info.gtt_physical_base);
464	dprintf("intel_gart: MMIO base = 0x%lx\n",
465		info.display.u.h0.base_registers[mmioIndex]);
466	dprintf("intel_gart: GMR base = 0x%lx\n", info.aperture_physical_base);
467
468	AreaKeeper apertureMapper;
469	info.aperture_area = apertureMapper.Map("intel graphics aperture",
470		(void*)info.aperture_physical_base, info.aperture_size,
471		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
472		B_READ_AREA | B_WRITE_AREA, (void**)&info.aperture_base);
473	if (apertureMapper.InitCheck() < B_OK) {
474		// try again without write combining
475		dprintf(DEVICE_NAME ": enabling write combined mode failed.\n");
476
477		info.aperture_area = apertureMapper.Map("intel graphics aperture",
478			(void*)info.aperture_physical_base, info.aperture_size,
479			B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA,
480			(void**)&info.aperture_base);
481	}
482	if (apertureMapper.InitCheck() < B_OK) {
483		dprintf(DEVICE_NAME ": could not map graphics aperture!\n");
484		return info.aperture_area;
485	}
486
487	info.scratch_page = entry.address;
488
489	gttMapper.Detach();
490	mmioMapper.Detach();
491	scratchCreator.Detach();
492	apertureMapper.Detach();
493
494	return B_OK;
495}
496
497
498//	#pragma mark - module interface
499
500
501status_t
502intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size,
503	void** _aperture)
504{
505	// TODO: we currently only support a single AGP bridge!
506	if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device
507			|| function != sInfo.bridge.function)
508		&& (bus != sInfo.display.bus || device != sInfo.display.device
509			|| function != sInfo.display.function))
510		return B_BAD_VALUE;
511
512	sInfo.aperture_size = size;
513
514	if (intel_map(sInfo) < B_OK)
515		return B_ERROR;
516
517	uint16 gmchControl = get_pci_config(sInfo.bridge,
518		INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED;
519	set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl);
520
521	write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL,
522		sInfo.gtt_physical_base | PAGE_TABLE_ENABLED);
523	read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL);
524
525	if (sInfo.scratch_page != 0) {
526		for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) {
527			set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page);
528		}
529		read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
530	}
531
532	asm("wbinvd;");
533
534	*_aperture = NULL;
535	return B_OK;
536}
537
538
539void
540intel_delete_aperture(void* aperture)
541{
542	intel_unmap(sInfo);
543}
544
545
546static status_t
547intel_get_aperture_info(void* aperture, aperture_info* info)
548{
549	if (info == NULL)
550		return B_BAD_VALUE;
551
552	info->base = sInfo.aperture_base;
553	info->physical_base = sInfo.aperture_physical_base;
554	info->size = sInfo.aperture_size;
555	info->reserved_size = sInfo.aperture_stolen_size;
556
557	return B_OK;
558}
559
560
561status_t
562intel_set_aperture_size(void* aperture, size_t size)
563{
564	return B_ERROR;
565}
566
567
568static status_t
569intel_bind_page(void* aperture, uint32 offset, phys_addr_t physicalAddress)
570{
571	//TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress);
572
573	set_gtt_entry(sInfo, offset, physicalAddress);
574	return B_OK;
575}
576
577
578static status_t
579intel_unbind_page(void* aperture, uint32 offset)
580{
581	//TRACE("unbind_page(offset %lx)\n", offset);
582
583	if (sInfo.scratch_page != 0)
584		set_gtt_entry(sInfo, offset, sInfo.scratch_page);
585
586	return B_OK;
587}
588
589
590void
591intel_flush_tlbs(void* aperture)
592{
593	read32(sInfo.gtt_base + sInfo.gtt_entries - 1);
594	asm("wbinvd;");
595}
596
597
598//	#pragma mark -
599
600
601static status_t
602intel_init()
603{
604	TRACE("bus manager init\n");
605
606	if (get_module(B_PCI_MODULE_NAME, (module_info**)&sPCI) != B_OK)
607		return B_ERROR;
608
609	bool found = false;
610
611	for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK;
612			index++) {
613		if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL
614			|| sInfo.bridge.class_base != PCI_bridge)
615			continue;
616
617		// check device
618		for (uint32 i = 0; i < sizeof(kSupportedDevices)
619				/ sizeof(kSupportedDevices[0]); i++) {
620			if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) {
621				sInfo.type = kSupportedDevices[i].type;
622				found = has_display_device(sInfo.display,
623					kSupportedDevices[i].display_id);
624			}
625		}
626
627		if (found)
628			break;
629	}
630
631	if (!found)
632		return ENODEV;
633
634	TRACE("found intel bridge\n");
635	return B_OK;
636}
637
638
639static void
640intel_uninit()
641{
642}
643
644
645static int32
646intel_std_ops(int32 op, ...)
647{
648	switch (op) {
649		case B_MODULE_INIT:
650			return intel_init();
651		case B_MODULE_UNINIT:
652			intel_uninit();
653			return B_OK;
654	}
655
656	return B_BAD_VALUE;
657}
658
659
660static struct agp_gart_bus_module_info sIntelModuleInfo = {
661	{
662		"busses/agp_gart/intel/v0",
663		0,
664		intel_std_ops
665	},
666
667	intel_create_aperture,
668	intel_delete_aperture,
669
670	intel_get_aperture_info,
671	intel_set_aperture_size,
672	intel_bind_page,
673	intel_unbind_page,
674	intel_flush_tlbs
675};
676
677module_info* modules[] = {
678	(module_info*)&sIntelModuleInfo,
679	NULL
680};
681