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
21 const char* DEFAULT_MICROC_PATH = "/boot/home/config/settings/Media/RageTheater200/ativmc20.cod";
22 const char* DEFAULT_MICROC_TYPE = "BINARY";
23
CTheater200(CRadeon & radeon,int device)24 CTheater200::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
~CTheater200()57 CTheater200::~CTheater200()
58 {
59 PRINT(("CTheater200::~CTheater200()\n"));
60
61 if( InitCheck() == B_OK )
62 SetEnable(false, false);
63
64 }
65
InitCheck() const66 status_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
Reset()91 void 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
DSPLoadMicrocode(char * micro_path,char * micro_type,struct rt200_microc_data * microc_datap)102 status_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 = µc_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
292 fail_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
DSPCleanMicrocode(struct rt200_microc_data * microc_datap)307 void 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
DspInit()322 status_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
DspLoad(struct rt200_microc_data * microc_datap)347 status_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
DspSendCommand(uint32 fb_scratch1,uint32 fb_scratch0)548 status_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
InitTheatre()597 void 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
DSPDownloadMicrocode()671 int 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, µc_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(µc_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(µc_data);
710 return 0;
711
712 err_exit:
713
714 DSPCleanMicrocode(µc_data);
715 return -1;
716
717 }
718
ShutdownTheatre()719 void CTheater200::ShutdownTheatre()
720 {
721 fMode = MODE_UNINITIALIZED;
722 }
723
ResetTheatreRegsForNoTVout()724 void 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
ResetTheatreRegsForTVout()737 void 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
DspSetVideostreamformat(int32 format)753 int32 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
DspGetSignalLockStatus()766 int32 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
SetEnable(bool enable,bool vbi)783 void 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
SetStandard(theater_standard standard,theater_source source)806 void 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
SetSize(int hactive,int vactive)818 void 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
SetDeinterlace(bool deinterlace)826 void 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 */
SetSharpness(int sharpness)834 void 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
SetBrightness(int brightness)846 void CTheater200::SetBrightness(int brightness)
847 {
848 PRINT(("CTheater200::SetBrightness(%d)\n", brightness));
849
850 fBrightness = brightness;
851 SetLuminanceLevels(fStandard, fBrightness, fContrast);
852 }
853
SetContrast(int contrast)854 void CTheater200::SetContrast(int contrast)
855 {
856 PRINT(("CTheater200::SetContrast(%d)\n", contrast));
857
858 fContrast = contrast;
859 SetLuminanceLevels(fStandard, fBrightness, fContrast);
860 }
861
SetSaturation(int saturation)862 void CTheater200::SetSaturation(int saturation)
863 {
864 PRINT(("CTheater200::SetSaturation(%d)\n", saturation));
865
866 fSaturation = saturation;
867 SetChromaLevels(fStandard, fSaturation, fHue);
868 }
869
SetHue(int hue)870 void 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
SetADC(theater_standard standard,theater_source source)879 void 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
WaitHSYNC()987 void 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
WaitVSYNC()1000 void 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
SetLuminanceLevels(theater_standard standard,int brightness,int contrast)1012 void 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
SetChromaLevels(theater_standard standard,int saturation,int hue)1033 void 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
1053 static const uint16 h_active_start[] = {
1054 0x06b, 0x06B, 0x07E, 0x067, 0x09A, 0x07D, 0x09A, 0x084, 0x095 };
1055 static const uint16 h_active_end[] = {
1056 0x363, 0x363, 0x42A, 0x363, 0x439, 0x439, 0x439, 0x363, 0x439 };
1057 static 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
1062 static const uint16 v_active_end[] = {
1063 0x204, 0x204, 0x204, 0x204, 0x269, 0x269, 0x269, 0x204, 0x269 };
1064 static const uint16 h_vbi_wind_start[] = {
1065 0x064, 0x064, 0x064, 0x064, 0x084, 0x084, 0x084, 0x064, 0x084 };
1066 static const uint16 h_vbi_wind_end[] = {
1067 0x366, 0x366, 0x366, 0x366, 0x41F, 0x41F, 0x41F, 0x366, 0x41F };
1068 static const uint16 v_vbi_wind_start[] = {
1069 0x00b, 0x00b, 0x00b, 0x00b, 0x008, 0x008, 0x008, 0x00b, 0x008 };
1070 static const uint16 v_vbi_wind_end[] = {
1071 0x024, 0x024, 0x024, 0x024, 0x02d, 0x02d, 0x02d, 0x024, 0x02d };
1072
1073
getActiveRange(theater_standard standard,CRadeonRect & rect)1074 void 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
getVBIRange(theater_standard standard,CRadeonRect & rect)1083 void 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.
SetScaler(theater_standard standard,int hactive,int vactive,bool deinterlace)1093 void 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
DspAudioMute(int8 left,int8 right)1135 int32 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
DspSetAudioVolume(int8 left,int8 right,int8 auto_mute)1149 int32 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
DspConfigureI2SPort(int8 tx_mode,int8 rx_mode,int8 clk_mode)1165 int32 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
DspConfigureSpdifPort(int8 state)1181 int32 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
ReadFifo(uint32 address,uint8 * buffer)1196 int CTheater200::ReadFifo( uint32 address, uint8 *buffer)
1197 {
1198 return fPort.ReadFifo(fDevice, address, 1, buffer);
1199 }
1200
WriteFifo(uint32 address,uint32 count,uint8 * buffer)1201 int CTheater200::WriteFifo( uint32 address, uint32 count, uint8 *buffer)
1202 {
1203 return fPort.WriteFifo(fDevice, address, count, buffer);
1204 }
1205
CurrentLine()1206 int 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
PrintToStream()1223 void 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