Hardware/AV Encoder

From WiiBrew
Jump to: navigation, search

The A/V encoder is located on the underside of the Wii main board; it is communicated with via I2C.

See http://www.gc-linux.org/wiki/AVE-RVL for additional information.

Contents

Registers description

Here is a more complete description of the registers that can be modified by the software. This is heavily based on the disassembly and analysis of some original code with help of left symbols, there is therefore still unknown features and the whole description should be handled with caution.


Register 00h

address size read/write description
0x00 1 W A/V timings ?


bit(s) description
0 0 = default value, 1 for D-Terminal (?)


Register 01h

address size read/write description
0x01 1 W Video Output configuration


bit(s) description
5 YUV output (0: disabled 1: enabled)
0-1 color encoding (0: NTSC, 1:MPAL, 2:PAL, 3:DEBUG ?)

YUV output is typically enabled only when component video cable is detected.

Register 02h

address size read/write description
0x02 1 W Vertical blanking interval (VBI) control ?


bit(s) description
2 unknown (1: default value, 0 for D-Terminal ?)
1 unknown (1: default value, 0 for D-Terminal ?)
0 unknown (1: default value, 0 for D-Terminal ?)


Register 03h

address size read/write description
0x03 1 W Composite Video Trap Filter control


bit(s) description
1 1: enabled, 0: disabled


A Trap filter is generally used to improve Luma/Chroma separation in the composite video signal. When disabled, the video signal is unfiltered, which sometimes produces visual artefacts such as color bleeding. This register does not seem to affect RGB, S-Video or YUV output.

Register 04h

address size read/write description
0x04 1 R/W A/V output control


bit(s) description
1 1: enabled, 0: disabled

A/V output is typically disabled during register initialization.

Registers 05h & 06h

address size read/write description
0x05 2 W CGMS protection ?


bit(s) description
8-15 unknown (0: default value)
2-5 unknown (0: default value)
0-1 unknown (0: default value)


Registers 08h & 09h

address size read/write description
0x08 2 W WSS (Widescreen signaling) ?


bit(s) description
11-13 unknown (0: default value)
8-10 unknown (0: default value)
4-7 unknown (0: default value)
0-3 unknown (0: default value)


Register 0Ah

address size read/write description
0x0A 1 W RGB color output control (overdrive ?)


bit(s) description
1-7 unknown (1: default value)
0 0: disabled, 1: enabled

This is apparently only enabled in DEBUG mode (Reg $1 = 3).

Registers 10h - 30h

address size read/write description
0x10-0x30 33 r/W Gamma coefficients


byte(s) description
0-32 See coefficients table below (default is gamma 1.0)


/* Wii A/V Encoder gamma coefficients */
 
