2 BootMii - a Free Software replacement for the Nintendo/BroadOn bootloader.
3 low-level video support for the BootMii UI
5 Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
6 Copyright (C) 2009 Haxx Enterprises <bushing@gmail.com>
7 Copyright (c) 2009 Sven Peter <svenpeter@gmail.com>
9 # This code is licensed to you under the terms of the GNU GPL, version 2;
10 # see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
12 Some routines and initialization constants originally came from the
13 "GAMECUBE LOW LEVEL INFO" document and sourcecode released by Titanik
14 of Crazy Nation and the GC Linux project.
17 #include "bootmii_ppc.h"
18 #include "video_low.h"
22 #define VI_debug(f, arg...) printf("VI: " f, ##arg);
24 #define VI_debug(f, arg...) while(0)
27 // hardcoded VI init states
28 static const u16 VIDEO_Mode640X480NtsciYUV16[64] = {
29 0x0F06, 0x0001, 0x4769, 0x01AD, 0x02EA, 0x5140, 0x0003, 0x0018,
30 0x0002, 0x0019, 0x410C, 0x410C, 0x40ED, 0x40ED, 0x0043, 0x5A4E,
31 0x0000, 0x0000, 0x0043, 0x5A4E, 0x0000, 0x0000, 0x0000, 0x0000,
32 0x1107, 0x01AE, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
33 0x0000, 0x0000, 0x0000, 0x0000, 0x2850, 0x0100, 0x1AE7, 0x71F0,
34 0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
35 0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0000, 0x0000,
36 0x0280, 0x0000, 0x0000, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
38 static const u16 VIDEO_Mode640X480Pal50YUV16[64] = {
39 0x11F5, 0x0101, 0x4B6A, 0x01B0, 0x02F8, 0x5640, 0x0001, 0x0023,
40 0x0000, 0x0024, 0x4D2B, 0x4D6D, 0x4D8A, 0x4D4C, 0x0043, 0x5A4E,
41 0x0000, 0x0000, 0x0043, 0x5A4E, 0x0000, 0x0000, 0x013C, 0x0144,
42 0x1139, 0x01B1, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
43 0x0000, 0x0000, 0x0000, 0x0000, 0x2850, 0x0100, 0x1AE7, 0x71F0,
44 0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
45 0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0000, 0x0000,
46 0x0280, 0x0000, 0x0000, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
48 static const u16 VIDEO_Mode640X480Pal60YUV16[64] = {
49 0x0F06, 0x0001, 0x4769, 0x01AD, 0x02EA, 0x5140, 0x0003, 0x0018,
50 0x0002, 0x0019, 0x410C, 0x410C, 0x40ED, 0x40ED, 0x0043, 0x5A4E,
51 0x0000, 0x0000, 0x0043, 0x5A4E, 0x0000, 0x0000, 0x0005, 0x0176,
52 0x1107, 0x01AE, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
53 0x0000, 0x0000, 0x0000, 0x0000, 0x2850, 0x0100, 0x1AE7, 0x71F0,
54 0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
55 0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0000, 0x0000,
56 0x0280, 0x0000, 0x0000, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
58 static const u16 VIDEO_Mode640X480NtscpYUV16[64] = {
59 0x1E0C, 0x0005, 0x4769, 0x01AD, 0x02EA, 0x5140, 0x0006, 0x0030,
60 0x0006, 0x0030, 0x81D8, 0x81D8, 0x81D8, 0x81D8, 0x0015, 0x77A0,
61 0x0000, 0x0000, 0x0015, 0x77A0, 0x0000, 0x0000, 0x022A, 0x01D6,
62 0x120E, 0x0001, 0x1001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
63 0x0000, 0x0000, 0x0000, 0x0000, 0x2828, 0x0100, 0x1AE7, 0x71F0,
64 0x0DB4, 0xA574, 0x00C1, 0x188E, 0xC4C0, 0xCBE2, 0xFCEC, 0xDECF,
65 0x1313, 0x0F08, 0x0008, 0x0C0F, 0x00FF, 0x0000, 0x0001, 0x0001,
66 0x0280, 0x807A, 0x019C, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF};
68 static int video_mode;
70 void VIDEO_Init(int VideoMode)
73 const u16 *video_initstate=NULL;
75 VI_debug("Resetting VI...\n");
76 write16(R_VIDEO_STATUS1, 2);
78 write16(R_VIDEO_STATUS1, 0);
79 VI_debug("VI reset...\n");
83 case VIDEO_640X480_NTSCi_YUV16:
84 video_initstate = VIDEO_Mode640X480NtsciYUV16;
87 case VIDEO_640X480_PAL50_YUV16:
88 video_initstate = VIDEO_Mode640X480Pal50YUV16;
91 case VIDEO_640X480_PAL60_YUV16:
92 video_initstate = VIDEO_Mode640X480Pal60YUV16;
95 case VIDEO_640X480_NTSCp_YUV16:
96 video_initstate = VIDEO_Mode640X480NtscpYUV16;
99 /* Use NTSC as default */
101 VideoMode = VIDEO_640X480_NTSCi_YUV16;
102 video_initstate = VIDEO_Mode640X480NtsciYUV16;
106 VI_debug("Configuring VI...\n");
107 for(Counter=0; Counter<64; Counter++)
110 write16(MEM_VIDEO_BASE + 2*Counter, video_initstate[Counter] & 0xFFFE);
112 write16(MEM_VIDEO_BASE + 2*Counter, video_initstate[Counter]);
115 video_mode = VideoMode;
117 write16(R_VIDEO_STATUS1, video_initstate[1]);
119 VI_debug("VI dump:\n");
120 for(Counter=0; Counter<32; Counter++)
121 printf("%02x: %04x %04x,\n", Counter*4, read16(MEM_VIDEO_BASE + Counter*4), read16(MEM_VIDEO_BASE + Counter*4+2));
127 void VIDEO_SetFrameBuffer(void *FrameBufferAddr)
129 u32 fb = virt_to_phys(FrameBufferAddr);
131 write32(R_VIDEO_FRAMEBUFFER_1, (fb >> 5) | 0x10000000);
132 if(video_mode != VIDEO_640X480_NTSCp_YUV16)
133 fb += 2 * 640; // 640 pixels == 1 line
134 write32(R_VIDEO_FRAMEBUFFER_2, (fb >> 5) | 0x10000000);
137 void VIDEO_WaitVSync(void)
139 while(read16(R_VIDEO_HALFLINE_1) >= 200);
140 while(read16(R_VIDEO_HALFLINE_1) < 200);
143 /* black out video (not reversible!) */
144 void VIDEO_BlackOut(void)
148 int active = read32(R_VIDEO_VTIMING) >> 4;
150 write32(R_VIDEO_PRB_ODD, read32(R_VIDEO_PRB_ODD) + ((active<<1)-2));
151 write32(R_VIDEO_PRB_EVEN, read32(R_VIDEO_PRB_EVEN) + ((active<<1)-2));
152 write32(R_VIDEO_PSB_ODD, read32(R_VIDEO_PSB_ODD) + 2);
153 write32(R_VIDEO_PSB_EVEN, read32(R_VIDEO_PSB_EVEN) + 2);
155 mask32(R_VIDEO_VTIMING, 0xfffffff0, 0);
158 //static vu16* const _viReg = (u16*)0xCC002000;
160 void VIDEO_Shutdown(void)
163 write16(R_VIDEO_STATUS1, 0);
166 #define HW_REG_BASE 0xd800000
168 // PPC side of GPIO1 (Starlet can access this too)
170 #define HW_GPIO1BOUT (HW_REG_BASE + 0x0c0)
171 // Direction (1=output)
172 #define HW_GPIO1BDIR (HW_REG_BASE + 0x0c4)
174 #define HW_GPIO1BIN (HW_REG_BASE + 0x0c8)
176 #define SLAVE_AVE 0xe0
178 static inline void aveSetDirection(u32 dir)
180 u32 val = (read32(HW_GPIO1BDIR)&~0x8000)|0x4000;
181 if(dir) val |= 0x8000;
182 write32(HW_GPIO1BDIR, val);
185 static inline void aveSetSCL(u32 scl)
187 u32 val = read32(HW_GPIO1BOUT)&~0x4000;
188 if(scl) val |= 0x4000;
189 write32(HW_GPIO1BOUT, val);
192 static inline void aveSetSDA(u32 sda)
194 u32 val = read32(HW_GPIO1BOUT)&~0x8000;
195 if(sda) val |= 0x8000;
196 write32(HW_GPIO1BOUT, val);
199 static inline u32 aveGetSDA()
201 if(read32(HW_GPIO1BIN)&0x8000)
207 static u32 __sendSlaveAddress(u8 addr)
216 if(addr&0x80) aveSetSDA(1);
234 VI_debug("No ACK\n");
245 static u32 __VISendI2CData(u8 addr,void *val,u32 len)
251 VI_debug("I2C[%02x]:",addr);
253 VI_debug(" %02x", ((u8*)val)[i]);
262 ret = __sendSlaveAddress(addr);
271 if(c&0x80) aveSetSDA(1);
287 VI_debug("No ACK\n");
304 static void __VIWriteI2CRegister8(u8 reg, u8 data)
309 __VISendI2CData(SLAVE_AVE,buf,2);
313 static void __VIWriteI2CRegister16(u8 reg, u16 data)
318 buf[2] = data & 0xFF;
319 __VISendI2CData(SLAVE_AVE,buf,3);
323 static void __VIWriteI2CRegister32(u8 reg, u32 data)
328 buf[2] = (data >> 16) & 0xFF;
329 buf[3] = (data >> 8) & 0xFF;
330 buf[4] = data & 0xFF;
331 __VISendI2CData(SLAVE_AVE,buf,5);
335 static void __VIWriteI2CRegisterBuf(u8 reg, int size, u8 *data)
339 memcpy(&buf[1], data, size);
340 __VISendI2CData(SLAVE_AVE,buf,size+1);
344 static void __VISetYUVSEL(u8 dtvstatus)
348 case VIDEO_640X480_NTSCi_YUV16:
349 case VIDEO_640X480_NTSCp_YUV16:
353 case VIDEO_640X480_PAL50_YUV16:
354 case VIDEO_640X480_PAL60_YUV16:
358 __VIWriteI2CRegister8(0x01, (dtvstatus<<5) | (vdacFlagRegion&0x1f));
361 static void __VISetFilterEURGB60(u8 enable)
363 __VIWriteI2CRegister8(0x6e, enable);
366 void VISetupEncoder(void)
371 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00,
372 0x10, 0x00, 0x10, 0x00, 0x10, 0x20, 0x40, 0x60,
373 0x80, 0xa0, 0xeb, 0x10, 0x00, 0x20, 0x00, 0x40,
374 0x00, 0x60, 0x00, 0x80, 0x00, 0xa0, 0x00, 0xeb,
380 //tv = VIDEO_GetCurrentTvMode();
381 dtv = read16(R_VIDEO_VISEL) & 1;
382 //oldDtvStatus = dtv;
384 // SetRevolutionModeSimple
386 VI_debug("DTV status: %d\n", dtv);
388 memset(macrobuf, 0, 0x1a);
390 __VIWriteI2CRegister8(0x6a, 1);
391 __VIWriteI2CRegister8(0x65, 1);
393 __VIWriteI2CRegister8(0x00, 0);
394 __VIWriteI2CRegister16(0x71, 0x8e8e);
395 __VIWriteI2CRegister8(0x02, 7);
396 __VIWriteI2CRegister16(0x05, 0x0000);
397 __VIWriteI2CRegister16(0x08, 0x0000);
398 __VIWriteI2CRegister32(0x7A, 0x00000000);
401 __VIWriteI2CRegisterBuf(0x40, sizeof(macrobuf), macrobuf);
403 // Sometimes 1 in RGB mode? (reg 1 == 3)
404 __VIWriteI2CRegister8(0x0A, 0);
406 __VIWriteI2CRegister8(0x03, 1);
408 __VIWriteI2CRegisterBuf(0x10, sizeof(gamma), gamma);
410 __VIWriteI2CRegister8(0x04, 1);
411 __VIWriteI2CRegister32(0x7A, 0x00000000);
412 __VIWriteI2CRegister16(0x08, 0x0000);
413 __VIWriteI2CRegister8(0x03, 1);
415 //if(tv==VI_EURGB60) __VISetFilterEURGB60(1);
417 __VISetFilterEURGB60(0);