xref: /haiku/src/add-ons/kernel/drivers/graphics/intel_810/driver.cpp (revision 77fb9ca3e653f72d1d15c9f1a50c3d4287f680e0)
1 /*
2  * Copyright 2007-2012 Haiku, Inc.  All rights reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Gerald Zajac
7  */
8 
9 
10 #include <AGP.h>
11 #include <KernelExport.h>
12 #include <PCI.h>
13 #include <drivers/bios.h>
14 #include <malloc.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <graphic_driver.h>
18 #include <boot_item.h>
19 
20 #include "DriverInterface.h"
21 
22 
23 #undef TRACE
24 
25 #ifdef ENABLE_DEBUG_TRACE
26 #	define TRACE(x...) dprintf("i810: " x)
27 #else
28 #	define TRACE(x...) ;
29 #endif
30 
31 
32 #define ACCELERANT_NAME    "intel_810.accelerant"
33 
34 #define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
35 
36 #define MAX_DEVICES		4
37 #define DEVICE_FORMAT	"%04X_%04X_%02X%02X%02X"
38 
39 #define VENDOR_ID	0x8086	// Intel vendor ID
40 
41 
42 struct ChipInfo {
43 	uint16		chipID;		// PCI device id of the chip
44 	const char*	chipName;	// user recognizable name (must be < 32 chars)
45 };
46 
47 
48 // This table maps a PCI device ID to a chip type identifier and the chip name.
49 
50 static const ChipInfo chipTable[] = {
51 	{ 0x7121, "i810" },
52 	{ 0x7123, "i810-dc100" },
53 	{ 0x7125, "i810e" },
54 	{ 0x1132, "i815" },
55 	{ 0, NULL }
56 };
57 
58 
59 struct DeviceInfo {
60 	uint32			openCount;		// how many times device has been opened
61 	int32			flags;
62 	area_id 		sharedArea;		// shared between driver and accelerants
63 	SharedInfo* 	sharedInfo;		// pointer to shared info area memory
64 	vuint8*	 		regs;			// pointer to memory mapped registers
65 	const ChipInfo*	pChipInfo;		// info about the selected chip
66 	pci_info		pciInfo;		// copy of pci info for this device
67 	area_id			gttArea;		// area used for GTT
68 	addr_t			gttAddr;		// virtual address of GTT
69 	char			name[B_OS_NAME_LENGTH]; // name of device
70 };
71 
72 
73 static Benaphore		gLock;
74 static DeviceInfo		gDeviceInfo[MAX_DEVICES];
75 static char*			gDeviceNames[MAX_DEVICES + 1];
76 static pci_module_info*	gPCI;
77 
78 
79 // Prototypes for device hook functions.
80 static status_t device_open(const char* name, uint32 flags, void** cookie);
81 static status_t device_close(void* dev);
82 static status_t device_free(void* dev);
83 static status_t device_read(void* dev, off_t pos, void* buf, size_t* len);
84 static status_t device_write(void* dev, off_t pos, const void* buf,
85 	size_t* len);
86 static status_t device_ioctl(void* dev, uint32 msg, void* buf, size_t len);
87 
88 static device_hooks gDeviceHooks =
89 {
90 	device_open,
91 	device_close,
92 	device_free,
93 	device_ioctl,
94 	device_read,
95 	device_write,
96 	NULL,
97 	NULL,
98 	NULL,
99 	NULL
100 };
101 
102 
103 // Video chip register definitions.
104 // =================================
105 
106 #define INTERRUPT_ENABLED		0x020a0
107 #define INTERRUPT_MASK			0x020a8
108 
109 // Graphics address translation table.
110 #define PAGE_TABLE_CONTROL		0x02020
111 #define PAGE_TABLE_ENABLED		0x01
112 
113 #define PTE_BASE				0x10000
114 #define PTE_VALID				0x01
115 
116 
117 // Macros for memory mapped I/O.
118 // ==============================
119 
120 #define INREG16(addr)		(*((vuint16*)(di.regs + (addr))))
121 #define INREG32(addr)		(*((vuint32*)(di.regs + (addr))))
122 
123 #define OUTREG16(addr, val)	(*((vuint16*)(di.regs + (addr))) = (val))
124 #define OUTREG32(addr, val)	(*((vuint32*)(di.regs + (addr))) = (val))
125 
126 
127 static inline uint32
128 GetPCI(pci_info& info, uint8 offset, uint8 size)
129 {
130 	return gPCI->read_pci_config(info.bus, info.device, info.function, offset,
131 		size);
132 }
133 
134 
135 static inline void
136 SetPCI(pci_info& info, uint8 offset, uint8 size, uint32 value)
137 {
138 	gPCI->write_pci_config(info.bus, info.device, info.function, offset, size,
139 		value);
140 }
141 
142 
143 static status_t
144 GetEdidFromBIOS(edid1_raw& edidRaw)
145 {
146 	// Get the EDID info from the video BIOS, and return B_OK if successful.
147 
148 	#define ADDRESS_SEGMENT(address) ((addr_t)(address) >> 4)
149 	#define ADDRESS_OFFSET(address) ((addr_t)(address) & 0xf)
150 
151 	bios_module_info* biosModule;
152 	status_t status = get_module(B_BIOS_MODULE_NAME, (module_info**)&biosModule);
153 	if (status != B_OK) {
154 		TRACE("GetEdidFromBIOS(): failed to get BIOS module: 0x%" B_PRIx32 "\n",
155 			status);
156 		return status;
157 	}
158 
159 	bios_state* state;
160 	status = biosModule->prepare(&state);
161 	if (status != B_OK) {
162 		TRACE("GetEdidFromBIOS(): bios_prepare() failed: 0x%" B_PRIx32 "\n",
163 			status);
164 		put_module(B_BIOS_MODULE_NAME);
165 		return status;
166 	}
167 
168 	bios_regs regs = {};
169 	regs.eax = 0x4f15;
170 	regs.ebx = 0;			// 0 = report DDC service
171 	regs.ecx = 0;
172 	regs.es = 0;
173 	regs.edi = 0;
174 
175 	status = biosModule->interrupt(state, 0x10, &regs);
176 	if (status == B_OK) {
177 		// AH contains the error code, and AL determines whether or not the
178 		// function is supported.
179 		if (regs.eax != 0x4f)
180 			status = B_NOT_SUPPORTED;
181 
182 		// Test if DDC is supported by the monitor.
183 		if ((regs.ebx & 3) == 0)
184 			status = B_NOT_SUPPORTED;
185 	}
186 
187 	if (status == B_OK) {
188 		edid1_raw* edid = (edid1_raw*)biosModule->allocate_mem(state,
189 			sizeof(edid1_raw));
190 		if (edid == NULL) {
191 			status = B_NO_MEMORY;
192 			goto out;
193 		}
194 
195 		regs.eax = 0x4f15;
196 		regs.ebx = 1;		// 1 = read EDID
197 		regs.ecx = 0;
198 		regs.edx = 0;
199 		regs.es  = ADDRESS_SEGMENT(edid);
200 		regs.edi = ADDRESS_OFFSET(edid);
201 
202 		status = biosModule->interrupt(state, 0x10, &regs);
203 		if (status == B_OK) {
204 			if (regs.eax != 0x4f) {
205 				status = B_NOT_SUPPORTED;
206 			} else {
207 				// Copy the EDID info to the caller's location, and compute the
208 				// checksum of the EDID info while copying.
209 
210 				uint8 sum = 0;
211 				uint8 allOr = 0;
212 				uint8* dest = (uint8*)&edidRaw;
213 				uint8* src = (uint8*)edid;
214 
215 				for (uint32 j = 0; j < sizeof(edidRaw); j++) {
216 					sum += *src;
217 					allOr |= *src;
218 					*dest++ = *src++;
219 				}
220 
221 				if (allOr == 0) {
222 					TRACE("GetEdidFromBIOS(); EDID info contains only zeros\n");
223 					status = B_ERROR;
224 				} else if (sum != 0) {
225 					TRACE("GetEdidFromBIOS(); Checksum error in EDID info\n");
226 					status = B_ERROR;
227 				}
228 			}
229 		}
230 	}
231 
232 out:
233 	biosModule->finish(state);
234 	put_module(B_BIOS_MODULE_NAME);
235 
236 	TRACE("GetEdidFromBIOS() status: 0x%" B_PRIx32 "\n", status);
237 	return status;
238 }
239 
240 
241 static status_t
242 InitDevice(DeviceInfo& di)
243 {
244 	// Perform initialization and mapping of the device, and return B_OK if
245 	// sucessful;  else, return error code.
246 
247 	TRACE("enter InitDevice()\n");
248 
249 	// Create the area for shared info with NO user-space read or write
250 	// permissions, to prevent accidental damage.
251 
252 	size_t sharedSize = (sizeof(SharedInfo) + 7) & ~7;
253 
254 	di.sharedArea = create_area("i810 shared info",
255 		(void**) &(di.sharedInfo),
256 		B_ANY_KERNEL_ADDRESS,
257 		ROUND_TO_PAGE_SIZE(sharedSize),
258 		B_FULL_LOCK,
259 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA);
260 	if (di.sharedArea < 0)
261 		return di.sharedArea;	// return error code
262 
263 	SharedInfo& si = *(di.sharedInfo);
264 	memset(&si, 0, sharedSize);
265 	si.regsArea = -1;			// indicate area has not yet been created
266 	si.videoMemArea = -1;
267 
268 	pci_info& pciInfo = di.pciInfo;
269 
270 	si.vendorID = pciInfo.vendor_id;
271 	si.deviceID = pciInfo.device_id;
272 	si.revision = pciInfo.revision;
273 	strcpy(si.chipName, di.pChipInfo->chipName);
274 
275 	// Enable memory mapped IO and bus master.
276 
277 	SetPCI(pciInfo, PCI_command, 2, GetPCI(pciInfo, PCI_command, 2)
278 		| PCI_command_io | PCI_command_memory | PCI_command_master);
279 
280 	// Map the MMIO register area.
281 
282 	phys_addr_t regsBase = pciInfo.u.h0.base_registers[1];
283 	uint32 regAreaSize = pciInfo.u.h0.base_register_sizes[1];
284 
285 	si.regsArea = map_physical_memory("i810 mmio registers",
286 		regsBase,
287 		regAreaSize,
288 		B_ANY_KERNEL_ADDRESS,
289 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_CLONEABLE_AREA,
290 		(void**)&di.regs);
291 
292 	if (si.regsArea < 0) {
293 		TRACE("Unable to map MMIO, error: 0x%" B_PRIx32 "\n", si.regsArea);
294 		return si.regsArea;
295 	}
296 
297 	// Allocate memory for the GTT which must be 64K for the 810/815 chips.
298 
299 	uint32 gttSize = 64 * 1024;
300 	di.gttArea = create_area("GTT memory", (void**) &(di.gttAddr),
301 		B_ANY_KERNEL_ADDRESS, gttSize, B_FULL_LOCK | B_CONTIGUOUS,
302 		B_READ_AREA | B_WRITE_AREA);
303 
304 	if (di.gttArea < B_OK) {
305 		TRACE("Unable to create GTT, error: 0x%" B_PRIx32 "\n", di.gttArea);
306 		return B_NO_MEMORY;
307 	}
308 
309 	memset((void*)(di.gttAddr), 0, gttSize);
310 
311 	// Get the physical address of the GTT, and set GTT address in the chip.
312 
313 	physical_entry entry;
314 	status_t status = get_memory_map((void *)(di.gttAddr),
315 		B_PAGE_SIZE, &entry, 1);
316 	if (status < B_OK) {
317 		TRACE("Unable to get physical address of GTT, "
318 			"error: 0x%" B_PRIx32 "\n", status);
319 		return status;
320 	}
321 
322 	OUTREG32(PAGE_TABLE_CONTROL, entry.address | PAGE_TABLE_ENABLED);
323 	INREG32(PAGE_TABLE_CONTROL);
324 
325 	// Allocate video memory to be used for the frame buffer.
326 
327 	si.videoMemSize = 4 * 1024 * 1024;
328 	si.videoMemArea = create_area("video memory", (void**)&(si.videoMemAddr),
329 		B_ANY_ADDRESS, si.videoMemSize, B_FULL_LOCK,
330 		B_READ_AREA | B_WRITE_AREA);
331 	if (si.videoMemArea < B_OK) {
332 		TRACE("Unable to create video memory, error: 0x%" B_PRIx32 "\n",
333 			si.videoMemArea);
334 		return B_NO_MEMORY;
335 	}
336 
337 	// Get the physical address of each page of the video memory, and put
338 	// the physical address of each page into the GTT table.
339 
340 	for (uint32 offset = 0; offset < si.videoMemSize; offset += B_PAGE_SIZE) {
341 		status = get_memory_map((void *)(si.videoMemAddr + offset),
342 			B_PAGE_SIZE, &entry, 1);
343 		if (status < B_OK) {
344 			TRACE("Unable to get physical address of video memory page, error:"
345 				" 0x%" B_PRIx32 "  offset: %" B_PRId32 "\n", status, offset);
346 			return status;
347 		}
348 
349 		if (offset == 0)
350 			si.videoMemPCI = entry.address;
351 
352 		OUTREG32(PTE_BASE + ((offset / B_PAGE_SIZE) * 4),
353 			entry.address | PTE_VALID);
354 	}
355 
356 	TRACE("InitDevice() exit OK\n");
357 	return B_OK;
358 }
359 
360 
361 static void
362 DeleteAreas(DeviceInfo& di)
363 {
364 	// Delete all areas that were created.
365 
366 	if (di.sharedArea >= 0 && di.sharedInfo != NULL) {
367 		SharedInfo& si = *(di.sharedInfo);
368 		if (si.regsArea >= 0)
369 			delete_area(si.regsArea);
370 		if (si.videoMemArea >= 0)
371 			delete_area(si.videoMemArea);
372 	}
373 
374 	if (di.gttArea >= 0)
375 		delete_area(di.gttArea);
376 	di.gttArea = -1;
377 	di.gttAddr = (addr_t)NULL;
378 
379 	if (di.sharedArea >= 0)
380 		delete_area(di.sharedArea);
381 	di.sharedArea = -1;
382 	di.sharedInfo = NULL;
383 }
384 
385 
386 static const ChipInfo*
387 GetNextSupportedDevice(uint32& pciIndex, pci_info& pciInfo)
388 {
389 	// Search the PCI devices for a device that is supported by this driver.
390 	// The search starts at the device specified by argument pciIndex, and
391 	// continues until a supported device is found or there are no more devices
392 	// to examine.  Argument pciIndex is incremented after each device is
393 	// examined.
394 
395 	// If a supported device is found, return a pointer to the struct containing
396 	// the chip info; else return NULL.
397 
398 	while (gPCI->get_nth_pci_info(pciIndex, &pciInfo) == B_OK) {
399 
400 		if (pciInfo.vendor_id == VENDOR_ID) {
401 
402 			// Search the table of supported devices to find a chip/device that
403 			// matches device ID of the current PCI device.
404 
405 			const ChipInfo* pDevice = chipTable;
406 
407 			while (pDevice->chipID != 0) {	// end of table?
408 				if (pDevice->chipID == pciInfo.device_id)
409 					return pDevice; // matching device/chip found
410 
411 				pDevice++;
412 			}
413 		}
414 
415 		pciIndex++;
416 	}
417 
418 	return NULL; // no supported device found
419 }
420 
421 
422 //	#pragma mark - Kernel Interface
423 
424 
425 status_t
426 init_hardware(void)
427 {
428 	// Return B_OK if a device supported by this driver is found; otherwise,
429 	// return B_ERROR so the driver will be unloaded.
430 
431 	status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
432 	if (status != B_OK) {
433 		TRACE("PCI module unavailable, error 0x%" B_PRIx32 "\n", status);
434 		return status;
435 	}
436 
437 	// Check pci devices for a device supported by this driver.
438 
439 	uint32 pciIndex = 0;
440 	pci_info pciInfo;
441 	const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, pciInfo);
442 
443 	TRACE("init_hardware() - %s\n",
444 		pDevice == NULL ? "no supported devices" : "device supported");
445 
446 	put_module(B_PCI_MODULE_NAME);		// put away the module manager
447 
448 	return (pDevice == NULL ? B_ERROR : B_OK);
449 }
450 
451 
452 status_t
453 init_driver(void)
454 {
455 	// Get handle for the pci bus.
456 
457 	status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
458 	if (status != B_OK) {
459 		TRACE("PCI module unavailable, error 0x%" B_PRIx32 "\n", status);
460 		return status;
461 	}
462 
463 	status = gLock.Init("i810 driver lock");
464 	if (status < B_OK) {
465 		put_module(B_AGP_GART_MODULE_NAME);
466 		put_module(B_PCI_MODULE_NAME);
467 		return status;
468 	}
469 
470 	// Get info about all the devices supported by this driver.
471 
472 	uint32 pciIndex = 0;
473 	uint32 count = 0;
474 
475 	while (count < MAX_DEVICES) {
476 		DeviceInfo& di = gDeviceInfo[count];
477 
478 		const ChipInfo* pDevice = GetNextSupportedDevice(pciIndex, di.pciInfo);
479 		if (pDevice == NULL)
480 			break;			// all supported devices have been obtained
481 
482 		// Compose device name.
483 		sprintf(di.name, "graphics/" DEVICE_FORMAT,
484 			di.pciInfo.vendor_id, di.pciInfo.device_id,
485 			di.pciInfo.bus, di.pciInfo.device, di.pciInfo.function);
486 		TRACE("init_driver() match found; name: %s\n", di.name);
487 
488 		gDeviceNames[count] = di.name;
489 		di.openCount = 0;		// mark driver as available for R/W open
490 		di.sharedArea = -1;		// indicate shared area not yet created
491 		di.sharedInfo = NULL;
492 		di.gttArea = -1;		// indicate GTT area not yet created
493 		di.gttAddr = (addr_t)NULL;
494 		di.pChipInfo = pDevice;
495 		count++;
496 		pciIndex++;
497 	}
498 
499 	gDeviceNames[count] = NULL;	// terminate list with null pointer
500 
501 	TRACE("init_driver() %" B_PRIu32 " supported devices\n", count);
502 
503 	return B_OK;
504 }
505 
506 
507 void
508 uninit_driver(void)
509 {
510 	// Free the driver data.
511 
512 	gLock.Delete();
513 	put_module(B_AGP_GART_MODULE_NAME);
514 	put_module(B_PCI_MODULE_NAME);	// put the pci module away
515 }
516 
517 
518 const char**
519 publish_devices(void)
520 {
521 	return (const char**)gDeviceNames;	// return list of supported devices
522 }
523 
524 
525 device_hooks*
526 find_device(const char* name)
527 {
528 	int i = 0;
529 	while (gDeviceNames[i] != NULL) {
530 		if (strcmp(name, gDeviceNames[i]) == 0)
531 			return &gDeviceHooks;
532 		i++;
533 	}
534 
535 	return NULL;
536 }
537 
538 
539 //	#pragma mark - Device Hooks
540 
541 
542 static status_t
543 device_open(const char* name, uint32 /*flags*/, void** cookie)
544 {
545 	status_t status = B_OK;
546 
547 	TRACE("device_open() - name: %s, cookie: 0x%" B_PRIXADDR "\n", name,
548 		(addr_t)cookie);
549 
550 	// Find the device name in the list of devices.
551 
552 	int32 i = 0;
553 	while (gDeviceNames[i] != NULL && (strcmp(name, gDeviceNames[i]) != 0))
554 		i++;
555 
556 	if (gDeviceNames[i] == NULL)
557 		return B_BAD_VALUE;		// device name not found in list of devices
558 
559 	DeviceInfo& di = gDeviceInfo[i];
560 
561 	gLock.Acquire();	// make sure no one else has write access to common data
562 
563 	if (di.openCount == 0) {
564 		status = InitDevice(di);
565 		if (status < B_OK)
566 			DeleteAreas(di);	// error occurred; delete any areas created
567 	}
568 
569 	gLock.Release();
570 
571 	if (status == B_OK) {
572 		di.openCount++;		// mark device open
573 		*cookie = &di;		// send cookie to opener
574 	}
575 
576 	TRACE("device_open() returning 0x%" B_PRIx32 ",  "
577 		"open count: %" B_PRId32 "\n", status, di.openCount);
578 	return status;
579 }
580 
581 
582 static status_t
583 device_read(void* dev, off_t pos, void* buf, size_t* len)
584 {
585 	// Following 3 lines of code are here to eliminate "unused parameter"
586 	// warnings.
587 	(void)dev;
588 	(void)pos;
589 	(void)buf;
590 
591 	*len = 0;
592 	return B_NOT_ALLOWED;
593 }
594 
595 
596 static status_t
597 device_write(void* dev, off_t pos, const void* buf, size_t* len)
598 {
599 	// Following 3 lines of code are here to eliminate "unused parameter"
600 	// warnings.
601 	(void)dev;
602 	(void)pos;
603 	(void)buf;
604 
605 	*len = 0;
606 	return B_NOT_ALLOWED;
607 }
608 
609 
610 static status_t
611 device_close(void* dev)
612 {
613 	(void)dev;		// avoid compiler warning for unused arg
614 
615 	TRACE("device_close()\n");
616 	return B_NO_ERROR;
617 }
618 
619 
620 static status_t
621 device_free(void* dev)
622 {
623 	DeviceInfo& di = *((DeviceInfo*)dev);
624 
625 	TRACE("enter device_free()\n");
626 
627 	gLock.Acquire();		// lock driver
628 
629 	// If opened multiple times, merely decrement the open count and exit.
630 
631 	if (di.openCount <= 1)
632 		DeleteAreas(di);
633 
634 	if (di.openCount > 0)
635 		di.openCount--;		// mark device available
636 
637 	gLock.Release();	// unlock driver
638 
639 	TRACE("exit device_free() openCount: %" B_PRId32 "\n", di.openCount);
640 	return B_OK;
641 }
642 
643 
644 static status_t
645 device_ioctl(void* dev, uint32 msg, void* buffer, size_t bufferLength)
646 {
647 	DeviceInfo& di = *((DeviceInfo*)dev);
648 
649 	TRACE("device_ioctl(); ioctl: %" B_PRIu32 ", buffer: 0x%" B_PRIXADDR ", "
650 		"bufLen: %lu\n", msg, (addr_t)buffer, bufferLength);
651 
652 	switch (msg) {
653 		case B_GET_ACCELERANT_SIGNATURE:
654 			strcpy((char*)buffer, ACCELERANT_NAME);
655 			TRACE("Intel 810 accelerant: %s\n", ACCELERANT_NAME);
656 			return B_OK;
657 
658 		case INTEL_DEVICE_NAME:
659 			strncpy((char*)buffer, di.name, B_OS_NAME_LENGTH);
660 			((char*)buffer)[B_OS_NAME_LENGTH -1] = '\0';
661 			return B_OK;
662 
663 		case INTEL_GET_SHARED_DATA:
664 			if (bufferLength != sizeof(area_id))
665 				return B_BAD_DATA;
666 
667 			*((area_id*)buffer) = di.sharedArea;
668 			return B_OK;
669 
670 		case INTEL_GET_EDID:
671 		{
672 			if (bufferLength != sizeof(edid1_raw))
673 				return B_BAD_DATA;
674 
675 			edid1_raw rawEdid;
676 			status_t status = GetEdidFromBIOS(rawEdid);
677 			if (status == B_OK)
678 				user_memcpy((edid1_raw*)buffer, &rawEdid, sizeof(rawEdid));
679 			return status;
680 		}
681 	}
682 
683 	return B_DEV_INVALID_IOCTL;
684 }
685