const u8 gamma_coeffs[][33] =
{
	/* GM_0_0 */
	{
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 
	},	
 
	/* GM_0_1 */
	{
		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x97, 0x3B, 0x49,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x80, 0x1B, 0x80, 0xEB, 0x00
	},	
 
	/* GM_0_2 */
	{
		 0x00, 0x00, 0x00, 0x28, 0x00, 0x5A, 0x02, 0xDB, 0x0D, 0x8D, 0x30, 0x49,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x10, 0x00, 0x10, 0x40, 0x11, 0x00, 0x18, 0x80, 0x42, 0x00, 0xEB, 0x00
	},	
 
	/* GM_0_3 */
	{
		 0x00, 0x00, 0x00, 0x7A, 0x02, 0x3C, 0x07, 0x6D, 0x12, 0x9C, 0x27, 0x24,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x10, 0x00, 0x10, 0xC0, 0x15, 0x80, 0x29, 0x00, 0x62, 0x00, 0xEB, 0x00
	},	
 
	/* GM_0_4 */
	{
		 0x00, 0x4E, 0x01, 0x99, 0x05, 0x2D, 0x0B, 0x24, 0x14, 0x29, 0x20, 0xA4,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x00, 0x10, 0x10, 0x40, 0x12, 0xC0, 0x1D, 0xC0, 0x3B, 0x00, 0x78, 0xC0, 0xEB, 0x00
	},	
 
	/* GM_0_5 */
	{
		 0x00, 0xEC, 0x03, 0xD7, 0x08, 0x00, 0x0D, 0x9E, 0x14, 0x3E, 0x1B, 0xDB,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x10, 0xC0, 0x16, 0xC0, 0x27, 0xC0, 0x4B, 0x80, 0x89, 0x80, 0xEB, 0x00
	},	
 
	/* GM_0_6 */
	{
		 0x02, 0x76, 0x06, 0x66, 0x0A, 0x96, 0x0E, 0xF3, 0x13, 0xAC, 0x18, 0x49,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB, 
		 0x10, 0x00, 0x12, 0x00, 0x1C, 0x00, 0x32, 0x80, 0x59, 0xC0, 0x96, 0x00, 0xEB, 0x00
	},	
 
	/* GM_0_7 */
	{
		 0x04, 0xEC, 0x08, 0xF5, 0x0C, 0x96, 0x0F, 0xCF, 0x12, 0xC6, 0x15, 0x80,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB, 
		 0x10, 0x00, 0x14, 0x00, 0x22, 0x00, 0x3C, 0xC0, 0x66, 0x40, 0x9F, 0xC0, 0xEB, 0x00
	},	
 
	/* GM_0_8 */
	{
		 0x08, 0x00, 0x0B, 0xAE, 0x0E, 0x00, 0x10, 0x30, 0x11, 0xCB, 0x13, 0x49,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB, 
		 0x10, 0x00, 0x16, 0x80, 0x28, 0xC0, 0x46, 0x80, 0x71, 0x00, 0xA7, 0x80, 0xEB, 0x00
	},	
 
	/* GM_0_9 */
	{
		 0x0B, 0xB1, 0x0E, 0x14, 0x0F, 0x2D, 0x10, 0x18, 0x10, 0xE5, 0x11, 0x80,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x19, 0x80, 0x2F, 0x80, 0x4F, 0xC0, 0x7A, 0x00, 0xAD, 0xC0, 0xEB, 0x00
	},	
 
	/* GM_1_0 */
	{
		 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00,
		 0x10, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xEB,
		 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x60, 0x00, 0x80, 0x00, 0xA0, 0x00, 0xEB, 0x00
	},	
 
	/* GM_1_1 */
	{
		 0x14, 0xEC, 0x11, 0xC2, 0x10, 0x78, 0x0F, 0xB6, 0x0F, 0x2F, 0x0E, 0xB6,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x21, 0x00, 0x3C, 0xC0, 0x5F, 0xC0, 0x89, 0x00, 0xB7, 0x80, 0xEB, 0x00
	},	
 
	/* GM_1_2 */
	{
		 0x19, 0xD8, 0x13, 0x33, 0x10, 0xD2, 0x0F, 0x6D, 0x0E, 0x5E, 0x0D, 0xA4,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x25, 0x00, 0x43, 0x00, 0x66, 0xC0, 0x8F, 0x40, 0xBB, 0x40, 0xEB, 0x00
	},	
 
	/* GM_1_3 */
	{
		 0x1E, 0xC4, 0x14, 0x7A, 0x11, 0x0F, 0xF, 0x0C, 0x0D, 0xA1, 0x0C, 0xB6,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x29, 0x00, 0x49, 0x00, 0x6D, 0x40, 0x94, 0xC0, 0xBE, 0x80, 0xEB, 0x00
	},	
 
	/* GM_1_4 */
	{
		 0x24, 0x00, 0x15, 0x70, 0x11, 0x0F, 0x0E, 0xAA, 0x0D, 0x0F, 0x0B, 0xDB,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x2D, 0x40, 0x4E, 0xC0, 0x73, 0x00, 0x99, 0x80, 0xC1, 0x80, 0xEB, 0x00
 	},	
 
	/* GM_1_5 */
	{
		 0x29, 0x3B, 0x16, 0x3D, 0x11, 0x0F, 0x0E, 0x30, 0x0C, 0x7D, 0x0B, 0x24,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x31, 0x80, 0x54, 0x40, 0x78, 0x80, 0x9D, 0xC0, 0xC4, 0x00, 0xEB, 0x00
	},	
 
	/* GM_1_6 */
	{
		 0x2E, 0x27, 0x17, 0x0A, 0x10, 0xD2, 0x0D, 0xE7, 0x0B, 0xEB, 0x0A, 0x80,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x35, 0x80, 0x59, 0x80, 0x7D, 0x40, 0xA1, 0xC0, 0xC6, 0x40, 0xEB, 0x00
	},	
 
	/* GM_1_7 */
	{
		 0x33, 0x62, 0x17, 0x5C, 0x10, 0xD2, 0x0D, 0x6D, 0x0B, 0x6D, 0x09, 0xED,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x39, 0xC0, 0x5E, 0x40, 0x82, 0x00, 0xA5, 0x40, 0xC8, 0x40, 0xEB, 0x00
	},	
 
	/* GM_1_8 */
	{
		 0x38, 0x4E, 0x17, 0xAE, 0x10, 0xB4, 0x0D, 0x0C, 0x0A, 0xF0, 0x09, 0x6D,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x3D, 0xC0, 0x62, 0xC0, 0x86, 0x40, 0xA8, 0x80, 0xCA, 0x00, 0xEB, 0x00
	},	
 
	/* GM_1_9 */
	{
		 0x3D, 0x3B, 0x18, 0x00, 0x10, 0x5A, 0x0C, 0xC3, 0x0A, 0x72, 0x09, 0x00,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x41, 0xC0, 0x67, 0x40, 0x8A, 0x00, 0xAB, 0x80, 0xCB, 0x80, 0xEB, 0x00
	},	
 
	/* GM_2_0 */
	{
		 0x41, 0xD8, 0x18, 0x28, 0x10, 0x3C, 0x0C, 0x49, 0x0A, 0x1F, 0x08, 0x92,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x45, 0x80, 0x6B, 0x40, 0x8D, 0xC0, 0xAE, 0x00, 0xCD, 0x00, 0xEB, 0x00
	},	
 
	/* GM_2_1 */
	{
		 0x46, 0x76, 0x18, 0x51, 0x0F, 0xE1, 0x0C, 0x00, 0x09, 0xB6, 0x08, 0x36,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x49, 0x40, 0x6F, 0x40, 0x91, 0x00, 0xB0, 0x80, 0xCE, 0x40, 0xEB, 0x00
	},	
 
	/* GM_2_2 */
	{
		 0x4A, 0xC4, 0x18, 0x7A, 0x0F, 0xA5, 0x0B, 0x9E, 0x09, 0x63, 0x07, 0xDB,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x4C, 0xC0, 0x73, 0x00, 0x94, 0x40, 0xB2, 0xC0, 0xCF, 0x80, 0xEB, 0x00
	},	
 
	/* GM_2_3 */
	{
		 0x4F, 0x13, 0x18, 0x51, 0x0F, 0x69, 0x0B, 0x6D, 0x09, 0x0F, 0x07, 0x80,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x50, 0x40, 0x76, 0x40, 0x97, 0x00, 0xB5, 0x00, 0xD0, 0xC0, 0xEB, 0x00
	},	
 
	/* GM_2_4 */
	{
		 0x53, 0x13, 0x18, 0x7A, 0x0F, 0x0F, 0x0B, 0x24, 0x08, 0xBC, 0x07, 0x36,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x53, 0x80, 0x79, 0xC0, 0x99, 0xC0, 0xB7, 0x00, 0xD1, 0xC0, 0xEB, 0x00
	},	
 
	/* GM_2_5 */
	{
		 0x57, 0x13, 0x18, 0x51, 0x0E, 0xF0, 0x0A, 0xC3, 0x08, 0x7D, 0x06, 0xED,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x56, 0xC0, 0x7C, 0xC0, 0x9C, 0x80, 0xB8, 0xC0, 0xD2, 0xC0, 0xEB, 0x00
	},	
 
	/* GM_2_6 */
	{
		 0x5B, 0x13, 0x18, 0x28, 0x0E, 0x96, 0x0A, 0x92, 0x08, 0x29, 0x06, 0xB6,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x5A, 0x00, 0x7F, 0xC0, 0x9E, 0xC0, 0xBA, 0x80, 0xD3, 0x80, 0xEB, 0x00
	},	
 
	/* GM_2_7 */
	{
		 0x5E, 0xC4, 0x18, 0x00, 0x0E, 0x78, 0x0A, 0x30, 0x08, 0x00, 0x06, 0x6D,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x5D, 0x00, 0x82, 0x80, 0xA1, 0x40, 0xBC, 0x00, 0xD4, 0x80, 0xEB, 0x00
	},	
 
	/* GM_2_8 */
	{
		 0x62, 0x76, 0x17, 0xD7, 0x0E, 0x1E, 0x0A, 0x00, 0x07, 0xC1, 0x06, 0x36,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x60, 0x00, 0x85, 0x40, 0xA3, 0x40, 0xBD, 0x80, 0xD5, 0x40, 0xEB, 0x00
	},	
 
	/* GM_2_9 */
	{
		 0x65, 0xD8, 0x17, 0xAE, 0x0D, 0xE1, 0x09, 0xCF, 0x07, 0x82, 0x06, 0x00,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x62, 0xC0, 0x87, 0xC0, 0xA5, 0x40, 0xBF, 0x00, 0xD6, 0x00, 0xEB, 0x00
	},	
 
	/* GM_3_0 */
	{
		 0x69, 0x3B, 0x17, 0x85, 0x0D, 0xA5, 0x09, 0x86, 0x07, 0x43, 0x05, 0xDB,
		 0x10, 0x1D, 0x36, 0x58, 0x82, 0xB3, 0xEB,
		 0x10, 0x00, 0x65, 0x80, 0x8A, 0x40, 0xA7, 0x40, 0xC0, 0x40, 0xD6, 0x80, 0xEB, 0x00
	}
}

