1/******************************************************************************
2/
3/	File:			Theater.cpp
4/
5/	Description:	ATI Rage Theater Video Decoder interface.
6/
7/	Copyright 2001, Carlos Hasan
8/
9*******************************************************************************/
10
11#include <Debug.h>
12#include "Theater.h"
13#include "Theater200.h"
14#include "TheatreReg.h"
15#include "lendian_bitfield.h"
16#include <stdio.h>
17#include <stdlib.h>
18#include <OS.h>
19
20
21const char* DEFAULT_MICROC_PATH = "/boot/home/config/settings/Media/RageTheater200/ativmc20.cod";
22const char* DEFAULT_MICROC_TYPE = "BINARY";
23
24CTheater200::CTheater200(CRadeon & radeon, int device)
25		:CTheater(radeon, device),
26		fMode(MODE_UNINITIALIZED),
27		microcode_path(NULL),
28		microcode_type(NULL)
29
30{
31	PRINT(("CTheater200::CTheater200()\n"));
32
33	fMode = MODE_UNINITIALIZED;
34
35	if( fPort.InitCheck() == B_OK ) {
36		radeon_video_tuner tuner;
37		radeon_video_decoder video;
38
39		radeon.GetMMParameters(tuner, video, fClock,
40			fTunerPort, fCompositePort, fSVideoPort);
41
42		if (fClock != C_RADEON_VIDEO_CLOCK_29_49892_MHZ &&
43			fClock != C_RADEON_VIDEO_CLOCK_27_00000_MHZ)
44			PRINT(("CTheater200::CTheater200() - Unsupported crystal clock!\n"));
45
46		// fDevice = fPort.FindVIPDevice( C_THEATER200_VIP_DEVICE_ID );
47
48	}
49
50	if( InitCheck() != B_OK )
51		PRINT(("CTheater200::CTheater200() - Rage Theater not found!\n"));
52
53	InitTheatre();
54
55}
56
57CTheater200::~CTheater200()
58{
59	PRINT(("CTheater200::~CTheater200()\n"));
60
61	if( InitCheck() == B_OK )
62		SetEnable(false, false);
63
64}
65
66status_t CTheater200::InitCheck() const
67{
68	status_t res;
69
70	res = fPort.InitCheck();
71	if( res != B_OK )
72	{
73		PRINT(("CTheater200::InitCheck() fPort Failed\n"));
74		return res;
75	}
76
77	res = (fDevice >= C_VIP_PORT_DEVICE_0 && fDevice <= C_VIP_PORT_DEVICE_3) ? B_OK : B_ERROR;
78	if( res != B_OK )
79	{
80		PRINT(("CTheater200::InitCheck() Invalid VIP Channel\n"));
81		return res;
82	}
83
84	if (fMode != MODE_INITIALIZED_FOR_TV_IN);
85		return B_ERROR;
86
87	PRINT(("CTheater200::InitCheck() Sucess\n"));
88	return res;
89}
90
91void CTheater200::Reset()
92{
93	PRINT(("CTheater200::Reset()\n"));
94
95	SetHue(0);
96	SetBrightness(0);
97	SetSaturation(0);
98	SetContrast(0);
99	SetSharpness(false);
100}
101
102status_t CTheater200::DSPLoadMicrocode(char* micro_path, char* micro_type, struct rt200_microc_data* microc_datap)
103{
104	FILE* file;
105	struct rt200_microc_head* microc_headp = &microc_datap->microc_head;
106	struct rt200_microc_seg* seg_list = NULL;
107	struct rt200_microc_seg* curr_seg = NULL;
108	struct rt200_microc_seg* prev_seg = NULL;
109	uint32 i;
110
111	if (micro_path == NULL)
112		return -1;
113
114	if (micro_type == NULL)
115		return -1;
116
117	file = fopen(micro_path, "r");
118	if (file == NULL) {
119		PRINT(("Cannot open microcode file\n"));
120		return -1;
121	}
122
123	if (!strcmp(micro_type, "BINARY"))
124	{
125		if (fread(microc_headp, sizeof(struct rt200_microc_head), 1, file) != 1)
126		{
127			PRINT(("Cannot read header from file: %s\n", micro_path));
128			goto fail_exit;
129		}
130
131		PRINT(("Microcode: num_seg: %x\n", microc_headp->num_seg));
132
133		if (microc_headp->num_seg == 0)
134			goto fail_exit;
135
136		for (i = 0; i < microc_headp->num_seg; i++)
137		{
138			int ret;
139
140			curr_seg = (struct rt200_microc_seg*) malloc(sizeof(struct rt200_microc_seg));
141			if (curr_seg == NULL)
142			{
143				PRINT(("Cannot allocate memory\n"));
144				goto fail_exit;
145			}
146
147			ret = fread(&curr_seg->num_bytes, 4, 1, file);
148			ret += fread(&curr_seg->download_dst, 4, 1, file);
149			ret += fread(&curr_seg->crc_val, 4, 1, file);
150			if (ret != 3)
151			{
152				PRINT(("Cannot read segment from microcode file: %s\n", micro_path));
153				goto fail_exit;
154			}
155
156			curr_seg->data = (unsigned char*) malloc(curr_seg->num_bytes);
157			if (curr_seg->data == NULL)
158			{
159				PRINT(("cannot allocate memory\n"));
160				goto fail_exit;
161			}
162
163			PRINT(("Microcode: segment number: %x\n", i));
164			PRINT(("Microcode: curr_seg->num_bytes: %x\n", curr_seg->num_bytes));
165			PRINT(("Microcode: curr_seg->download_dst: %x\n", curr_seg->download_dst));
166			PRINT(("Microcode: curr_seg->crc_val: %x\n", curr_seg->crc_val));
167
168			if (seg_list)
169			{
170				prev_seg->next = curr_seg;
171				curr_seg->next = NULL;
172				prev_seg = curr_seg;
173			}
174			else
175				seg_list = prev_seg = curr_seg;
176
177		}
178
179		curr_seg = seg_list;
180		while (curr_seg)
181		{
182			if ( fread(curr_seg->data, curr_seg->num_bytes, 1, file) != 1 )
183			{
184				PRINT(("Cannot read segment data\n"));
185				goto fail_exit;
186			}
187
188			curr_seg = curr_seg->next;
189		}
190	}
191	else if (!strcmp(micro_type, "ASCII"))
192	{
193		char tmp1[12], tmp2[12], tmp3[12], tmp4[12];
194		unsigned int ltmp;
195
196		if ((fgets(tmp1, 12, file) != NULL) &&
197			(fgets(tmp2, 12, file) != NULL) &&
198			(fgets(tmp3, 12, file) != NULL) &&
199			 fgets(tmp4, 12, file) != NULL)
200		{
201			microc_headp->device_id = strtoul(tmp1, NULL, 16);
202			microc_headp->vendor_id = strtoul(tmp2, NULL, 16);
203			microc_headp->revision_id = strtoul(tmp3, NULL, 16);
204			microc_headp->num_seg = strtoul(tmp4, NULL, 16);
205		}
206		else
207		{
208			PRINT(("Cannot read header from file: %s\n", micro_path));
209			goto fail_exit;
210		}
211
212		PRINT(("Microcode: num_seg: %x\n", microc_headp->num_seg));
213
214		if (microc_headp->num_seg == 0)
215			goto fail_exit;
216
217		for (i = 0; i < microc_headp->num_seg; i++)
218		{
219			curr_seg = (struct rt200_microc_seg*) malloc(sizeof(struct rt200_microc_seg));
220			if (curr_seg == NULL)
221			{
222				PRINT(("Cannot allocate memory\n"));
223				goto fail_exit;
224			}
225
226			if (fgets(tmp1, 12, file) != NULL &&
227				fgets(tmp2, 12, file) != NULL &&
228				fgets(tmp3, 12, file) != NULL)
229			{
230				curr_seg->num_bytes = strtoul(tmp1, NULL, 16);
231				curr_seg->download_dst = strtoul(tmp2, NULL, 16);
232				curr_seg->crc_val = strtoul(tmp3, NULL, 16);
233			}
234			else
235			{
236				PRINT(("Cannot read segment from microcode file: %s\n", micro_path));
237				goto fail_exit;
238			}
239
240			curr_seg->data = (unsigned char*) malloc(curr_seg->num_bytes);
241			if (curr_seg->data == NULL)
242			{
243				PRINT(("cannot allocate memory\n"));
244				goto fail_exit;
245			}
246
247			PRINT(("Microcode: segment number: %x\n", i));
248			PRINT(("Microcode: curr_seg->num_bytes: %x\n", curr_seg->num_bytes));
249			PRINT(("Microcode: curr_seg->download_dst: %x\n", curr_seg->download_dst));
250			PRINT(("Microcode: curr_seg->crc_val: %x\n", curr_seg->crc_val));
251
252			if (seg_list)
253			{
254				curr_seg->next = NULL;
255				prev_seg->next = curr_seg;
256				prev_seg = curr_seg;
257			}
258			else
259				seg_list = prev_seg = curr_seg;
260		}
261
262		curr_seg = seg_list;
263		while (curr_seg)
264		{
265			for ( i = 0; i < curr_seg->num_bytes; i+=4)
266			{
267
268				if ( fgets(tmp1, 12, file) == NULL )
269				{
270					PRINT(("Cannot read from file\n"));
271					goto fail_exit;
272				}
273				ltmp = strtoul(tmp1, NULL, 16);
274
275				*(unsigned int*)(curr_seg->data + i) = ltmp;
276			}
277
278			curr_seg = curr_seg->next;
279		}
280
281	}
282	else
283	{
284		PRINT(("File type %s unknown\n", micro_type));
285	}
286
287	microc_datap->microc_seg_list = seg_list;
288
289	fclose(file);
290	return 0;
291
292fail_exit:
293	curr_seg = seg_list;
294	while(curr_seg)
295	{
296		free(curr_seg->data);
297		prev_seg = curr_seg;
298		curr_seg = curr_seg->next;
299		free(prev_seg);
300	}
301	fclose(file);
302
303	return -1;
304}
305
306
307void CTheater200::DSPCleanMicrocode(struct rt200_microc_data* microc_datap)
308{
309	struct rt200_microc_seg* seg_list = microc_datap->microc_seg_list;
310	struct rt200_microc_seg* prev_seg;
311
312	while(seg_list)
313	{
314		free(seg_list->data);
315		prev_seg = seg_list;
316		seg_list = seg_list->next;
317		free(prev_seg);
318	}
319}
320
321
322status_t CTheater200::DspInit()
323{
324	uint32 data;
325	int i = 0;
326
327	PRINT(("CTheater200::Dsp_Init()\n"));
328
329	/* Map FIFOD to DSP Port I/O port */
330	data = Register(VIP_HOSTINTF_PORT_CNTL);
331	SetRegister(VIP_HOSTINTF_PORT_CNTL, data & (~VIP_HOSTINTF_PORT_CNTL__FIFO_RW_MODE));
332
333	/* The default endianess is LE. It matches the ost one for x86 */
334	data = Register(VIP_HOSTINTF_PORT_CNTL);
335	SetRegister(VIP_HOSTINTF_PORT_CNTL, data & (~VIP_HOSTINTF_PORT_CNTL__FIFOD_ENDIAN_SWAP));
336
337	/* Wait until Shuttle bus channel 14 is available */
338	data = Register(VIP_TC_STATUS);
339	while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000))
340		data = Register(VIP_TC_STATUS);
341
342	PRINT(("Microcode: dsp_init: channel 14 available\n"));
343
344	return B_OK;
345}
346
347status_t CTheater200::DspLoad( struct rt200_microc_data* microc_datap )
348{
349
350	struct rt200_microc_seg* seg_list = microc_datap->microc_seg_list;
351	uint8	data8;
352	uint32 data, fb_scratch0, fb_scratch1;
353	uint32 i;
354	uint32 tries = 0;
355	uint32 result = 0;
356	uint32 seg_id = 0;
357
358	PRINT(("Microcode: before everything: %x\n", data8));
359
360	if (ReadFifo(0x000, &data8))
361		PRINT(("Microcode: FIFO status0: %x\n", data8));
362	else
363	{
364		PRINT(("Microcode: error reading FIFO status0\n"));
365		return -1;
366	}
367
368
369	if (ReadFifo(0x100, &data8))
370		PRINT(("Microcode: FIFO status1: %x\n", data8));
371	else
372	{
373		PRINT(("Microcode: error reading FIFO status1\n"));
374		return -1;
375	}
376
377	/*
378	 * Download the Boot Code and CRC Checking Code (first segment)
379	 */
380	//debugger("DSPLoad");
381	seg_id = 1;
382	while(result != DSP_OK && tries++ < 10)
383	{
384
385		/* Put DSP in reset before download (0x02) */
386		data = Register(VIP_TC_DOWNLOAD);
387		SetRegister(VIP_TC_DOWNLOAD, (data & ~VIP_TC_DOWNLOAD__TC_RESET_MODE) | (0x02 << 17));
388
389		/*
390		 * Configure shuttle bus for tranfer between DSP I/O "Program Interface"
391		 * and Program Memory at address 0
392		 */
393
394		SetRegister(VIP_TC_SOURCE, 0x90000000);
395		SetRegister(VIP_TC_DESTINATION, 0x00000000);
396		SetRegister(VIP_TC_COMMAND, 0xe0000044 | ((seg_list->num_bytes - 1) << 7));
397
398		/* Load first segment */
399		PRINT(("Microcode: Loading first segment\n"));
400
401		if (!WriteFifo(0x700, seg_list->num_bytes, seg_list->data))
402		{
403			PRINT(("Microcode: write to FIFOD failed\n"));
404			return -1;
405		}
406
407		/* Wait until Shuttle bus channel 14 is available */
408		i = data = 0;
409		data = Register(VIP_TC_STATUS);
410		while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000))
411			data = Register(VIP_TC_STATUS);
412
413		if (i >= 10000)
414		{
415			PRINT(("Microcode: channel 14 timeout\n"));
416			return -1;
417		}
418
419		PRINT(("Microcode: dsp_load: checkpoint 1\n"));
420		PRINT(("Microcode: TC_STATUS: %x\n", data));
421
422		/* transfer the code from program memory to data memory */
423		SetRegister(VIP_TC_SOURCE, 0x00000000);
424		SetRegister(VIP_TC_DESTINATION, 0x10000000);
425		SetRegister(VIP_TC_COMMAND, 0xe0000006 | ((seg_list->num_bytes - 1) << 7));
426
427		/* Wait until Shuttle bus channel 14 is available */
428		i = data = 0;
429		data = Register(VIP_TC_STATUS);
430		while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000))
431			data = Register(VIP_TC_STATUS);
432
433		if (i >= 10000)
434		{
435			PRINT(("Microcode: channel 14 timeout\n"));
436			return -1;
437		}
438		PRINT(("Microcode: dsp_load: checkpoint 2\n"));
439		PRINT(("Microcode: TC_STATUS: %x\n", data));
440
441		/* Take DSP out from reset (0x0) */
442		data = Register(VIP_TC_DOWNLOAD);
443		SetRegister(VIP_TC_DOWNLOAD, data & ~VIP_TC_DOWNLOAD__TC_RESET_MODE);
444
445		data = Register(VIP_TC_STATUS);
446		PRINT(("Microcode: dsp_load: checkpoint 3\n"));
447		PRINT(("Microcode: TC_STATUS: %x\n", data));
448
449		/* send dsp_download_check_CRC */
450		fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 193);
451		fb_scratch1 = (unsigned int)seg_list->crc_val;
452
453		result = DspSendCommand(fb_scratch1, fb_scratch0);
454
455		PRINT(("Microcode: dsp_load: checkpoint 4\n"));
456	}
457
458	//debugger("DSPLoad");
459
460	if (tries >= 10)
461	{
462		PRINT(("Microcode: Download of boot degment failed\n"));
463		return -1;
464	}
465
466	PRINT(("Microcode: Download of boot code succeeded\n"));
467
468	while((seg_list = seg_list->next) != NULL)
469	{
470		seg_id++;
471		result = tries = 0;
472		while(result != DSP_OK && tries++ < 10)
473		{
474			/*
475			 * Configure shuttle bus for tranfer between DSP I/O "Program Interface"
476			 * and Data Memory at address 0
477			 */
478
479			SetRegister(VIP_TC_SOURCE, 0x90000000);
480			SetRegister(VIP_TC_DESTINATION, 0x10000000);
481			SetRegister(VIP_TC_COMMAND, 0xe0000044 | ((seg_list->num_bytes - 1) << 7));
482
483			if (!WriteFifo(0x700, seg_list->num_bytes, seg_list->data))
484			{
485				PRINT(("Microcode: write to FIFOD failed\n"));
486				return -1;
487			}
488
489			i = data = 0;
490			data = Register(VIP_TC_STATUS);
491			while(((data & VIP_TC_STATUS__TC_CHAN_BUSY) & 0x00004000) && (i++ < 10000))
492				data = Register(VIP_TC_STATUS);
493
494			/* send dsp_download_check_CRC */
495			fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 193);
496			fb_scratch1 = (unsigned int)seg_list->crc_val;
497
498			result = DspSendCommand(fb_scratch1, fb_scratch0);
499		}
500
501		if (i >=10)
502		{
503			PRINT(("Microcode: DSP failed to move seg: %x from data to code memory\n", seg_id));
504			return -1;
505		}
506
507		PRINT(("Microcode: segment: %x loaded\n", seg_id));
508
509		/*
510		 * The segment is downloaded correctly to data memory. Now move it to code memory
511		 * by using dsp_download_code_transfer command.
512		 */
513
514		fb_scratch0 = ((seg_list->num_bytes << 16) & 0xffff0000) | ((seg_id << 8) & 0xff00) | (0xff & 194);
515		fb_scratch1 = (unsigned int)seg_list->download_dst;
516
517		result = DspSendCommand(fb_scratch1, fb_scratch0);
518
519		if (result != DSP_OK)
520		{
521			PRINT(("Microcode: DSP failed to move seg: %x from data to code memory\n", seg_id));
522			return -1;
523		}
524	}
525
526	PRINT(("Microcode: download complete\n"));
527
528	/*
529	 * The last step is sending dsp_download_check_CRC with "download complete"
530	 */
531
532	fb_scratch0 = ((165 << 8) & 0xff00) | (0xff & 193);
533	fb_scratch1 = (unsigned int)0x11111;
534
535	result = DspSendCommand(fb_scratch1, fb_scratch0);
536
537	if (result == DSP_OK)
538		PRINT(("Microcode: DSP microcode successfully loaded\n"));
539	else
540	{
541		PRINT(("Microcode: DSP microcode UNsuccessfully loaded\n"));
542		return -1;
543	}
544
545	return 0;
546}
547
548status_t CTheater200::DspSendCommand(uint32 fb_scratch1, uint32 fb_scratch0)
549{
550	uint32 data;
551	int i;
552
553	/*
554	 * Clear the FB_INT0 bit in INT_CNTL
555	 */
556	data = Register(VIP_INT_CNTL);
557	SetRegister(VIP_INT_CNTL, data | VIP_INT_CNTL__FB_INT0_CLR);
558
559	/*
560	 * Write FB_SCRATCHx registers. If FB_SCRATCH1==0 then we have a DWORD command.
561	 */
562	SetRegister(VIP_FB_SCRATCH0, fb_scratch0);
563	if (fb_scratch1 != 0)
564		SetRegister(VIP_FB_SCRATCH1, fb_scratch1);
565
566	/*
567	 * Attention DSP. We are talking to you.
568	 */
569	data = Register(VIP_FB_INT);
570	SetRegister(VIP_FB_INT, data | VIP_FB_INT__INT_7);
571
572	/*
573	 * Wait (by polling) for the DSP to process the command.
574	 */
575	i = 0;
576	data = Register(VIP_INT_CNTL);
577	while((!(data & VIP_INT_CNTL__FB_INT0)) && (i++ < 10))
578	{
579		snooze(1000);
580		data = Register(VIP_INT_CNTL);
581	}
582
583	/*
584	 * The return code is in FB_SCRATCH0
585	 */
586	fb_scratch0 = Register(VIP_FB_SCRATCH0);
587
588	/*
589	 * If we are here it means we got an answer. Clear the FB_INT0 bit.
590	 */
591	data = Register(VIP_INT_CNTL);
592	SetRegister(VIP_INT_CNTL, data | VIP_INT_CNTL__FB_INT0_CLR);
593
594	return fb_scratch0;
595}
596
597void CTheater200::InitTheatre()
598{
599	uint32 data;
600	uint32 M, N, P;
601
602	/* this will give 108Mhz at 27Mhz reference */
603	M = 28;
604	N = 224;
605	P = 1;
606
607	ShutdownTheatre();
608	snooze(100000);
609	fMode = MODE_INITIALIZATION_IN_PROGRESS;
610
611	data = M | (N << 11) | (P <<24);
612	SetRegister(VIP_DSP_PLL_CNTL, data);
613
614	Register(VIP_PLL_CNTL0, data);
615	data |= 0x2000;
616	SetRegister(VIP_PLL_CNTL0, data);
617
618	/* RT_regw(VIP_I2C_SLVCNTL, 0x249); */
619	Register(VIP_PLL_CNTL1, data);
620	data |= 0x00030003;
621	SetRegister(VIP_PLL_CNTL1, data);
622
623	Register(VIP_PLL_CNTL0, data);
624	data &= 0xfffffffc;
625	SetRegister(VIP_PLL_CNTL0, data);
626	snooze(15000);
627
628	Register(VIP_CLOCK_SEL_CNTL, data);
629	data |= 0x1b;
630	SetRegister(VIP_CLOCK_SEL_CNTL, data);
631
632	Register(VIP_MASTER_CNTL, data);
633	data &= 0xffffff07;
634	SetRegister(VIP_MASTER_CNTL, data);
635	data &= 0xffffff03;
636	SetRegister(VIP_MASTER_CNTL, data);
637	snooze(1000);
638
639	if (microcode_path == NULL)
640	{
641		microcode_path = const_cast<char *>(DEFAULT_MICROC_PATH);
642		PRINT(("Microcode: Use default microcode path: %s\n", DEFAULT_MICROC_PATH));
643	}
644	else
645	{
646		PRINT(("Microcode: Use microcode path: %s\n", microcode_path));
647	}
648
649	if (microcode_type == NULL)
650	{
651		microcode_type = const_cast<char *>(DEFAULT_MICROC_TYPE);
652		PRINT(("Microcode: Use default microcode type: %s\n", DEFAULT_MICROC_TYPE));
653	}
654	else
655	{
656		PRINT(("Microcode: Use microcode type: %s\n", microcode_type));
657	}
658
659	if (DSPDownloadMicrocode() < 0)
660	{
661		ShutdownTheatre();
662		return;
663	}
664
665	//DspSetLowPowerState(1);
666	//DspSetVideoStreamFormat(1);
667
668	fMode = MODE_INITIALIZED_FOR_TV_IN;
669}
670
671int CTheater200::DSPDownloadMicrocode()
672{
673	struct rt200_microc_data microc_data;
674	microc_data.microc_seg_list = NULL;
675
676	if (DSPLoadMicrocode(microcode_path, microcode_type, &microc_data) < 0)
677	{
678		PRINT(("Microcode: cannot load microcode\n"));
679		goto err_exit;
680	}
681	else
682	{
683		PRINT(("Microcode: device_id: %x\n", microc_data.microc_head.device_id));
684		PRINT(("Microcode: vendor_id: %x\n", microc_data.microc_head.vendor_id));
685		PRINT(("Microcode: rev_id: %x\n", 	 microc_data.microc_head.revision_id));
686		PRINT(("Microcode: num_seg: %x\n", 	 microc_data.microc_head.num_seg));
687	}
688
689	if (DspInit() < 0)
690	{
691		PRINT(("Microcode: dsp_init failed\n"));
692		goto err_exit;
693	}
694	else
695	{
696		PRINT(("Microcode: dsp_init OK\n"));
697	}
698
699	if (DspLoad(&microc_data) < 0)
700	{
701		PRINT(("Microcode: dsp_download failed\n"));
702		goto err_exit;
703	}
704	else
705	{
706		PRINT(("Microcode: dsp_download OK\n"));
707	}
708
709	DSPCleanMicrocode(&microc_data);
710	return 0;
711
712err_exit:
713
714	DSPCleanMicrocode(&microc_data);
715	return -1;
716
717}
718
719void CTheater200::ShutdownTheatre()
720{
721    fMode = MODE_UNINITIALIZED;
722}
723
724void CTheater200::ResetTheatreRegsForNoTVout()
725{
726	SetRegister(VIP_CLKOUT_CNTL, 0x0);
727	SetRegister(VIP_HCOUNT, 0x0);
728	SetRegister(VIP_VCOUNT, 0x0);
729	SetRegister(VIP_DFCOUNT, 0x0);
730#if 0
731	SetRegister(VIP_CLOCK_SEL_CNTL, 0x2b7);  /* versus 0x237 <-> 0x2b7 */
732	SetRegister(VIP_VIN_PLL_CNTL, 0x60a6039);
733#endif
734	SetRegister(VIP_FRAME_LOCK_CNTL, 0x0);
735}
736
737void CTheater200::ResetTheatreRegsForTVout()
738{
739	SetRegister(VIP_CLKOUT_CNTL, 0x29);
740#if 1
741	SetRegister(VIP_HCOUNT, 0x1d1);
742	SetRegister(VIP_VCOUNT, 0x1e3);
743#else
744	SetRegister(VIP_HCOUNT, 0x322);
745	SetRegister(VIP_VCOUNT, 0x151);
746#endif
747	SetRegister(VIP_DFCOUNT, 0x01);
748	SetRegister(VIP_CLOCK_SEL_CNTL, 0x2b7);		/* versus 0x237 <-> 0x2b7 */
749	SetRegister(VIP_VIN_PLL_CNTL, 0x60a6039);
750	SetRegister(VIP_FRAME_LOCK_CNTL, 0x0f);
751}
752
753int32 CTheater200::DspSetVideostreamformat(int32 format)
754{
755	int32 fb_scratch0 = 0;
756	int32 result;
757
758	fb_scratch0 = ((format << 8) & 0xff00) | (65 & 0xff);
759	result = DspSendCommand(0, fb_scratch0);
760
761	PRINT(("dsp_set_videostreamformat: %x\n", result));
762
763	return result;
764}
765
766int32 CTheater200::DspGetSignalLockStatus()
767{
768	int32 fb_scratch1 = 0;
769	int32 fb_scratch0 = 0;
770	int32 result;
771
772	fb_scratch0 = 0 | (77 & 0xff);
773
774	result = DspSendCommand(fb_scratch1, fb_scratch0);
775
776	PRINT(("dsp_get_signallockstatus: %x, h_pll: %x, v_pll: %x\n", \
777		result, (result >> 8) & 0xff, (result >> 16) & 0xff));
778
779	return result;
780}
781
782// disable/enable capturing
783void CTheater200::SetEnable(bool enable, bool vbi)
784{
785
786	PRINT(("CTheater200::SetEnable(%d, %d)\n", enable, vbi));
787
788	if (enable) {
789		WaitVSYNC();
790
791		SetADC(fStandard, fSource);
792
793		SetScaler(fStandard, fHActive, fVActive, fDeinterlace);
794
795		// Enable ADC block
796		SetRegister(VIP_ADC_CNTL, ADC_PDWN, ADC_PDWN_UP);
797
798		WaitVSYNC();
799
800		// restore luminance and chroma settings
801		SetLuminanceLevels(fStandard, fBrightness, fContrast);
802		SetChromaLevels(fStandard, fSaturation, fHue);
803	}
804}
805
806void CTheater200::SetStandard(theater_standard standard, theater_source source)
807{
808	PRINT(("CTheater200::SetStandard(%s, %s)\n",
809		"NTSC\0\0\0\0\0\0NTSC-J\0\0\0\0NTSC-443\0\0PAL-M\0\0\0\0\0"
810		"PAL-N\0\0\0\0\0PAL-NC\0\0\0\0PAL-BDGHI\0PAL-60\0\0\0\0"
811		"SECAM\0\0\0\0\0"+10*standard,
812		"TUNER\0COMP\0\0SVIDEO"+6*source));
813
814	fStandard = standard;
815	fSource = source;
816}
817
818void CTheater200::SetSize(int hactive, int vactive)
819{
820	PRINT(("CTheater200::SetSize(%d, %d)\n", hactive, vactive));
821
822	fHActive = hactive;
823	fVActive = vactive;
824}
825
826void CTheater200::SetDeinterlace(bool deinterlace)
827{
828	PRINT(("CTheater200::SetDeinterlace(%d)\n", deinterlace));
829
830	fDeinterlace = deinterlace;
831}
832
833/* one assumes as sharpness is not used it's not supported */
834void CTheater200::SetSharpness(int sharpness)
835{
836	int32 fb_scratch0 = 0;
837	int32 fb_scratch1 = 1;
838	int32 result;
839
840	PRINT(("CTheater200::SetSharpness(%d)\n", sharpness));
841
842	fb_scratch0 = 0 | (73 & 0xff);
843	result = DspSendCommand(fb_scratch1, fb_scratch0);
844}
845
846void CTheater200::SetBrightness(int brightness)
847{
848	PRINT(("CTheater200::SetBrightness(%d)\n", brightness));
849
850	fBrightness = brightness;
851	SetLuminanceLevels(fStandard, fBrightness, fContrast);
852}
853
854void CTheater200::SetContrast(int contrast)
855{
856	PRINT(("CTheater200::SetContrast(%d)\n", contrast));
857
858	fContrast = contrast;
859	SetLuminanceLevels(fStandard, fBrightness, fContrast);
860}
861
862void CTheater200::SetSaturation(int saturation)
863{
864	PRINT(("CTheater200::SetSaturation(%d)\n", saturation));
865
866	fSaturation = saturation;
867	SetChromaLevels(fStandard, fSaturation, fHue);
868}
869
870void CTheater200::SetHue(int hue)
871{
872	PRINT(("CTheater200::SetHue(%d)\n", hue));
873
874	fHue = hue;
875	SetChromaLevels(fStandard, fSaturation, fHue);
876}
877
878// setup analog-digital converter
879void CTheater200::SetADC(theater_standard standard, theater_source source)
880{
881	uint32 fb_scratch0 = 0;
882	uint32 result;
883	uint32 data = 0;
884
885	PRINT(("CTheater200::SetADC(%c, %c)\n", "NJ4MNCB6S"[standard], "TCS"[source]));
886
887	// set HW_DEBUG before setting the standard
888	SetRegister(VIP_HW_DEBUG, 0x0000f000);
889
890	// select the video standard
891	switch (standard) {
892	case C_THEATER_NTSC:
893	case C_THEATER_NTSC_JAPAN:
894	case C_THEATER_NTSC_443:
895	case C_THEATER_PAL_M:
896		// SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_NTSC);
897		// break;
898	case C_THEATER_PAL_BDGHI:
899	case C_THEATER_PAL_N:
900	case C_THEATER_PAL_60:
901	case C_THEATER_PAL_NC:
902		// SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_PAL);
903		// break;
904	case C_THEATER_SECAM:
905		// SetRegister(VIP_STANDARD_SELECT, STANDARD_SEL, STANDARD_SECAM);
906		fb_scratch0 = ((standard << 8) & 0xff00) | (52 & 0xff);
907		result = DspSendCommand(0, fb_scratch0);
908		break;
909	default:
910		PRINT(("CTheater200::SetADC() - Bad standard\n"));
911		return;
912	}
913
914	Register(VIP_GPIO_CNTL, data);
915	PRINT(("VIP_GPIO_CNTL: %x\n", data));
916
917	Register(VIP_GPIO_INOUT, data);
918	PRINT(("VIP_GPIO_INOUT: %x\n", data));
919
920	// select input connector and Y/C mode
921	switch (source) {
922	case C_THEATER_TUNER:
923		// set video input connector
924		fb_scratch0 = ((fTunerPort << 8) & 0xff00) | (55 & 0xff);
925		DspSendCommand(0, fb_scratch0);
926
927		/* this is to set the analog mux used for sond */
928		Register(VIP_GPIO_CNTL, data);
929		data &= ~0x10;
930		SetRegister(VIP_GPIO_CNTL, data);
931
932		Register(VIP_GPIO_INOUT, data);
933		data &= ~0x10;
934		SetRegister(VIP_GPIO_INOUT, data);
935		break;
936	case C_THEATER_COMPOSITE:
937		// set video input connector
938		fb_scratch0 = ((fCompositePort << 8) & 0xff00) | (55 & 0xff);
939		DspSendCommand(0, fb_scratch0);
940
941		/* this is to set the analog mux used for sond */
942		Register(VIP_GPIO_CNTL, data);
943		data |= 0x10;
944		SetRegister(VIP_GPIO_CNTL, data);
945
946		Register(VIP_GPIO_INOUT, data);
947		data |= 0x10;
948		SetRegister(VIP_GPIO_INOUT, data);
949		break;
950	case C_THEATER_SVIDEO:
951		// set video input connector
952		fb_scratch0 = ((fSVideoPort << 8) & 0xff00) | (55 & 0xff);
953		DspSendCommand(0, fb_scratch0);
954
955		/* this is to set the analog mux used for sond */
956		Register(VIP_GPIO_CNTL, data);
957		data |= 0x10;
958		SetRegister(VIP_GPIO_CNTL, data);
959
960		Register(VIP_GPIO_INOUT, data);
961		data |= 0x10;
962		SetRegister(VIP_GPIO_INOUT, data);
963		break;
964	default:
965		PRINT(("CTheater200::SetADC() - Bad source\n"));
966		return;
967	}
968
969
970	Register(VIP_GPIO_CNTL, data);
971	PRINT(("VIP_GPIO_CNTL: %x\n", data));
972
973	Register(VIP_GPIO_INOUT, data);
974	PRINT(("VIP_GPIO_INOUT: %x\n", data));
975
976
977	DspConfigureI2SPort(0, 0, 0);
978	DspConfigureSpdifPort(0);
979
980	/*dsp_audio_detection(t, 0);*/
981	DspAudioMute(1, 1);
982	DspSetAudioVolume(128, 128, 0);
983
984}
985
986// wait until horizontal scaler is locked
987void CTheater200::WaitHSYNC()
988{
989	for (int timeout = 0; timeout < 1000; timeout++) {
990		if (Register(VIP_HS_PULSE_WIDTH, HS_GENLOCKED) != 0)
991			return;
992		snooze(20);
993	}
994	PRINT(("CTheater200::WaitHSYNC() - wait for HSync locking time out!\n"));
995}
996
997
998
999// wait until a visible line is viewed
1000void CTheater200::WaitVSYNC()
1001{
1002	for (int timeout = 0; timeout < 1000; timeout++) {
1003		int lineCount = CurrentLine();
1004		if (lineCount > 1 && lineCount < 20)
1005			return;
1006		snooze(20);
1007	}
1008	PRINT(("CTheater200::WaitVSYNC() - wait for VBI timed out!\n"));
1009}
1010
1011// setup brightness and contrast
1012void CTheater200::SetLuminanceLevels(theater_standard standard, int brightness, int contrast)
1013{
1014
1015	int32 fb_scratch1 = 0;
1016	int32 fb_scratch0 = 0;
1017	int32 result;
1018
1019	/* set luminance processor constrast */
1020	fb_scratch0 = ((contrast << 8) & 0xff00) | (71 & 0xff);
1021	result = DspSendCommand(fb_scratch1, fb_scratch0);
1022	PRINT(("dsp_set_contrast: %x\n", result));
1023
1024	/* set luminance processor brightness */
1025	fb_scratch0 = ((brightness << 8) & 0xff00) | (67 & 0xff);
1026	DspSendCommand(fb_scratch1, fb_scratch0);
1027	PRINT(("dsp_set_brightness: %x\n", result));
1028
1029}
1030
1031// set colour saturation and hue.
1032// hue makes sense for NTSC only and seems to act as saturation for PAL
1033void CTheater200::SetChromaLevels(theater_standard standard, int saturation, int hue)
1034{
1035
1036	int32 fb_scratch1 = 0;
1037	int32 fb_scratch0 = 0;
1038
1039	// Set Hue
1040	fb_scratch0 = ((hue << 8) & 0xff00) | (75 & 0xff);
1041	DspSendCommand(fb_scratch1, fb_scratch0);
1042
1043	// Set Saturation
1044	fb_scratch0 = ((saturation << 8) & 0xff00) | (69 & 0xff);
1045	DspSendCommand(fb_scratch1, fb_scratch0);
1046
1047	PRINT(("dsp_set_saturation: %x\n", saturation));
1048	PRINT(("dsp_set_tint: %x\n", hue));
1049}
1050
1051
1052// these values are used by scaler as well
1053static const uint16 h_active_start[] = {
1054	0x06b,	0x06B,	0x07E,	0x067,	0x09A,	0x07D,	0x09A,	0x084,	0x095 };
1055static const uint16 h_active_end[] = {
1056	0x363,	0x363,	0x42A,	0x363,	0x439,	0x439,	0x439,	0x363,	0x439 };
1057static const uint16 v_active_start[] = {
1058	0x025,	0x025,	0x025,	0x025,	0x02E,	0x02E,	0x02E,	0x025,	0x02E };
1059// PAL height is too small (572 instead of 576 lines), but changing 0x269 to 0x26d
1060// leads to trouble, and the last 2 lines seem to be used for VBI data
1061// (read: garbage) anyway
1062static const uint16 v_active_end[] = {
1063	0x204,	0x204,	0x204,	0x204,	0x269,	0x269,	0x269,	0x204,	0x269 };
1064static const uint16 h_vbi_wind_start[] = {
1065	0x064,	0x064,	0x064,	0x064,	0x084,	0x084,	0x084,	0x064,	0x084 };
1066static const uint16 h_vbi_wind_end[] = {
1067	0x366,	0x366,	0x366,	0x366,	0x41F,	0x41F,	0x41F,	0x366,	0x41F };
1068static const uint16 v_vbi_wind_start[] = {
1069	0x00b,	0x00b,	0x00b,	0x00b,	0x008,	0x008,	0x008,	0x00b,	0x008 };
1070static const uint16 v_vbi_wind_end[] = {
1071	0x024,	0x024,	0x024,	0x024,	0x02d,	0x02d,	0x02d,	0x024,	0x02d };
1072
1073
1074void CTheater200::getActiveRange( theater_standard standard, CRadeonRect &rect )
1075{
1076
1077	rect.SetTo(
1078		h_active_start[standard], v_active_start[standard],
1079		h_active_end[standard], v_active_end[standard] );
1080
1081}
1082
1083void CTheater200::getVBIRange( theater_standard standard, CRadeonRect &rect )
1084{
1085
1086	rect.SetTo(
1087		h_vbi_wind_start[standard], v_vbi_wind_start[standard],
1088		h_vbi_wind_end[standard], v_vbi_wind_end[standard] );
1089
1090}
1091
1092// setup capture scaler.
1093void CTheater200::SetScaler(theater_standard standard, int hactive, int vactive, bool deinterlace)
1094{
1095
1096	int32 fb_scratch1 = 0;
1097	int32 fb_scratch0 = 0;
1098	int oddOffset, evenOffset;
1099	uint16 h_active_width, v_active_height;
1100
1101//	ASSERT(vactive <= 511);
1102
1103	// TK: Gatos uses different values here
1104	h_active_width = h_active_end[standard] - h_active_start[standard] + 1;
1105	v_active_height = v_active_end[standard] - v_active_start[standard] + 1;
1106
1107	// for PAL, we have 572 lines only, but need 576 lines;
1108	// my attempts to find those missing lines all failed, so if the application requests
1109	// 576 lines, we had to upscale the video which is not supported by hardware;
1110	// solution: restrict to 572 lines - the scaler will fill out the missing lines with black
1111	if( vactive > v_active_height )
1112		vactive = v_active_height;
1113
1114	if (deinterlace) {
1115		// progressive scan
1116		evenOffset = oddOffset = 512 - (int) ((512 * vactive) / v_active_height);
1117	}
1118	else {
1119		// interlaced
1120		evenOffset = (int) ((512 * vactive) / v_active_height);
1121		oddOffset = 2048 - evenOffset;
1122	}
1123
1124	// Set Horizontal Size
1125	fb_scratch0 = ((h_active_width << 8) & 0x00ffff00) | (195 & 0xff);
1126	fb_scratch1 = ((h_active_end[standard] << 16) & 0xffff0000) | (h_active_start[standard] & 0xffff);
1127	DspSendCommand(fb_scratch1, fb_scratch0);
1128
1129	// Set Vertical Size
1130	fb_scratch0 = ((v_active_height << 8) & 0x00ffff00) | (196 & 0xff);
1131	fb_scratch1 = ((v_active_end[standard] << 16) & 0xffff0000) | (v_active_start[standard] + 1 & 0xffff);
1132	DspSendCommand(fb_scratch1, fb_scratch0);
1133}
1134
1135int32 CTheater200::DspAudioMute(int8 left, int8 right)
1136{
1137	int32 fb_scratch1 = 0;
1138	int32 fb_scratch0 = 0;
1139	int32 result;
1140
1141	fb_scratch0 = ((right << 16) & 0xff0000) | ((left << 8) & 0xff00) | (21 & 0xff);
1142	result = DspSendCommand(fb_scratch1, fb_scratch0);
1143
1144	PRINT(("dsp_audio_mute: %x\n", result));
1145
1146	return result;
1147}
1148
1149int32 CTheater200::DspSetAudioVolume(int8 left, int8 right, int8 auto_mute)
1150{
1151	int32 fb_scratch1 = 0;
1152	int32 fb_scratch0 = 0;
1153	int32 result;
1154
1155	fb_scratch0 = ((auto_mute << 24) & 0xff000000)
1156		| ((right << 16) & 0xff0000)
1157		| ((left << 8) & 0xff00) | (22 & 0xff);
1158	result = DspSendCommand(fb_scratch1, fb_scratch0);
1159
1160	PRINT(("dsp_set_audio_volume: %x\n", result));
1161
1162	return result;
1163}
1164
1165int32 CTheater200::DspConfigureI2SPort(int8 tx_mode, int8 rx_mode, int8 clk_mode)
1166{
1167	int32 fb_scratch1 = 0;
1168	int32 fb_scratch0 = 0;
1169	int32 result;
1170
1171	fb_scratch0 = ((clk_mode << 24) & 0xff000000) | ((rx_mode << 16) & 0xff0000)
1172					| ((tx_mode << 8) & 0xff00) | (40 & 0xff);
1173
1174	result = DspSendCommand(fb_scratch1, fb_scratch0);
1175
1176	PRINT(("dsp_configure_i2s_port: %x\n", result));
1177
1178	return result;
1179}
1180
1181int32 CTheater200::DspConfigureSpdifPort(int8 state)
1182{
1183	int32 fb_scratch1 = 0;
1184	int32 fb_scratch0 = 0;
1185	int32 result;
1186
1187	fb_scratch0 = ((state << 8) & 0xff00) | (41 & 0xff);
1188
1189	result = DspSendCommand(fb_scratch1, fb_scratch0);
1190
1191	PRINT(("dsp_configure_spdif_port: %x\n", result));
1192
1193	return result;
1194}
1195
1196int CTheater200::ReadFifo( uint32 address, uint8 *buffer)
1197{
1198	return fPort.ReadFifo(fDevice, address, 1, buffer);
1199}
1200
1201int CTheater200::WriteFifo( uint32 address, uint32 count, uint8 *buffer)
1202{
1203	return fPort.WriteFifo(fDevice, address, count, buffer);
1204}
1205
1206int CTheater200::CurrentLine()
1207{
1208//	return Register(VIP_VS_LINE_COUNT) & VS_LINE_COUNT;
1209	int32 fb_scratch1 = 0;
1210	int32 fb_scratch0 = 0;
1211	int32 result;
1212
1213	fb_scratch0 = 0 | (78 & 0xff);
1214	result = DspSendCommand(fb_scratch1, fb_scratch0);
1215
1216	PRINT(("dsp_get_signallinenumber: %x, linenum: %x\n", \
1217		result, (result >> 8) & 0xffff));
1218
1219	return result;
1220
1221}
1222
1223void CTheater200::PrintToStream()
1224{
1225	PRINT(("<<< Rage Theater Registers >>>\n"));
1226	/*for (int index = 0x0400; index <= 0x06ff; index += 4) {
1227		int value = Register(index);
1228		PRINT(("REG_0x%04x = 0x%08x\n", index, value));
1229	}	*/
1230}
1231