1/******************************************************************************
2/
3/	File:			Radeon.cpp
4/
5/	Description:	ATI Radeon Graphics Chip interface.
6/
7/	Copyright 2001, Carlos Hasan
8/
9*******************************************************************************/
10
11#include <unistd.h>
12#include <dirent.h>
13#include <Debug.h>
14#include <string.h>
15//#include "Driver.h"
16#include "Radeon.h"
17#include "OS.h"
18
19static const char * const C_RADEON_REGISTER_AREA_NAME = "RadeonRegisters";
20static const char * const C_RADEON_MEMORY_AREA_NAME = "RadeonMemory";
21static const char * const C_RADEON_ROM_AREA_NAME = "RadeonROM";
22
23// CRadeonRect
24CRadeonRect::CRadeonRect()
25	:	fLeft(0),
26		fTop(0),
27		fRight(0),
28		fBottom(0)
29{
30}
31
32CRadeonRect::CRadeonRect(int left, int top, int right, int bottom)
33	:	fLeft(left),
34		fTop(top),
35		fRight(right),
36		fBottom(bottom)
37{
38}
39
40int CRadeonRect::Left() const
41{
42	return fLeft;
43}
44
45int CRadeonRect::Top() const
46{
47	return fTop;
48}
49
50int CRadeonRect::Right() const
51{
52	return fRight;
53}
54
55int CRadeonRect::Bottom() const
56{
57	return fBottom;
58}
59
60int CRadeonRect::Width() const
61{
62	return fRight - fLeft + 1;
63}
64
65int CRadeonRect::Height() const
66{
67	return fBottom - fTop + 1;
68}
69
70void CRadeonRect::SetLeft(int value)
71{
72	fLeft = value;
73}
74
75void CRadeonRect::SetTop(int value)
76{
77	fTop = value;
78}
79
80void CRadeonRect::SetRight(int value)
81{
82	fRight = value;
83}
84
85void CRadeonRect::SetBottom(int value)
86{
87	fBottom = value;
88}
89
90void CRadeonRect::SetTo(int left, int top, int right, int bottom)
91{
92	fLeft = left;
93	fTop = top;
94	fRight = right;
95	fBottom = bottom;
96}
97
98void CRadeonRect::MoveTo(int left, int top)
99{
100	fRight += left - fLeft;
101	fBottom += top - fTop;
102	fLeft += left - fLeft;
103	fTop += top - fTop;
104}
105
106void CRadeonRect::ResizeTo(int width, int height)
107{
108	fRight = fLeft + width - 1;
109	fBottom = fTop + height - 1;
110}
111
112
113// CRadeon
114CRadeon::CRadeon( const char *dev_name )
115	:	fHandle(0),
116		fRegister(NULL),
117		fROM(NULL),
118		fVirtualCard(NULL),
119		fSharedInfo(NULL),
120		fRegisterArea(0),
121		fROMArea(0),
122		fVirtualCardArea(0),
123		fSharedInfoArea(0),
124		caps_video_in(0)
125{
126	PRINT(("CRadeon::CRadeon()\n"));
127
128	if ((fHandle = open(dev_name, O_RDWR | O_CLOEXEC)) < 0) {
129		PRINT(("CRadeon::CRadeon() - Can't open kernel driver\n"));
130		return;
131	}
132
133	radeon_get_private_data gpd;
134
135	if (GetDeviceInformation(gpd) < B_OK) {
136		PRINT(("CRadeon::CRadeon() - Can't get device information\n"));
137		return;
138	}
139
140	CloneArea(
141		"Radeon virtual card", gpd.virtual_card_area,
142		&fVirtualCardArea, (void **)&fVirtualCard );
143	CloneArea(
144		"Radeon shared info", gpd.shared_info_area,
145		&fSharedInfoArea, (void **)&fSharedInfo );
146
147	if( fSharedInfo != NULL )  {
148		CloneArea(
149			"Radeon regs", fSharedInfo->regs_area,
150			&fRegisterArea, (void **)&fRegister );
151		CloneArea(
152			"Radeon ROM", fSharedInfo->ROM_area,
153			&fROMArea, (void **)&fROM );
154	}
155
156	if (fVirtualCard == NULL || fSharedInfo == NULL ||
157		fROM == NULL || fRegister == NULL)
158	{
159		PRINT(("CRadeon::CRadeon() - Can't map memory apertures\n"));
160		return;
161	}
162
163	PRINT(("CRadeon::CRadeon() - ATI Radeon found\n"));
164}
165
166CRadeon::~CRadeon()
167{
168	PRINT(("CRadeon::~CRadeon()\n"));
169
170	if( fVirtualCard != NULL )
171		delete_area( fVirtualCardArea );
172
173	if( fSharedInfo != NULL )
174		delete_area( fSharedInfoArea );
175
176	if (fRegister != NULL)
177		delete_area( fRegisterArea );
178
179	if (fROM != NULL)
180		delete_area( fROMArea );
181
182	if (fHandle >= 0)
183		close(fHandle);
184}
185
186status_t CRadeon::InitCheck() const
187{
188	return
189		(fHandle >= 0 &&
190		fRegister != NULL && fROM != NULL &&
191		fVirtualCard != NULL && fSharedInfo != NULL) ? B_OK : B_ERROR;
192}
193
194uint32 CRadeon::VirtualMemoryBase() const
195{
196	return fSharedInfo->memory[mt_local].virtual_addr_start;
197}
198
199int CRadeon::Register(radeon_register index) const
200{
201	return fRegister[index >> 2];
202}
203
204void CRadeon::SetRegister(radeon_register index, int value)
205{
206	fRegister[index >> 2] = value;
207}
208
209int CRadeon::Register(radeon_register index, int mask) const
210{
211	return fRegister[index >> 2] & mask;
212}
213
214void CRadeon::SetRegister(radeon_register index, int mask, int value)
215{
216#ifdef DEBUG
217	if ((value & ~mask) != 0)
218		PRINT(("CRadeon::SetRegister(0x%04x, 0x%08x, 0x%08x)\n", index, mask, value));
219#endif
220
221	fRegister[index >> 2] = (fRegister[index >> 2] & ~mask) | (value & mask);
222}
223
224int CRadeon::VIPRegister(int device, int address)
225{
226	radeon_vip_read vr;
227	status_t res;
228
229	vr.magic = RADEON_PRIVATE_DATA_MAGIC;
230	vr.channel = device;
231	vr.address = address;
232	vr.lock = true;
233
234	res = ioctl( fHandle, RADEON_VIPREAD, &vr, sizeof( vr ));
235
236	if( res == B_OK )
237		return vr.data;
238	else
239		return -1;
240}
241
242void CRadeon::SetVIPRegister(int device, int address, int value)
243{
244	radeon_vip_write vw;
245
246	vw.magic = RADEON_PRIVATE_DATA_MAGIC;
247	vw.channel = device;
248	vw.address = address;
249	vw.data = value;
250	vw.lock = true;
251
252	ioctl( fHandle, RADEON_VIPWRITE, &vw, sizeof( vw ));
253}
254
255
256int CRadeon::VIPReadFifo(int device, uint32 address, uint32 count, uint8 *buffer)
257{
258	radeon_vip_fifo_read vr;
259	status_t res;
260
261	vr.magic = RADEON_PRIVATE_DATA_MAGIC;
262	vr.channel = device;
263	vr.address = address;
264	vr.count = count;
265	vr.data = buffer;
266	vr.lock = true;
267
268	res = ioctl( fHandle, RADEON_VIPFIFOREAD, &vr, sizeof( vr ));
269	if( res == B_OK )
270		return TRUE;
271	else
272		return FALSE;
273
274}
275
276int CRadeon::VIPWriteFifo(int device, uint32 address, uint32 count, uint8 *buffer)
277{
278	radeon_vip_fifo_write vw;
279	status_t res;
280
281	vw.magic = RADEON_PRIVATE_DATA_MAGIC;
282	vw.channel = device;
283	vw.address = address;
284	vw.count = count;
285	vw.data = buffer;
286	vw.lock = true;
287
288	res = ioctl( fHandle, RADEON_VIPFIFOWRITE, &vw, sizeof( vw ));
289
290	if( res == B_OK )
291		return TRUE;
292	else
293		return FALSE;
294}
295
296
297int CRadeon::FindVIPDevice( uint32 device_id )
298{
299	radeon_find_vip_device fvd;
300	status_t res;
301
302	fvd.magic = RADEON_PRIVATE_DATA_MAGIC;
303	fvd.device_id = device_id;
304
305	res = ioctl( fHandle, RADEON_FINDVIPDEVICE, &fvd, sizeof( fvd ));
306
307	if( res == B_OK )
308		return fvd.channel;
309	else
310		return -1;
311}
312
313shared_info* CRadeon::GetSharedInfo()
314{
315	return fSharedInfo;
316}
317
318void CRadeon::GetPLLParameters(int & refFreq, int & refDiv, int & minFreq, int & maxFreq, int & xclock)
319{
320	refFreq = fSharedInfo->pll.ref_freq;
321	refDiv = fSharedInfo->pll.ref_div;
322	minFreq = fSharedInfo->pll.min_pll_freq;
323	maxFreq = fSharedInfo->pll.max_pll_freq;
324	xclock = fSharedInfo->pll.xclk;
325}
326
327void CRadeon::GetMMParameters(radeon_video_tuner & tuner,
328							  radeon_video_decoder & video,
329							  radeon_video_clock & clock,
330							  int & tunerPort,
331							  int & compositePort,
332							  int & svideoPort)
333{
334
335	unsigned char * fMMTable = NULL;
336
337	PRINT(("CRadeon::GetMMParameters()\n"));
338
339	if (fSharedInfo->is_atombios) {
340		uint16 hdr  = fROM[0x48] + (fROM[0x49] << 8);
341		uint16 PCIR = hdr + fROM[hdr] + (fROM[hdr + 1] << 8);
342		uint16 hdr2 = fROM[PCIR - 4] + (fROM[PCIR - 3] << 8);
343		uint16 hmMedia = fROM[hdr2 + 8] + (fROM[hdr2 + 9] << 8);
344		if(fROM[hmMedia    ] == 0x14
345		&& fROM[hmMedia + 1] == 0x00
346		&& fROM[hmMedia + 2] == 0x01
347		&& fROM[hmMedia + 3] == 0x01
348		&& fROM[hmMedia + 4] == '$'
349		&& fROM[hmMedia + 5] == 'M'
350		&& fROM[hmMedia + 6] == 'M'
351		&& fROM[hmMedia + 7] == 'T') {
352			fMMTable = &fROM[hmMedia + 8];
353			PRINT(("ATOMBIOS MM Table Signiture found\n"));
354		} else {
355			PRINT(("ATOMBIOS MM Table Not Found\n"));
356			return;
357		}
358	} else {
359		unsigned char *fVideoBIOS = fROM + fROM[0x48] + (fROM[0x49] << 8);
360		fMMTable = fROM + fVideoBIOS[0x38] + (fVideoBIOS[0x39] << 8) - 2;
361
362		if (fMMTable[0] != 0x0c)
363		{
364			PRINT(("MM_TABLE invalid size\n"));
365			return;
366		}
367		else
368		{
369			PRINT(("MM Table Found (non ATOM) \n"));
370			PRINT(("Revision      %02x\n", fMMTable[0]));
371			PRINT(("Size          %02x\n", fMMTable[2]));
372			fMMTable += 2;
373		}
374	}
375
376
377	// check table:
378	PRINT(( "MM_TABLE:\n"));
379	const char* names[] = {
380			"Tuner Type    %02x\n",
381			"Audio Chip    %02x\n",
382			"Product ID    %02x\n",
383			"Tuner misc    %02x\n",
384			"I2C Config    %02x\n",
385			"Vid Decoder   %02x\n",
386			"..Host config %02x\n",
387			"input 0       %02x\n",
388			"input 1       %02x\n",
389			"input 2       %02x\n",
390			"input 3       %02x\n",
391			"input 4       %02x\n",
392			0
393	};
394
395	int i = 0;
396	while(names[i]) {
397		PRINT((names[i], fMMTable[i]));
398		i++;
399	}
400
401	switch (fMMTable[0] & 0x1f) {
402	case 0x00:
403		tuner = C_RADEON_NO_TUNER;
404		PRINT(("CRadeon::GetMMParameters() No Tuner\n"));
405		break;
406	case 0x01:
407		tuner = C_RADEON_FI1236_MK1_NTSC;
408		break;
409	case 0x02:
410		tuner = C_RADEON_FI1236_MK2_NTSC_JAPAN;
411		break;
412	case 0x03:
413		tuner = C_RADEON_FI1216_MK2_PAL_BG;
414		break;
415	case 0x04:
416		tuner = C_RADEON_FI1246_MK2_PAL_I;
417		break;
418	case 0x05:
419		tuner = C_RADEON_FI1216_MF_MK2_PAL_BG_SECAM_L;
420		break;
421	case 0x06:
422		tuner = C_RADEON_FI1236_MK2_NTSC;
423		break;
424	case 0x07:
425		tuner = C_RADEON_FI1256_MK2_SECAM_DK;
426		break;
427	case 0x08:
428		tuner = C_RADEON_FI1236_MK2_NTSC;
429		break;
430	case 0x09:
431		tuner = C_RADEON_FI1216_MK2_PAL_BG;
432		break;
433	case 0x0a:
434		tuner = C_RADEON_FI1246_MK2_PAL_I;
435		break;
436	case 0x0b:
437		tuner = C_RADEON_FI1216_MK2_PAL_BG_SECAM_L;
438		break;
439	case 0x0c:
440		tuner = C_RADEON_FI1236_MK2_NTSC;
441		break;
442	case 0x0d:
443		tuner = C_RADEON_TEMIC_FN5AL_PAL_IBGDK_SECAM_DK;
444		break;
445	default:
446		tuner = C_RADEON_NO_TUNER;
447		PRINT(("CRadeon::GetMMParameters() No Tuner\n"));
448		break;
449	}
450
451	switch (fMMTable[5] & 0x0f) {
452	case 0x00:
453		video = C_RADEON_NO_VIDEO;
454		PRINT(("CRadeon::GetMMParameters() No Video\n"));
455		break;
456	case 0x01:
457		video = C_RADEON_BT819;
458		break;
459	case 0x02:
460		video = C_RADEON_BT829;
461		break;
462	case 0x03:
463		video = C_RADEON_BT829A;
464		break;
465	case 0x04:
466		video = C_RADEON_SA7111;
467		break;
468	case 0x05:
469		video = C_RADEON_SA7112;
470		break;
471	case 0x06:
472		video = C_RADEON_RAGE_THEATER;
473		PRINT(("CRadeon::GetMMParameters() Rage Theater\n"));
474		break;
475	default:
476		video = C_RADEON_NO_VIDEO;
477		PRINT(("CRadeon::GetMMParameters() No Video\n"));
478		break;
479	}
480
481	switch (fMMTable[5] & 0xf0) {
482	case 0x00:
483	case 0x10:
484	case 0x20:
485	case 0x30:
486		clock = C_RADEON_NO_VIDEO_CLOCK;
487		PRINT(("CRadeon::GetMMParameters() Video No Clock\n"));
488		break;
489	case 0x40:
490		clock = C_RADEON_VIDEO_CLOCK_28_63636_MHZ;
491		break;
492	case 0x50:
493		clock = C_RADEON_VIDEO_CLOCK_29_49892_MHZ;
494		break;
495	case 0x60:
496		clock = C_RADEON_VIDEO_CLOCK_27_00000_MHZ;
497		break;
498	case 0x70:
499		clock = C_RADEON_VIDEO_CLOCK_14_31818_MHZ;
500		break;
501	default:
502		clock = C_RADEON_NO_VIDEO_CLOCK;
503		PRINT(("CRadeon::GetMMParameters() Video No Clock\n"));
504		break;
505	}
506
507	for (int port = 0; port < 5; port++) {
508		switch (fMMTable[7 + port] & 0x03) {
509		case 0x00:
510			// Unused or Invalid
511			PRINT(("CRadeon::GetMMParameters() Invalid Port\n"));
512			break;
513		case 0x01:
514			// Tuner Input
515			PRINT(("CRadeon::GetMMParameters() Tuner Port\n"));
516			tunerPort = 0;
517			break;
518		case 0x02:
519			// Front/Rear Composite Input
520			PRINT(("CRadeon::GetMMParameters() Composite Port\n"));
521			compositePort = (fMMTable[7 + port] & 0x04 ? 2 : 1);
522			break;
523		case 0x03:
524			// Front/Rear SVideo Input
525			PRINT(("CRadeon::GetMMParameters() SVideo Port\n"));
526			svideoPort = (fMMTable[7 + port] & 0x04 ? 6 : 5);
527			break;
528		}
529	}
530}
531
532status_t CRadeon::AllocateGraphicsMemory(
533	memory_type_e memory_type, int32 size,
534	int32 *offset, int32 *handle )
535{
536	radeon_alloc_mem am;
537	status_t res;
538
539	am.magic = RADEON_PRIVATE_DATA_MAGIC;
540	am.size = size;
541	am.memory_type = mt_local;
542	am.global = false;
543
544	res = ioctl( fHandle, RADEON_ALLOC_MEM, &am );
545
546	if( res != B_OK )
547		return res;
548
549	*handle = am.handle;
550	*offset = am.offset;
551	return B_OK;
552}
553
554void CRadeon::FreeGraphicsMemory(
555	memory_type_e memory_type, int32 handle )
556{
557	radeon_free_mem fm;
558
559	fm.magic = RADEON_PRIVATE_DATA_MAGIC;
560	fm.memory_type = memory_type;
561	fm.global = false;
562	fm.handle = handle;
563
564	ioctl( fHandle, RADEON_FREE_MEM, &fm );
565}
566
567status_t CRadeon::DMACopy(
568	uint32 src, void *target, size_t size, bool lock_mem, bool contiguous )
569{
570	radeon_dma_copy dc;
571
572	dc.magic = RADEON_PRIVATE_DATA_MAGIC;
573	dc.src = src;
574	dc.target = target;
575	dc.size = size;
576	dc.lock_mem = lock_mem;
577	dc.contiguous = contiguous;
578
579	return ioctl( fHandle, RADEON_DMACOPY, &dc );
580}
581
582status_t CRadeon::GetDeviceInformation(radeon_get_private_data & info)
583{
584	info.magic = RADEON_PRIVATE_DATA_MAGIC;
585
586	return ioctl( fHandle, RADEON_GET_PRIVATE_DATA, &info, sizeof( info ));
587}
588
589status_t CRadeon::CloneArea(const char * name, area_id src_area,
590	area_id *cloned_area, void ** map)
591{
592	int res = clone_area( name, map, B_ANY_ADDRESS,
593		B_READ_AREA | B_WRITE_AREA, src_area );
594
595	if( res < 0 ) {
596		return res;
597	} else {
598		*cloned_area = res;
599		return B_OK;
600	}
601}
602
603status_t CRadeon::WaitInterrupt(int * mask, int * sequence, bigtime_t * time, bigtime_t timeout)
604{
605	radeon_wait_for_cap_irq wvc;
606	status_t status;
607
608	wvc.magic = RADEON_PRIVATE_DATA_MAGIC;
609	wvc.timeout = timeout;
610
611	status = ioctl( fHandle, RADEON_WAIT_FOR_CAP_IRQ, &wvc );
612
613	if( status == B_OK ) {
614		*mask = wvc.int_status;
615		*sequence = wvc.counter;
616		*time = wvc.timestamp;
617	}
618
619	return status;
620}
621
622#if 0
623void CRadeon::PrintToStream()
624{
625	// ATI ROM Signature
626	if (ROM(0) == 0x55 && ROM(1) == 0xAA) {
627		for (int offset = 0; offset < 128 - 9; offset++) {
628			if (ROM(offset + 0) == '7' &&
629				ROM(offset + 1) == '6' &&
630				ROM(offset + 2) == '1' &&
631				ROM(offset + 3) == '2' &&
632				ROM(offset + 4) == '9' &&
633				ROM(offset + 5) == '5' &&
634				ROM(offset + 6) == '5' &&
635				ROM(offset + 7) == '2' &&
636				ROM(offset + 8) == '0')
637				break;
638		}
639	}
640
641	// Video BIOS
642	unsigned char *fVideoBIOS = fROM + fROM[0x48] + (fROM[0x49] << 8);
643
644	PRINT((
645		"----------------------------------------------------------------------\n"
646        "ATI RADEON VIDEO BIOS\n"
647        "\n"
648        "BIOS Revision: %03d.%03d.%03d%03d.%s\n"
649        "PCI Bus/Device/Function Code: 0x%04x\n"
650        "BIOS Runtime Segment Address: 0x%04x\n"
651        "I/O Base Address: 0x%04x\n"
652        "Subsystem Vendor ID: 0x%04x\n"
653        "Subsystem ID: 0x%04x\n"
654        "Post Vendor ID: 0x%04x\n"
655        "\n",
656
657        // OEM Revision (ID1.ID2.REVISION.CONFIG_FILE)
658        fVideoBIOS[2], fVideoBIOS[3],
659        fVideoBIOS[4], fVideoBIOS[5],
660        fROM + fVideoBIOS[0x10] + (fVideoBIOS[0x11] << 8),
661
662        // PCI bus, device, function code
663        fVideoBIOS[0x16] + (fVideoBIOS[0x17] << 8),
664
665        // ROM BIOS segment
666        fVideoBIOS[0x18] + (fVideoBIOS[0x19] << 8),
667
668        // I/O base address
669        fVideoBIOS[0x1a] + (fVideoBIOS[0x1b] << 8),
670
671        // Subsystem Vendor ID, Subsystem ID, Post Vendor ID
672        fVideoBIOS[0x1c] + (fVideoBIOS[0x1d] << 8),
673        fVideoBIOS[0x1e] + (fVideoBIOS[0x1f] << 8),
674        fVideoBIOS[0x20] + (fVideoBIOS[0x21] << 8)
675    ));
676
677
678	// PLL Information
679	unsigned char *fPLL = fROM + fVideoBIOS[0x30] + (fVideoBIOS[0x31] << 8);
680
681	PRINT((
682		"----------------------------------------------------------------------\n"
683        "ATI RADEON PLL INFORMATION TABLE\n"
684        "\n"
685        "External Clock: %g MHz\n"
686        "Reference Frequency: %g MHz\n"
687        "Reference Divisor: %d\n"
688        "Min PLL Frequency: %g MHz\n"
689        "Max PLL Frequency: %g MHz\n"
690        "\n",
691		(fPLL[0x08] + (fPLL[0x09] << 8)) / 1000.0,
692		(fPLL[0x0e] + (fPLL[0x0f] << 8)) / 100.0,
693		fPLL[0x10] + (fPLL[0x11] << 8),
694		(fPLL[0x12] + (fPLL[0x13] << 8) + (fPLL[0x14] << 16) + (fPLL[0x15] << 24)) / 1000.0,
695		(fPLL[0x12] + (fPLL[0x16] << 8) + (fPLL[0x17] << 16) + (fPLL[0x18] << 24)) / 1000.0));
696
697
698	// TV Table
699	unsigned char * fTVTable = fROM + fVideoBIOS[0x32] + (fVideoBIOS[0x33] << 8);
700
701	PRINT((
702		"----------------------------------------------------------------------\n"
703        "ATI RADEON TV INFORMATION TABLE\n"
704        "\n"
705        "Table Signature: %c%c%c\n"
706        "Table Version: %d\n"
707        "Table Size: %d bytes\n"
708        "\n"
709        "TVOut Support: %s\n"
710        "BIOS built-in TV standard: %s\n"
711        "TVOut information: %s, %s MHz\n"
712        "\n"
713        "Run time supported TV standard:%s%s%s%s%s%s\n"
714        "Initialization time supported TV standard:%s%s%s%s%s%s\n"
715        "\n",
716
717        // Table signature, version and size
718        fTVTable[0x00],fTVTable[0x01], fTVTable[0x02],
719        fTVTable[0x03],
720        fTVTable[0x04] + ((int) fTVTable[0x05] << 8),
721
722        // TVOut support
723        fTVTable[0x06] == 'N' ? "TVOut chip not found" : "TVOut chip on board",
724
725        // BIOS built-in initialization TV standard
726        (fTVTable[0x07] & 0x0f) == 0x01 ? "NTSC" :
727        (fTVTable[0x07] & 0x0f) == 0x02 ? "PAL" :
728        (fTVTable[0x07] & 0x0f) == 0x03 ? "PAL-M" :
729        (fTVTable[0x07] & 0x0f) == 0x04 ? "PAL-60" :
730        (fTVTable[0x07] & 0x0f) == 0x05 ? "NTSC-J" :
731        (fTVTable[0x07] & 0x0f) == 0x06 ? "SCART-PAL" : "Reserved",
732
733        // TV Out information
734        (fTVTable[0x09] & 0x03) == 0x00 ? "Invalid" :
735        (fTVTable[0x09] & 0x03) == 0x01 ? "TV off, CRT on" :
736        (fTVTable[0x09] & 0x03) == 0x02 ? "TV on, CRT off" : "TV on, CRT on",
737
738        (fTVTable[0x09] & 0x0c) == 0x00 ? "29.498928713" :
739        (fTVTable[0x09] & 0x0c) == 0x04 ? "28.63636" :
740        (fTVTable[0x09] & 0x0c) == 0x08 ? "14.31818" : "27.0",
741
742        // Runtime supported TV standard
743        (fTVTable[0x0a] & 0x01) != 0 ? " NTSC" : "",
744        (fTVTable[0x0a] & 0x02) != 0 ? " PAL" : "",
745        (fTVTable[0x0a] & 0x04) != 0 ? " PAL-M" : "",
746        (fTVTable[0x0a] & 0x08) != 0 ? " PAL-60" : "",
747        (fTVTable[0x0a] & 0x10) != 0 ? " NTSC-J" : "",
748        (fTVTable[0x0a] & 0x20) != 0 ? " SCART-PAL" : "",
749
750        // Initialization time supported TV standard
751        (fTVTable[0x0b] & 0x01) != 0 ? " NTSC" : "",
752        (fTVTable[0x0b] & 0x02) != 0 ? " PAL" : "",
753        (fTVTable[0x0b] & 0x04) != 0 ? " PAL-M" : "",
754        (fTVTable[0x0b] & 0x08) != 0 ? " PAL-60" : "",
755        (fTVTable[0x0b] & 0x10) != 0 ? " NTSC-J" : "",
756        (fTVTable[0x0b] & 0x20) != 0 ? " SCART-PAL" : ""
757    ));
758
759    // Hardware Configuration Table
760    unsigned char * fHWTable = fROM + fVideoBIOS[0x36] + (fVideoBIOS[0x37] << 8);
761
762	PRINT((
763		"----------------------------------------------------------------------\n"
764        "ATI RADEON HARDWARE CONFIGURATION TABLE\n"
765        "\n"
766        "Table Signature: %c%c%c%c\n"
767        "Table Revision: %d\n"
768        "Table Size: %d\n"
769        "\n"
770        "I2C Type: %s\n"
771        "TVOut Support: %s\n"
772        "Video Out Crystal: %s\n"
773        "ImpactTV Data Port: %s\n"
774        "\n"
775        "Video Port Capability:\n"
776        "   AMC/DVS0 Video Port: %s\n"
777        "   Zoom Video Port: %s\n"
778        "   AMC/DVS1 Video Port: %s\n"
779        "   VIP 16-bit Video Port: %s\n"
780        "\n"
781        "Host Port Configuration: %s\n"
782        "\n",
783
784        // Table Signature, Revision, Size
785        fHWTable[0x00], fHWTable[0x01], fHWTable[0x02], fHWTable[0x03],
786        fHWTable[0x04], fHWTable[0x05],
787
788        // I2C type
789        (fHWTable[0x06] & 0x0f) == 0x00 ? "Normal GP I/O (data=GP_IO2, clock=GP_IO1)" :
790        (fHWTable[0x06] & 0x0f) == 0x01 ? "ImpacTV GP I/O" :
791        (fHWTable[0x06] & 0x0f) == 0x02 ? "Dedicated I2C Pin" :
792        (fHWTable[0x06] & 0x0f) == 0x03 ? "GP I/O (data=GP_IO12, clock=GP_IO13)" :
793        (fHWTable[0x06] & 0x0f) == 0x04 ? "GP I/O (data=GPIO12, clock=GPIO10)" :
794        (fHWTable[0x06] & 0x0f) == 0x05 ? "RAGE THEATER I2C Master" :
795        (fHWTable[0x06] & 0x0f) == 0x06 ? "Rage128 MPP2 Pin" :
796        (fHWTable[0x06] & 0x0f) == 0x0f ? "No I2C Configuration" : "Reserved",
797
798        // TVOut support
799        (fHWTable[0x07] & 0x0f) == 0x00 ? "No TVOut supported" :
800        (fHWTable[0x07] & 0x0f) == 0x01 ? "ImpactTV1 supported" :
801        (fHWTable[0x07] & 0x0f) == 0x02 ? "ImpactTV2 supported" :
802        (fHWTable[0x07] & 0x0f) == 0x03 ? "Improved ImpactTV2 supported" :
803        (fHWTable[0x07] & 0x0f) == 0x04 ? "RAGE THEATER supported" : "Reserved",
804
805        // Video Out Crystal
806        (fHWTable[0x07] & 0x70) == 0x00 ? "TVOut not installed" :
807        (fHWTable[0x07] & 0x70) == 0x10 ? "28.63636 MHz" :
808        (fHWTable[0x07] & 0x70) == 0x20 ? "29.49892713 MHz" :
809        (fHWTable[0x07] & 0x70) == 0x30 ? "27.0 MHz" :
810        (fHWTable[0x07] & 0x70) == 0x40 ? "14.31818 MHz" : "Reserved",
811
812        // ImpactTV data port
813        (fHWTable[0x07] & 0x80) == 0x00 ? "MPP1" : "MPP2",
814
815        // Video Port Capability
816        (fHWTable[0x08] & 0x01) == 0x00 ? "Not Supported" : "Supported",
817        (fHWTable[0x08] & 0x02) == 0x00 ? "Not Supported" : "Supported",
818        (fHWTable[0x08] & 0x04) == 0x00 ? "Not Supported" : "Supported",
819        (fHWTable[0x08] & 0x08) == 0x00 ? "Not Supported" : "Supported",
820
821        // Host Port Configuration
822        (fHWTable[0x09] & 0x0f) == 0x00 ? "No Host Port" :
823        (fHWTable[0x09] & 0x0f) == 0x01 ? "MPP Host Port" :
824        (fHWTable[0x09] & 0x0f) == 0x02 ? "2 bit VIP Host Port" :
825        (fHWTable[0x09] & 0x0f) == 0x03 ? "4 bit VIP Host Port" :
826        (fHWTable[0x09] & 0x0f) == 0x04 ? "8 bit VIP Host Port" : "Reserved"
827    ));
828
829	// Multimedia Table
830	unsigned char * fMMTable = fROM + fVideoBIOS[0x38] + (fVideoBIOS[0x39] << 8);
831
832    PRINT((
833    	"----------------------------------------------------------------------\n"
834        "ATI RADEON MULTIMEDIA TABLE\n"
835        "\n"
836        "Table Revision: %d\n"
837        "Table Size: %d bytes\n"
838        "\n"
839        "Tuner Chip: %s\n"
840        "Tuner Input: %s\n"
841        "Tuner Voltage Regulator: %s\n"
842        "\n"
843        "Audio Chip: %s\n"
844        "FM Audio Decoder: %s\n"
845        "Audio Scrambling: %s\n"
846        "\n"
847        "Product Type: %s, Revision %d\n"
848        "Product ID: %s\n"
849        "\n"
850        "I2S Input Configuration: %s\n"
851        "I2S Output Configuration: %s\n"
852        "I2S Audio Chip: %s\n"
853        "S/PDIF Output Configuration: %s\n"
854        "\n"
855        "Video Decoder: %s\n"
856        "Video Standard/Crystal: %s\n"
857        "Video Decoder Host Config: %s\n"
858        "Hardware Teletext: %s\n"
859        "\n"
860        "Video Input:\n"
861        "    0: %s, %s (ID %d)\n"
862        "    1: %s, %s (ID %d)\n"
863        "    2: %s, %s (ID %d)\n"
864        "    3: %s, %s (ID %d)\n"
865        "    4: %s, %s (ID %d)\n"
866        "\n",
867
868        /* Hardware Table */
869        fMMTable[-2], fMMTable[-1],
870
871        /* Tuner Type */
872        (fMMTable[0] & 0x1f) == 0x00 ? "No Tuner" :
873        (fMMTable[0] & 0x1f) == 0x01 ? "Philips FI1236 MK1 NTSC M/N North America" :
874        (fMMTable[0] & 0x1f) == 0x02 ? "Philips FI1236 MK2 NTSC M/N Japan" :
875
876        (fMMTable[0] & 0x1f) == 0x03 ? "Philips FI1216 MK2 PAL B/G" :
877        (fMMTable[0] & 0x1f) == 0x04 ? "Philips FI1246 MK2 PAL I" :
878        (fMMTable[0] & 0x1f) == 0x05 ? "Philips FI1216 MF MK2 PAL B/G, SECAM L/L'" :
879        (fMMTable[0] & 0x1f) == 0x06 ? "Philips FI1236 MK2 NTSC M/N North America" :
880        (fMMTable[0] & 0x1f) == 0x07 ? "Philips FI1256 MK2 SECAM D/K" :
881        (fMMTable[0] & 0x1f) == 0x08 ? "Philips FM1236 MK2 NTSC M/N North America" :
882
883        (fMMTable[0] & 0x1f) == 0x09 ? "Philips FI1216 MK2 PAL B/G - External Tuner POD" :
884        (fMMTable[0] & 0x1f) == 0x0a ? "Philips FI1246 MK2 PAL I - External Tuner POD" :
885        (fMMTable[0] & 0x1f) == 0x0b ? "Philips FI1216 MF MK2 PAL B/G, SECAM L/L' - External Tuner POD" :
886        (fMMTable[0] & 0x1f) == 0x0c ? "Philips FI1236 MK2 NTSC M/N North America - External Tuner POD" :
887
888        (fMMTable[0] & 0x1f) == 0x0d ? "Temic FN5AL RF3X7595 PAL I/B/G/DK & SECAM DK" :
889        (fMMTable[0] & 0x1f) == 0x10 ? "Alps TSBH5 NTSC M/N North America" :
890        (fMMTable[0] & 0x1f) == 0x11 ? "Alps TSC?? NTSC M/N North America" :
891        (fMMTable[0] & 0x1f) == 0x12 ? "Alps TSCH5 NTSC M/N North America" :
892
893        (fMMTable[0] & 0x1f) == 0x1f ? "Unknown Tuner Type" : "Reserved",
894
895        /* Video Input for Tuner */
896        (fMMTable[0] & 0xe0) == 0x00 ? "Video Input 0" :
897        (fMMTable[0] & 0xe0) == 0x20 ? "Video Input 1" :
898        (fMMTable[0] & 0xe0) == 0x40 ? "Video Input 2" :
899        (fMMTable[0] & 0xe0) == 0x60 ? "Video Input 3" :
900        (fMMTable[0] & 0xe0) == 0x80 ? "Video Input 4" : "Reserved",
901
902        /* Tuner Voltage */
903        (fMMTable[3] & 0x03) == 0x00 ? "No Tuner Power down feature" :
904        (fMMTable[3] & 0x03) == 0x01 ? "Tuner Power down feature" : "Reserved",
905
906        /* Audio Chip Type */
907        (fMMTable[1] & 0x0f) == 0x00 ? "Philips TEA5582 NTSC Stereo, no dbx, no volume" :
908        (fMMTable[1] & 0x0f) == 0x01 ? "Mono with audio mux" :
909        (fMMTable[1] & 0x0f) == 0x02 ? "Philips TDA9850 NTSC N.A. Stereo, dbx, mux, no volume" :
910        (fMMTable[1] & 0x0f) == 0x03 ? "Sony CXA2020S Japan NTSC Stereo, mux, no volume" :
911        (fMMTable[1] & 0x0f) == 0x04 ? "ITT MSP3410D Europe Stereo, volume, internal mux" :
912        (fMMTable[1] & 0x0f) == 0x05 ? "Crystal CS4236B" :
913        (fMMTable[1] & 0x0f) == 0x06 ? "Philips TDA9851 NTSC Stereo, volume, no dbx, no mux" :
914        (fMMTable[1] & 0x0f) == 0x07 ? "ITT MSP3415 (Europe)" :
915        (fMMTable[1] & 0x0f) == 0x08 ? "ITT MSP3430 (N.A.)" :
916        (fMMTable[1] & 0x0f) == 0x0f ? "No Audio Chip Installed" : "Reserved",
917
918        /* FM Audio Decoder */
919        (fMMTable[3] & 0x30) == 0x00 ? "No FM Audio Decoder" :
920        (fMMTable[3] & 0x30) == 0x10 ? "FM Audio Decoder (Rohm BA1332F)" : "Reserved",
921
922        /* Audio Scrambling */
923        (fMMTable[3] & 0x80) == 0x00 ? "Not Supported" : "Supported",
924
925        /* Product Type */
926        (fMMTable[1] & 0x10) == 0x00 ? "OEM Product" : "ATI Product",
927
928        /* OEM Revision */
929        (fMMTable[1] & 0xe0) >> 5,
930
931        /* Product ID */
932        (fMMTable[1] & 0x10) == 0x00 ? "<OEM ID>" :
933        (
934            fMMTable[2] == 0x00 ? "ATI Prototype Board" :
935            fMMTable[2] == 0x01 ? "ATI All in Wonder" :
936            fMMTable[2] == 0x02 ? "ATI All in Wonder Pro, no MPEG/DVD decoder" :
937            fMMTable[2] == 0x03 ? "ATI All in Wonder Pro, CD11 or similar MPEG/DVD decoder on MPP" :
938            fMMTable[2] == 0x04 ? "ATI All in Wonder Plus" :
939            fMMTable[2] == 0x05 ? "ATI Kitchener Board" :
940            fMMTable[2] == 0x06 ? "ATI Toronto Board (analog audio)" :
941            fMMTable[2] == 0x07 ? "ATI TV-Wonder" :
942            fMMTable[2] == 0x08 ? "ATI Victoria Board (Rage XL plus RAGE THEATER)" : "Reserved"
943        ),
944
945        /* I2S Input/Output Configuration */
946        (fMMTable[4] & 0x01) == 0x00 ? "Not Supported" : "Supported",
947        (fMMTable[4] & 0x02) == 0x00 ? "Not Supported" : "Supported",
948
949        /* I2S Audio Chip */
950        (fMMTable[4] & 0x1c) == 0x00 ? "TDA1309_32Strap" :
951        (fMMTable[4] & 0x1c) == 0x04 ? "TDA1309_64Strap" :
952        (fMMTable[4] & 0x1c) == 0x08 ? "ITT MSP3430" :
953        (fMMTable[4] & 0x1c) == 0x0c ? "ITT MSP3415" : "Reserved",
954
955        /* S/PDIF Output Config */
956        (fMMTable[4] & 0x20) == 0x00 ? "Not Supported" : "Supported",
957
958        /* Video Decoder Type */
959        (fMMTable[5] & 0x0f) == 0x00 ? "No Video Decoder" :
960        (fMMTable[5] & 0x0f) == 0x01 ? "Bt819" :
961        (fMMTable[5] & 0x0f) == 0x02 ? "Bt829" :
962        (fMMTable[5] & 0x0f) == 0x03 ? "Bt829A" :
963        (fMMTable[5] & 0x0f) == 0x04 ? "Philips SA7111" :
964        (fMMTable[5] & 0x0f) == 0x05 ? "Philips SA7112 or SA7112A" :
965        (fMMTable[5] & 0x0f) == 0x06 ? "RAGE THEATER" : "Reserved",
966
967        /* Video-In Standard/Crystal */
968        (fMMTable[5] & 0xf0) == 0x00 ? "NTSC and PAL Crystals installed" :
969        (fMMTable[5] & 0xf0) == 0x10 ? "NTSC Crystal only" :
970        (fMMTable[5] & 0xf0) == 0x20 ? "PAL Crystal only" :
971        (fMMTable[5] & 0xf0) == 0x30 ? "NTSC, PAL, SECAM Ssingle crystal for Bt829 and Bt879" :
972        (fMMTable[5] & 0xf0) == 0x40 ? "28.63636 MHz Crystal" :
973        (fMMTable[5] & 0xf0) == 0x50 ? "29.49892713 MHz Crystal" :
974        (fMMTable[5] & 0xf0) == 0x60 ? "27.0 MHz Crystal" :
975        (fMMTable[5] & 0xf0) == 0x70 ? "14.31818 MHz Crystal" : "Reserved",
976
977        /* Video Decoder Host Config */
978        (fMMTable[6] & 0x07) == 0x00 ? "I2C Device" :
979        (fMMTable[6] & 0x07) == 0x01 ? "MPP Device" :
980        (fMMTable[6] & 0x07) == 0x02 ? "2 bits VIP Device" :
981        (fMMTable[6] & 0x07) == 0x03 ? "4 bits VIP Device" :
982        (fMMTable[6] & 0x07) == 0x04 ? "8 bits VIP Device" :
983        (fMMTable[6] & 0x07) == 0x07 ? "PCI Device" : "Reserved",
984
985        /* Hardware Teletext */
986        (fMMTable[3] & 0x0c) == 0x00 ? "No Hardware Teletext" :
987        (fMMTable[3] & 0x0c) == 0x04 ? "Philips SAA5281" : "Reserved",
988
989        /* Video Input 0 */
990        (fMMTable[7] & 0x03) == 0x00 ? "Unused/Invalid" :
991        (fMMTable[7] & 0x03) == 0x01 ? "Tuner Input" :
992        (fMMTable[7] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
993        (fMMTable[7] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
994        (fMMTable[7] & 0x38) >> 3,
995
996        /* Video Input 1 */
997        (fMMTable[8] & 0x03) == 0x00 ? "Unused/Invalid" :
998        (fMMTable[8] & 0x03) == 0x01 ? "Tuner Input" :
999        (fMMTable[8] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
1000        (fMMTable[8] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
1001        (fMMTable[8] & 0x38) >> 3,
1002
1003        /* Video Input 2 */
1004        (fMMTable[9] & 0x03) == 0x00 ? "Unused/Invalid" :
1005        (fMMTable[9] & 0x03) == 0x01 ? "Tuner Input" :
1006        (fMMTable[9] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
1007        (fMMTable[9] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
1008        (fMMTable[9] & 0x38) >> 3,
1009
1010        /* Video Input 3 */
1011        (fMMTable[10] & 0x03) == 0x00 ? "Unused/Invalid" :
1012        (fMMTable[10] & 0x03) == 0x01 ? "Tuner Input" :
1013        (fMMTable[10] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
1014        (fMMTable[10] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
1015        (fMMTable[10] & 0x38) >> 3,
1016
1017        /* Video Input 4 */
1018        (fMMTable[11] & 0x03) == 0x00 ? "Unused/Invalid" :
1019        (fMMTable[11] & 0x03) == 0x01 ? "Tuner Input" :
1020        (fMMTable[11] & 0x03) == 0x02 ? "Composite Input" : "S-Video Input",
1021        (fMMTable[11] & 0x04) == 0x00 ? "Front Connector" : "Rear Connector",
1022        (fMMTable[11] & 0x38) >> 3
1023    ));
1024}
1025#endif
1026