Registers 40h - 59h

address size read/write description
0x40-0x59 26 r/W Macrovision code


bytes(s) description
0-25 unknown, default is 0xFF


Register 62h

address size read/write description
0x62 1 W RGB switch control


bit(s) description
0 1:swap blue & red signals, 0: normal


Register 63h

address size read/write description
0x63 1 ? Unknown


bit(s) description
0 unknown (0: initial value)


Register 64h

address size read/write description
0x64 1 ? Unknown


bit(s) description
0 unknown (0: initial value)


Register 65h

address size read/write description
0x65 1 W color DAC control (oversampling ?)


bit(s) description
0 unknown (1: default value)


Modifying the default value does seem to have any effect on retail Wii.

Register 67h

address size read/write description
0x67 1 W Color Test


bit(s) description
0 1:display color test pattern, 0: normal


Register 68h

address size read/write description
0x68 1 ? Unknown


bit(s) description
0 unknown (0: initial value)


Register 6Ah

address size read/write description
0x6A 1 W Unknown (CCSEL ?)


bit(s) description
0 unknown (1: default value)


Register 6Bh

address size read/write description
0x6B 1 ? Unknown


bit(s) description
0 unknown (0: initial value)


Register 6Ch

address size read/write description
0x6C 1 ? Unknown


