port-work; won't compile or even work
[ppcskel.git] / video_low.c
1 /*
2         BootMii - a Free Software replacement for the Nintendo/BroadOn bootloader.
3         low-level video support for the BootMii UI
4
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>
8
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
11
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.
15 */
16
17 #include "bootmii_ppc.h"
18 #include "video_low.h"
19 #include "string.h"
20
21 #ifdef VI_DEBUG
22 #define  VI_debug(f, arg...) printf("VI: " f, ##arg);
23 #else
24 #define  VI_debug(f, arg...) while(0)
25 #endif
26
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};
37
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};
47
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};
57
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};
67
68 static int video_mode;
69
70 void VIDEO_Init(int VideoMode)
71 {
72         u32 Counter=0;
73         const u16 *video_initstate=NULL;
74
75         VI_debug("Resetting VI...\n");
76         write16(R_VIDEO_STATUS1, 2);
77         udelay(2);
78         write16(R_VIDEO_STATUS1, 0);
79         VI_debug("VI reset...\n");
80
81         switch(VideoMode)
82         {
83         case VIDEO_640X480_NTSCi_YUV16:
84                 video_initstate = VIDEO_Mode640X480NtsciYUV16;
85                 break;
86
87         case VIDEO_640X480_PAL50_YUV16:
88                 video_initstate = VIDEO_Mode640X480Pal50YUV16;
89                 break;
90
91         case VIDEO_640X480_PAL60_YUV16:
92                 video_initstate = VIDEO_Mode640X480Pal60YUV16;
93                 break;
94
95         case VIDEO_640X480_NTSCp_YUV16:
96                 video_initstate = VIDEO_Mode640X480NtscpYUV16;
97                 break;
98
99         /* Use NTSC as default */
100         default:
101                 VideoMode = VIDEO_640X480_NTSCi_YUV16;
102                 video_initstate = VIDEO_Mode640X480NtsciYUV16;
103                 break;
104         }
105         
106         VI_debug("Configuring VI...\n");
107         for(Counter=0; Counter<64; Counter++)
108         {
109                 if(Counter==1)
110                         write16(MEM_VIDEO_BASE + 2*Counter, video_initstate[Counter] & 0xFFFE);
111                 else
112                         write16(MEM_VIDEO_BASE + 2*Counter, video_initstate[Counter]);
113         }
114
115         video_mode = VideoMode;
116
117         write16(R_VIDEO_STATUS1, video_initstate[1]);
118 #ifdef VI_DEBUG
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));
122
123         printf("---\n");
124 #endif
125 }
126
127 void VIDEO_SetFrameBuffer(void *FrameBufferAddr)
128 {
129         u32 fb = virt_to_phys(FrameBufferAddr);
130
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);
135 }
136
137 void VIDEO_WaitVSync(void)
138 {
139         while(read16(R_VIDEO_HALFLINE_1) >= 200);
140         while(read16(R_VIDEO_HALFLINE_1) <  200);
141 }
142
143 /* black out video (not reversible!) */
144 void VIDEO_BlackOut(void)
145 {
146         VIDEO_WaitVSync();
147
148         int active = read32(R_VIDEO_VTIMING) >> 4;
149
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);
154
155         mask32(R_VIDEO_VTIMING, 0xfffffff0, 0);
156 }
157
158 //static vu16* const _viReg = (u16*)0xCC002000;
159
160 void VIDEO_Shutdown(void)
161 {
162         VIDEO_BlackOut();
163         write16(R_VIDEO_STATUS1, 0);
164 }
165
166 #define         HW_REG_BASE             0xd800000
167
168 // PPC side of GPIO1 (Starlet can access this too)
169 // Output state
170 #define         HW_GPIO1BOUT            (HW_REG_BASE + 0x0c0)
171 // Direction (1=output)
172 #define         HW_GPIO1BDIR            (HW_REG_BASE + 0x0c4)
173 // Input state
174 #define         HW_GPIO1BIN                     (HW_REG_BASE + 0x0c8)
175
176 #define SLAVE_AVE 0xe0
177
178 static inline void aveSetDirection(u32 dir)
179 {
180         u32 val = (read32(HW_GPIO1BDIR)&~0x8000)|0x4000;
181         if(dir) val |= 0x8000;
182         write32(HW_GPIO1BDIR, val);
183 }
184
185 static inline void aveSetSCL(u32 scl)
186 {
187         u32 val = read32(HW_GPIO1BOUT)&~0x4000;
188         if(scl) val |= 0x4000;
189         write32(HW_GPIO1BOUT, val);
190 }
191
192 static inline void aveSetSDA(u32 sda)
193 {
194         u32 val = read32(HW_GPIO1BOUT)&~0x8000;
195         if(sda) val |= 0x8000;
196         write32(HW_GPIO1BOUT, val);
197 }
198
199 static inline u32 aveGetSDA()
200 {
201         if(read32(HW_GPIO1BIN)&0x8000)
202                 return 1;
203         else
204                 return 0;
205 }
206
207 static u32 __sendSlaveAddress(u8 addr)
208 {
209         u32 i;
210
211         aveSetSDA(0);
212         udelay(2);
213
214         aveSetSCL(0);
215         for(i=0;i<8;i++) {
216                 if(addr&0x80) aveSetSDA(1);
217                 else aveSetSDA(0);
218                 udelay(2);
219
220                 aveSetSCL(1);
221                 udelay(2);
222
223                 aveSetSCL(0);
224                 addr <<= 1;
225         }
226
227         aveSetDirection(0);
228         udelay(2);
229
230         aveSetSCL(1);
231         udelay(2);
232
233         if(aveGetSDA()!=0) {
234                 VI_debug("No ACK\n");
235                 return 0;
236         }
237
238         aveSetSDA(0);
239         aveSetDirection(1);
240         aveSetSCL(0);
241
242         return 1;
243 }
244
245 static u32 __VISendI2CData(u8 addr,void *val,u32 len)
246 {
247         u8 c;
248         u32 i,j;
249         u32 ret;
250
251         VI_debug("I2C[%02x]:",addr);
252         for(i=0;i<len;i++)
253                 VI_debug(" %02x", ((u8*)val)[i]);
254         VI_debug("\n");
255
256         aveSetDirection(1);
257         aveSetSCL(1);
258
259         aveSetSDA(1);
260         udelay(4);
261
262         ret = __sendSlaveAddress(addr);
263         if(ret==0) {
264                 return 0;
265         }
266
267         aveSetDirection(1);
268         for(i=0;i<len;i++) {
269                 c = ((u8*)val)[i];
270                 for(j=0;j<8;j++) {
271                         if(c&0x80) aveSetSDA(1);
272                         else aveSetSDA(0);
273                         udelay(2);
274
275                         aveSetSCL(1);
276                         udelay(2);
277                         aveSetSCL(0);
278
279                         c <<= 1;
280                 }
281                 aveSetDirection(0);
282                 udelay(2);
283                 aveSetSCL(1);
284                 udelay(2);
285
286                 if(aveGetSDA()!=0) {
287                         VI_debug("No ACK\n");
288                         return 0;
289                 }
290
291                 aveSetSDA(0);
292                 aveSetDirection(1);
293                 aveSetSCL(0);
294         }
295
296         aveSetDirection(1);
297         aveSetSDA(0);
298         udelay(2);
299         aveSetSDA(1);
300
301         return 1;
302 }
303
304 static void __VIWriteI2CRegister8(u8 reg, u8 data)
305 {
306         u8 buf[2];
307         buf[0] = reg;
308         buf[1] = data;
309         __VISendI2CData(SLAVE_AVE,buf,2);
310         udelay(2);
311 }
312
313 static void __VIWriteI2CRegister16(u8 reg, u16 data)
314 {
315         u8 buf[3];
316         buf[0] = reg;
317         buf[1] = data >> 8;
318         buf[2] = data & 0xFF;
319         __VISendI2CData(SLAVE_AVE,buf,3);
320         udelay(2);
321 }
322
323 static void __VIWriteI2CRegister32(u8 reg, u32 data)
324 {
325         u8 buf[5];
326         buf[0] = reg;
327         buf[1] = data >> 24;
328         buf[2] = (data >> 16) & 0xFF;
329         buf[3] = (data >> 8) & 0xFF;
330         buf[4] = data & 0xFF;
331         __VISendI2CData(SLAVE_AVE,buf,5);
332         udelay(2);
333 }
334
335 static void __VIWriteI2CRegisterBuf(u8 reg, int size, u8 *data)
336 {
337         u8 buf[0x100];
338         buf[0] = reg;
339         memcpy(&buf[1], data, size);
340         __VISendI2CData(SLAVE_AVE,buf,size+1);
341         udelay(2);
342 }
343
344 static void __VISetYUVSEL(u8 dtvstatus)
345 {
346         int vdacFlagRegion;
347         switch(video_mode) {
348         case VIDEO_640X480_NTSCi_YUV16:
349         case VIDEO_640X480_NTSCp_YUV16:
350         default:
351                 vdacFlagRegion = 0;
352                 break;
353         case VIDEO_640X480_PAL50_YUV16:
354         case VIDEO_640X480_PAL60_YUV16:
355                 vdacFlagRegion = 2;
356                 break;
357         }
358         __VIWriteI2CRegister8(0x01, (dtvstatus<<5) | (vdacFlagRegion&0x1f));
359 }
360
361 static void __VISetFilterEURGB60(u8 enable)
362 {
363         __VIWriteI2CRegister8(0x6e, enable);
364 }
365
366 void VISetupEncoder(void)
367 {
368         u8 macrobuf[0x1a];
369
370         u8 gamma[0x21] = {
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,
375                 0x00
376         };
377
378         u8 dtv;
379
380         //tv = VIDEO_GetCurrentTvMode();
381         dtv = read16(R_VIDEO_VISEL) & 1;
382         //oldDtvStatus = dtv;
383
384         // SetRevolutionModeSimple
385
386         VI_debug("DTV status: %d\n", dtv);
387
388         memset(macrobuf, 0, 0x1a);
389
390         __VIWriteI2CRegister8(0x6a, 1);
391         __VIWriteI2CRegister8(0x65, 1);
392         __VISetYUVSEL(dtv);
393         __VIWriteI2CRegister8(0x00, 0);
394         __VIWriteI2CRegister16(0x71, 0x8e8e);
395         __VIWriteI2CRegister8(0x02, 7);
396         __VIWriteI2CRegister16(0x05, 0x0000);
397         __VIWriteI2CRegister16(0x08, 0x0000);
398         __VIWriteI2CRegister32(0x7A, 0x00000000);
399
400         // Macrovision crap
401         __VIWriteI2CRegisterBuf(0x40, sizeof(macrobuf), macrobuf);
402
403         // Sometimes 1 in RGB mode? (reg 1 == 3)
404         __VIWriteI2CRegister8(0x0A, 0);
405
406         __VIWriteI2CRegister8(0x03, 1);
407
408         __VIWriteI2CRegisterBuf(0x10, sizeof(gamma), gamma);
409
410         __VIWriteI2CRegister8(0x04, 1);
411         __VIWriteI2CRegister32(0x7A, 0x00000000);
412         __VIWriteI2CRegister16(0x08, 0x0000);
413         __VIWriteI2CRegister8(0x03, 1);
414
415         //if(tv==VI_EURGB60) __VISetFilterEURGB60(1);
416         //else
417         __VISetFilterEURGB60(0);
418
419         //oldTvStatus = tv;
420 }
421