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
42struct 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
50static const ChipInfo chipTable[] = {
51	{ 0x7121, "i810" },
52	{ 0x7123, "i810-dc100" },
53	{ 0x7125, "i810e" },
54	{ 0x1132, "i815" },
55	{ 0, NULL }
56};
57
58
59struct 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
73static Benaphore		gLock;
74static DeviceInfo		gDeviceInfo[MAX_DEVICES];
75static char*			gDeviceNames[MAX_DEVICES + 1];
76static pci_module_info*	gPCI;
77
78
79// Prototypes for device hook functions.
80static status_t device_open(const char* name, uint32 flags, void** cookie);
81static status_t device_close(void* dev);
82static status_t device_free(void* dev);
83static status_t device_read(void* dev, off_t pos, void* buf, size_t* len);
84static status_t device_write(void* dev, off_t pos, const void* buf,
85	size_t* len);
86static status_t device_ioctl(void* dev, uint32 msg, void* buf, size_t len);
87
88static 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
127static inline uint32
128GetPCI(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
135static inline void
136SetPCI(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
143static status_t
144GetEdidFromBIOS(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
232out:
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
241static status_t
242InitDevice(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
361static void
362DeleteAreas(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
386static const ChipInfo*
387GetNextSupportedDevice(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
425status_t
426init_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
452status_t
453init_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
507void
508uninit_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
518const char**
519publish_devices(void)
520{
521	return (const char**)gDeviceNames;	// return list of supported devices
522}
523
524
525device_hooks*
526find_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
542static status_t
543device_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
582static status_t
583device_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
596static status_t
597device_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
610static status_t
611device_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
620static status_t
621device_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
644static status_t
645device_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