bit(s) description
0 unknown (0: initial value)


Register 6Dh

address size read/write description
0x6D 1 W Audio mute control


bit(s) description
0 1:enabled, 0: disabled


Register 6Eh

address size read/write description
0x6E 1 W RGB output filter


bit(s) description
0 1:enabled, 0: disabled

This is typically enabled when the video mode is set to EURGB60 (5). Setting this to zero results in red saturated image when using RGB video cable. Still need confirmation if this happens in 576i (PAL 50Hz) mode as well. Maybe this is used to select between S-Video (NTSC) & RGB (PAL60) output when the video output is 60hz.

Register 70h

address size read/write description
0x70 1 ? Unknown


bit(s) description
0 unknown (0: initial value)


Registers 71h & 72h

address size read/write description
0x71 2 W Audio stereo output control


bit(s) description
8-15 right volume ? (default value is 0x8e, 0x71 for d-Terminal ?)
0-7 left volume ? (default value is 0x8e, 0x71 for d-Terminal ?)


Registers 7Ah - 7Dh

address size read/write description
0x7A 4 W Closed Captioning control ?


bit(s) description
24-30 unknown (0: default value)
16-22 unknown (0: default value)
8-14 unknown (0: default value)
0-6 unknown (0: default value)


Sample Code

Here is some sample code to initialize the A/V encoder :)

