Initial commit
[savezelda.git] / loader / video.c
1 // Copyright 2008-2009  Segher Boessenkool  <segher@kernel.crashing.org>
2 // Copyright 2003-2004  Felix Domke <tmbinc@elitedvb.net>
3 // This code is licensed to you under the terms of the GNU GPL, version 2;
4 // see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5
6 #include "loader.h"
7
8 extern u8 console_font_10x16x4[];
9
10 #define FONT_XSIZE  10
11 #define FONT_YSIZE  16
12 #define FONT_XGAP   0
13 #define FONT_YGAP   2
14
15 static struct {
16         u32 xres, yres, stride;
17
18         u32 cursor_x, cursor_y;
19
20         u32 border_left, border_right, border_top, border_bottom;
21 } fb;
22
23 static void fb_write(u32 offset, u32 x)
24 {
25 //      write32(0x00f00000 + offset, x);
26         u32 *p = (u32 *)(0x80f00000 + offset);
27         *p = x;
28         sync_after_write(p, 4);
29 }
30
31 static u32 fb_read(u32 offset)
32 {
33 //      return read32(0x00f00000 + offset);
34         u32 *p = (u32 *)(0x80f00000 + offset);
35
36         return *p;
37 }
38
39 static void fb_clear_lines(u32 top, u32 lines)
40 {
41         u32 x, y;
42         u32 offset;
43
44         offset = fb.stride * top;
45
46         for (y = 0; y < lines; y++) {
47                 for (x = 0; x < fb.xres/2; x++)
48                         fb_write(offset + 4*x, 0x00800080);
49
50                 offset += fb.stride;
51         }
52 }
53
54 static void fb_scroll_line(void)
55 {
56         u32 x, y;
57         u32 offset, delta;
58         u32 lines = FONT_YSIZE + FONT_YGAP;
59
60         offset = fb.stride * fb.border_top;
61         delta = fb.stride * lines;
62
63         for (y = fb.border_top; y < fb.yres - lines; y++) {
64                 for (x = 0; x < fb.xres/2; x++)
65                         fb_write(offset + 4*x, fb_read(offset + 4*x + delta));
66
67                 offset += fb.stride;
68         }
69
70         fb_clear_lines(fb.yres - lines, lines);
71
72         fb.cursor_y -= lines;
73 }
74
75 static void fb_drawc(u32 x, u32 y, u8 c)
76 {
77         if (c < 0x20 || c > 0x7f)
78                 c = 0x7f;
79         c -= 0x20;
80
81         u32 offset = fb.stride*y + 2*x;
82         u8 *font = &console_font_10x16x4[c * FONT_XSIZE * FONT_YSIZE / 2];
83
84         u32 ax, ay;
85         for (ay = 0; ay < FONT_YSIZE; ay++) {
86                 for (ax = 0; ax < FONT_XSIZE / 2; ax++) {
87                         u8 bits = *font++;
88                         u32 nybh = bits & 0xf0;
89                         u32 nybl = bits & 0x0f;
90                         u32 q = 0x00800080;
91                         q |= (nybh << 24) | (nybh << 20);
92                         q |= (nybl << 12) | (nybl << 8);
93                         fb_write(offset + 4*ax, q);
94                 }
95                 offset += fb.stride;
96         }
97 }
98
99 void fb_putc(char c)
100 {
101         switch (c) {
102         case '\n':
103                 fb.cursor_y += FONT_YSIZE + FONT_YGAP;
104
105         case '\r':
106                 fb.cursor_x = fb.border_left;
107                 break;
108
109         default:
110                 fb_drawc(fb.cursor_x, fb.cursor_y, c);
111                 fb.cursor_x += FONT_XSIZE + FONT_XGAP;
112                 if ((fb.cursor_x + FONT_XSIZE) > fb.border_right) {
113                         fb.cursor_y += FONT_YSIZE + FONT_YGAP;
114                         fb.cursor_x = fb.border_left;
115                 }
116         }
117
118         if (fb.cursor_y + FONT_YSIZE >= fb.border_bottom)
119                 fb_scroll_line();
120 }
121
122
123 static void fb_init(u32 xres, u32 yres, u32 stride)
124 {
125         fb.xres = xres;
126         fb.yres = yres;
127         fb.stride = stride;
128
129         fb.border_left = 30;
130         fb.border_top = 30;
131         fb.border_right = fb.xres - 30;
132         fb.border_bottom = fb.yres - 30;
133
134         fb.cursor_x = fb.border_left;
135         fb.cursor_y = fb.border_top;
136
137         fb_clear_lines(0, fb.yres);
138 }
139
140 void video_init(void)
141 {
142         // read VTR register to determine linecount and mode
143         u32 vtr = read16(0x0c002000);
144         u32 lines = vtr >> 4;
145
146         if ((vtr & 0x0f) > 10) {        // progressive
147                 // set framebuffer position
148                 write32(0x0c00201c, 0x00f00000);
149                 write32(0x0c002024, 0x00f00000);
150         } else {                        //interlaced
151                 lines *= 2;
152
153                 u32 vto = read32(0x0c00200c);
154                 u32 vte = read32(0x0c002010);
155
156                 // set framebuffer position
157                 // try to figure out the interlacing order
158                 if ((vto & 0x03ff) < (vte & 0x03ff)) {
159                         write32(0x0c00201c, 0x00f00000);
160                         write32(0x0c002024, 0x00f00000 + 2*640);
161                 } else {
162                         write32(0x0c00201c, 0x00f00000 + 2*640);
163                         write32(0x0c002024, 0x00f00000);
164                 }
165         }
166
167         fb_init(640, lines, 2*640);
168 }