/*
        BootMii - a Free Software replacement for the Nintendo/BroadOn bootloader.
        low-level video support for the BootMii UI
 
Copyright (C) 2008, 2009        Hector Martin "marcan" <marcan@marcansoft.com>
Copyright (C) 2009                      Haxx Enterprises <bushing@gmail.com>
Copyright (c) 2009              Sven Peter <svenpeter@gmail.com>
 
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 
Some routines and initialization constants originally came from the
"GAMECUBE LOW LEVEL INFO" document and sourcecode released by Titanik
of Crazy Nation and the GC Linux project.
*/
 
#include "bootmii_ppc.h"
#include "video_low.h"
#include "string.h"
#include "hollywood.h"
 
#ifdef VI_DEBUG
#define  VI_debug(f, arg...) printf("VI: " f, ##arg);
#else
#define  VI_debug(f, arg...) while(0)
#endif
 
// hardcoded VI init states -- these were obtained by dumping the register space after it was configured by 
 
a game in each mode
static const u16 VIDEO_Mode640X480NtsciYUV16[64] = {
  0x0F06, 0x0001, 0x4769, 0x01AD, 0x02EA, 0x5140, 0x0003, 0x0018,
  0x0002, 0x0019, 0x410C, 0x410C, 0x40ED, 0x40ED, 0x0043, 0x5A4E,
  0x0000, 0x0000, 0x0043, 0x5A4E, 0x0000, 0x0000, 0x0000, 0x0000,
  0x1107, 0x01AE, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
  0x0000, 0x0000, 0x0000, 0x0000, 0x2850, 0x0100, 0x1AE7, 0x71F0,
  0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
  0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0000, 0x0000,
  0x0280, 0x0000, 0x0000, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
 
static const u16 VIDEO_Mode640X480Pal50YUV16[64] = {
  0x11F5, 0x0101, 0x4B6A, 0x01B0, 0x02F8, 0x5640, 0x0001, 0x0023,
  0x0000, 0x0024, 0x4D2B, 0x4D6D, 0x4D8A, 0x4D4C, 0x0043, 0x5A4E,
  0x0000, 0x0000, 0x0043, 0x5A4E, 0x0000, 0x0000, 0x013C, 0x0144,
  0x1139, 0x01B1, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
  0x0000, 0x0000, 0x0000, 0x0000, 0x2850, 0x0100, 0x1AE7, 0x71F0,
  0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
  0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0000, 0x0000,
  0x0280, 0x0000, 0x0000, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
 
static const u16 VIDEO_Mode640X480Pal60YUV16[64] = {
  0x0F06, 0x0001, 0x4769, 0x01AD, 0x02EA, 0x5140, 0x0003, 0x0018,
  0x0002, 0x0019, 0x410C, 0x410C, 0x40ED, 0x40ED, 0x0043, 0x5A4E,
  0x0000, 0x0000, 0x0043, 0x5A4E, 0x0000, 0x0000, 0x0005, 0x0176,
  0x1107, 0x01AE, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
  0x0000, 0x0000, 0x0000, 0x0000, 0x2850, 0x0100, 0x1AE7, 0x71F0,
  0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
  0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0000, 0x0000,
  0x0280, 0x0000, 0x0000, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
 
static const u16 VIDEO_Mode640X480NtscpYUV16[64] = {
  0x1E0C, 0x0005, 0x4769, 0x01AD, 0x02EA, 0x5140, 0x0006, 0x0030,
  0x0006, 0x0030, 0x81D8, 0x81D8, 0x81D8, 0x81D8, 0x0015, 0x77A0,
  0x0000, 0x0000, 0x0015, 0x77A0, 0x0000, 0x0000, 0x022A, 0x01D6,
  0x120E, 0x0001, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
  0x0000, 0x0000, 0x0000, 0x0000, 0x2828, 0x0100, 0x1AE7, 0x71F0,
  0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
  0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0001, 0x0001,
  0x0280, 0x807A, 0x019C, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
 
static int video_mode;
void VIDEO_Init(int VideoMode)
{
        u32 Counter=0;
        const u16 *video_initstate=NULL;
 
        VI_debug("Resetting VI...\n");
        write16(R_VIDEO_STATUS1, 2);
        udelay(2);
        write16(R_VIDEO_STATUS1, 0);
        VI_debug("VI reset...\n");
 
        switch(VideoMode)
        {
        case VIDEO_640X480_NTSCi_YUV16:
                video_initstate = VIDEO_Mode640X480NtsciYUV16;
                break;
 
        case VIDEO_640X480_PAL50_YUV16:
                video_initstate = VIDEO_Mode640X480Pal50YUV16;
                break;
 
        case VIDEO_640X480_PAL60_YUV16:
                video_initstate = VIDEO_Mode640X480Pal60YUV16;
                break;
 
        case VIDEO_640X480_NTSCp_YUV16:
                video_initstate = VIDEO_Mode640X480NtscpYUV16;
                break;
 
        /* Use NTSC as default */
        default:
                VideoMode = VIDEO_640X480_NTSCi_YUV16;
                video_initstate = VIDEO_Mode640X480NtsciYUV16;
                break;
        }
        VI_debug("Configuring VI...\n");
        for(Counter=0; Counter<64; Counter++)
        {
                if(Counter==1)
                        write16(MEM_VIDEO_BASE + 2*Counter, video_initstate[Counter] & 0xFFFE);
                else
                        write16(MEM_VIDEO_BASE + 2*Counter, video_initstate[Counter]);
        }
 
        video_mode = VideoMode;
 
        write16(R_VIDEO_STATUS1, video_initstate[1]);
#ifdef VI_DEBUG
        VI_debug("VI dump:\n");
        for(Counter=0; Counter<32; Counter++)
                printf("%02x: %04x %04x,\n", Counter*4, read16(MEM_VIDEO_BASE + Counter*4), 
 
read16(MEM_VIDEO_BASE + Counter*4+2));
 
        printf("---\n");
#endif
}
 
void VIDEO_SetFrameBuffer(void *FrameBufferAddr)
{
        u32 fb = virt_to_phys(FrameBufferAddr);
 
        write32(R_VIDEO_FRAMEBUFFER_1, (fb >> 5) | 0x10000000);
        if(video_mode != VIDEO_640X480_NTSCp_YUV16)
                fb += 2 * 640; // 640 pixels == 1 line
        write32(R_VIDEO_FRAMEBUFFER_2, (fb >> 5) | 0x10000000);
}
void VIDEO_WaitVSync(void)
{
        while(read16(R_VIDEO_HALFLINE_1) >= 200);
        while(read16(R_VIDEO_HALFLINE_1) <  200);
}
 
/* black out video (not reversible!) */
void VIDEO_BlackOut(void)
{
        VIDEO_WaitVSync();
 
        int active = read32(R_VIDEO_VTIMING) >> 4;
 
        write32(R_VIDEO_PRB_ODD, read32(R_VIDEO_PRB_ODD) + ((active<<1)-2));
        write32(R_VIDEO_PRB_EVEN, read32(R_VIDEO_PRB_EVEN) + ((active<<1)-2));
        write32(R_VIDEO_PSB_ODD, read32(R_VIDEO_PSB_ODD) + 2);
        write32(R_VIDEO_PSB_EVEN, read32(R_VIDEO_PSB_EVEN) + 2);
 
        mask32(R_VIDEO_VTIMING, 0xfffffff0, 0);
}
 
//static vu16* const _viReg = (u16*)0xCC002000;
 
void VIDEO_Shutdown(void)
{
        VIDEO_BlackOut();
        write16(R_VIDEO_STATUS1, 0);
}
 
#define SLAVE_AVE 0xe0
 
static inline void aveSetDirection(u32 dir)
{
        u32 val = (read32(HW_GPIO1BDIR)&~0x8000)|0x4000;
        if(dir) val |= 0x8000;
        write32(HW_GPIO1BDIR, val);
}
static inline void aveSetSCL(u32 scl)
{
        u32 val = read32(HW_GPIO1BOUT)&~0x4000;
        if(scl) val |= 0x4000;
        write32(HW_GPIO1BOUT, val);
}
 
static inline void aveSetSDA(u32 sda)
{
        u32 val = read32(HW_GPIO1BOUT)&~0x8000;
        if(sda) val |= 0x8000;
        write32(HW_GPIO1BOUT, val);
}
 
static inline u32 aveGetSDA()
{
        if(read32(HW_GPIO1BIN)&0x8000)
                return 1;
        else
                return 0;
}
 
static u32 __sendSlaveAddress(u8 addr)
{
        u32 i;
 
        aveSetSDA(0);
        udelay(2);
 
        aveSetSCL(0);
        for(i=0;i<8;i++) {
                if(addr&0x80) aveSetSDA(1);
                else aveSetSDA(0);
                udelay(2);
 
                aveSetSCL(1);
                udelay(2);
 
                aveSetSCL(0);
                addr <<= 1;
        }
 
        aveSetDirection(0);
        udelay(2);
 
        aveSetSCL(1);
        udelay(2);
 
        if(aveGetSDA()!=0) {
                VI_debug("No ACK\n");
                return 0;
        }
 
        aveSetSDA(0);
        aveSetDirection(1);
        aveSetSCL(0);
 
        return 1;
}
 
static u32 __VISendI2CData(u8 addr,void *val,u32 len)
{
        u8 c;
        u32 i,j;
        u32 ret;
 
        VI_debug("I2C[%02x]:",addr);
        for(i=0;i<len;i++)
                VI_debug(" %02x", ((u8*)val)[i]);
        VI_debug("\n");
 
        aveSetDirection(1);
        aveSetSCL(1);
        aveSetSDA(1);
        udelay(4);
 
        ret = __sendSlaveAddress(addr);
        if(ret==0) {
                return 0;
        }
 
        aveSetDirection(1);
        for(i=0;i<len;i++) {
                c = ((u8*)val)[i];
                for(j=0;j<8;j++) {
                        if(c&0x80) aveSetSDA(1);
                        else aveSetSDA(0);
                        udelay(2);
 
                        aveSetSCL(1);
                        udelay(2);
                        aveSetSCL(0);
 
                        c <<= 1;
                }
                aveSetDirection(0);
                udelay(2);
                aveSetSCL(1);
                udelay(2);
 
                if(aveGetSDA()!=0) {
                        VI_debug("No ACK\n");
                        return 0;
                }
 
                aveSetSDA(0);
                aveSetDirection(1);
                aveSetSCL(0);
        }
 
        aveSetDirection(1);
        aveSetSDA(0);
        udelay(2);
        aveSetSDA(1);
 
        return 1;
}
 
static void __VIWriteI2CRegister8(u8 reg, u8 data)
{
        u8 buf[2];
        buf[0] = reg;
        buf[1] = data;
        __VISendI2CData(SLAVE_AVE,buf,2);
        udelay(2);
}
 
static void __VIWriteI2CRegister16(u8 reg, u16 data)
{
        u8 buf[3];
        buf[0] = reg;
        buf[1] = data >> 8;
        buf[2] = data & 0xFF;
        __VISendI2CData(SLAVE_AVE,buf,3);
        udelay(2);
}
 
static void __VIWriteI2CRegister32(u8 reg, u32 data)
{
        u8 buf[5];
        buf[0] = reg;
        buf[1] = data >> 24;
        buf[2] = (data >> 16) & 0xFF;
        buf[3] = (data >> 8) & 0xFF;
        buf[4] = data & 0xFF;
        __VISendI2CData(SLAVE_AVE,buf,5);
        udelay(2);
}
 
static void __VIWriteI2CRegisterBuf(u8 reg, int size, u8 *data)
{
        u8 buf[0x100];
        buf[0] = reg;
        memcpy(&buf[1], data, size);
        __VISendI2CData(SLAVE_AVE,buf,size+1);
        udelay(2);
}
 
static void __VISetYUVSEL(u8 dtvstatus)
{
        int vdacFlagRegion;
        switch(video_mode) {
        case VIDEO_640X480_NTSCi_YUV16:
        case VIDEO_640X480_NTSCp_YUV16:
        default:
                vdacFlagRegion = 0;
                break;
        case VIDEO_640X480_PAL50_YUV16:
        case VIDEO_640X480_PAL60_YUV16:
                vdacFlagRegion = 2;
                break;
        }
        __VIWriteI2CRegister8(0x01, (dtvstatus<<5) | (vdacFlagRegion&0x1f));
}
 
static void __VISetFilterEURGB60(u8 enable)
{
        __VIWriteI2CRegister8(0x6e, enable);
}
 
void VISetupEncoder(void)
{
        u8 macrobuf[0x1a];
 
        u8 gamma[0x21] = {
                0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00,
                0x10, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x60,
                0x80, 0xa0, 0xeb, 0x10, 0x00, 0x20, 0x00, 0x40,
                0x00, 0x60, 0x00, 0x80, 0x00, 0xa0, 0x00, 0xeb,
                0x00
        };
 
        u8 dtv;
 
        //tv = VIDEO_GetCurrentTvMode();
        dtv = read16(R_VIDEO_VISEL) & 1;
        //oldDtvStatus = dtv;
 
        // SetRevolutionModeSimple
 
        VI_debug("DTV status: %d\n", dtv);
 
        memset(macrobuf, 0, 0x1a);
 
        __VIWriteI2CRegister8(0x6a, 1);
        __VIWriteI2CRegister8(0x65, 1);
        __VISetYUVSEL(dtv);
        __VIWriteI2CRegister8(0x00, 0);
        __VIWriteI2CRegister16(0x71, 0x8e8e);
        __VIWriteI2CRegister8(0x02, 7);
        __VIWriteI2CRegister16(0x05, 0x0000);
        __VIWriteI2CRegister16(0x08, 0x0000);
        __VIWriteI2CRegister32(0x7A, 0x00000000);
 
        // Macrovision crap
        __VIWriteI2CRegisterBuf(0x40, sizeof(macrobuf), macrobuf);
 
        // Sometimes 1 in RGB mode? (reg 1 == 3)
        __VIWriteI2CRegister8(0x0A, 0);
 
        __VIWriteI2CRegister8(0x03, 1);
        __VIWriteI2CRegisterBuf(0x10, sizeof(gamma), gamma);
 
        __VIWriteI2CRegister8(0x04, 1);
        __VIWriteI2CRegister32(0x7A, 0x00000000);
        __VIWriteI2CRegister16(0x08, 0x0000);
        __VIWriteI2CRegister8(0x03, 1);
 
        //if(tv==VI_EURGB60) __VISetFilterEURGB60(1);
        //else
        __VISetFilterEURGB60(0);
 
        //oldTvStatus = tv;
}

Chip Picture

AVE-RVL.jpg

Personal tools
Resources
Community