]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/sh/dreamcast/v2_0/src/fb_support.c
Initial revision
[karo-tx-redboot.git] / packages / hal / sh / dreamcast / v2_0 / src / fb_support.c
1 //=============================================================================
2 //
3 //      fb_support.c
4 //
5 //      Frame buffer support for Dreamcast
6 //
7 //=============================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //=============================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):   t@keshi.org
44 // Contributors:t@keshi.org, gthomas
45 // Date:        2001-07-30
46 // Purpose:     Red Hat/eCos banner for display during boot
47 //              
48 //####DESCRIPTIONEND####
49 //
50 //=============================================================================
51
52 #include <pkgconf/hal.h>
53
54 #include <cyg/infra/diag.h>
55 #include <cyg/hal/hal_io.h>       // IO macros
56 #include <cyg/hal/hal_if.h>       // Virtual vector support
57 #include <cyg/hal/hal_arch.h>     // Register state info
58 #include <cyg/hal/hal_intr.h>     // HAL interrupt macros
59
60 #define LOGO_AT_TOP
61 #include "banner.xpm"
62 #include "font.h"
63
64 #define RESETREG        0xa05f8008
65 #define BORDERRGB       0xa05f8040
66 #define DISPLAYMODE     0xa05f8044
67 #define ALPHAMODE       0xa05f8048
68 #define DISPLAYALIGN    0xa05f804c
69 #define BASEOFFSET1     0xa05f8050
70 #define BASEOFFSET2     0xa05f8054
71 #define DISPLAYSIZE     0xa05f805c
72 #define SYNCMODE        0xa05f80d0
73 #define VERTICALRANGE   0xa05f80dc
74 #define HORIZPOSITION   0xa05f80ec
75 #define VERTPOSITION    0xa05f80f0
76 #define PALETTEMODE     0xa05f8108
77 #define VIDEOOUTPUT     0xa0702c00
78
79 static unsigned long dc_parm_vga_16bpp[] = {
80     DISPLAYMODE,        0x00800005,
81     BASEOFFSET1,        0,
82     BASEOFFSET2,        640*2,
83     DISPLAYSIZE,        (1<<20)+((480-1)<<10)+(640*2/4-1),
84     SYNCMODE,           0x100,
85     VERTPOSITION,       0x00230023,
86     VERTICALRANGE,      0x00280208,
87     HORIZPOSITION,      0x00000090,
88     VIDEOOUTPUT,        0,
89     0, 0,
90 };
91     
92 static unsigned long dc_parm_vga_32bpp[] = {
93     DISPLAYMODE,        0x0080000d,
94     BASEOFFSET1,        0,
95     BASEOFFSET2,        640*4,
96     DISPLAYSIZE,        (1<<20)+((480-1)<<10)+(640*4/4-1),
97     SYNCMODE,           0x100,
98     VERTPOSITION,       0x00230023,
99     VERTICALRANGE,      0x00280208,
100     HORIZPOSITION,      0x00000090,
101     VIDEOOUTPUT,        0,
102     0, 0,
103 };
104
105 static unsigned long *dc_parm_vga[] = {
106     dc_parm_vga_16bpp,
107     dc_parm_vga_32bpp,
108 };
109
110 static unsigned long dc_parm_composite_16bpp[] = {
111     DISPLAYMODE,        0x00000005,
112     BASEOFFSET1,        0,
113     BASEOFFSET2,        640*2,
114     DISPLAYSIZE,        ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
115     SYNCMODE,           0x150,
116     VERTPOSITION,       0x00120012,
117     VERTICALRANGE,      0x00240204,
118     HORIZPOSITION,      0x000000a4,
119     VIDEOOUTPUT,        0x300,
120     0, 0,
121 };
122     
123 static unsigned long dc_parm_composite_32bpp[] = {
124     DISPLAYMODE,        0x0000000d,
125     BASEOFFSET1,        0,
126     BASEOFFSET2,        640*4,
127     DISPLAYSIZE,        ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
128     SYNCMODE,           0x150,
129     VERTPOSITION,       0x00120012,
130     VERTICALRANGE,      0x00240204,
131     HORIZPOSITION,      0x000000a4,
132     VIDEOOUTPUT,        0x300,
133     0, 0,
134 };
135
136 static unsigned long *dc_parm_composite[] = {
137     dc_parm_composite_16bpp,
138     dc_parm_composite_32bpp,
139 };
140
141 static unsigned long dc_parm_interlace_16bpp[] = {
142     DISPLAYMODE,        0x00000005,
143     BASEOFFSET1,        0,
144     BASEOFFSET2,        640*2,
145     DISPLAYSIZE,        ((640*2/4+1)<<20)+((240-1)<<10)+(640*2/4-1),
146     SYNCMODE,           0x150,
147     VERTPOSITION,       0x00120012,
148     VERTICALRANGE,      0x00240204,
149     HORIZPOSITION,      0x000000a4,
150     VIDEOOUTPUT,        0,
151     0, 0,
152 };
153     
154 static unsigned long dc_parm_interlace_32bpp[] = {
155     DISPLAYMODE,        0x0000000d,
156     BASEOFFSET1,        0,
157     BASEOFFSET2,        640*4,
158     DISPLAYSIZE,        ((640*4/4+1)<<20)+((240-1)<<10)+(640*4/4-1),
159     SYNCMODE,           0x150,
160     VERTPOSITION,       0x00120012,
161     VERTICALRANGE,      0x00240204,
162     HORIZPOSITION,      0x000000a4,
163     VIDEOOUTPUT,        0,
164     0, 0,
165 };
166
167 static unsigned long *dc_parm_interlace[] = {
168     dc_parm_interlace_16bpp,
169     dc_parm_interlace_32bpp,
170 };
171
172 /*
173  *      Check cable type.
174  *      0: VGA, 2: RGB, 3: Composite
175  */
176
177 #define PCTRA   0xff80002c
178 #define PDTRA   0xff800030
179
180 static int dcfb_cable_check(void)
181 {
182     unsigned long temp;
183     HAL_READ_UINT32(PCTRA, temp);
184     temp &= 0xfff0ffff;
185     temp |= 0x000a0000;
186     HAL_WRITE_UINT32(PCTRA, temp);
187     HAL_READ_UINT16(PDTRA, temp);
188     return (temp>>8)&3;
189 }
190
191
192 // Physical dimensions of LCD display
193 #define DISPLAY_WIDTH  640
194 #define DISPLAY_HEIGHT 480
195
196 #define LCD_WIDTH  640
197 #define LCD_HEIGHT 480
198 #define LCD_DEPTH   16
199
200 #define USE_RGB565
201 #ifdef USE_RGB565
202 #define RGB_RED(x)   (((x)&0x1F)<<11)
203 #define RGB_GREEN(x) (((x)&0x3F)<<5)
204 #define RGB_BLUE(x)  ((x)&0x1F)
205 #else
206 #define RGB_RED(x)   (((x)&0x0F)<<12)
207 #define RGB_GREEN(x) (((x)&0x0F)<<7)
208 #define RGB_BLUE(x)  (((x)&0x0F)<<1)
209 #endif
210
211 // Physical screen info
212 static int lcd_width  = LCD_WIDTH;
213 static int lcd_height = LCD_HEIGHT;
214
215 // Virtual screen info
216 static int curX = 0;  // Last used position
217 static int curY = 0;
218 //static int width = LCD_WIDTH / (FONT_WIDTH*NIBBLES_PER_PIXEL);
219 //static int height = LCD_HEIGHT / (FONT_HEIGHT*SCREEN_SCALE);
220
221 static int fg = RGB_RED(15) | RGB_GREEN(63) | RGB_BLUE(8);
222 static int bg = RGB_RED(0) | RGB_GREEN(0) | RGB_BLUE(15/*31*/);
223
224 #define SCREEN_PAN            20
225 #define SCREEN_WIDTH          80
226 #define SCREEN_HEIGHT         (LCD_HEIGHT/FONT_HEIGHT)
227 #define VISIBLE_SCREEN_WIDTH  (LCD_WIDTH/FONT_WIDTH)
228 #define VISIBLE_SCREEN_HEIGHT (LCD_HEIGHT/FONT_HEIGHT)
229 static char screen[SCREEN_HEIGHT][SCREEN_WIDTH];
230 static int screen_start = 0;
231 static int screen_height = SCREEN_HEIGHT;
232 static int screen_width = SCREEN_WIDTH;
233 static int screen_pan = 0;
234
235 static bool cursor_enable = true;
236
237 static int kbd_pos;
238
239 static unsigned short *framebuffer = (void*)0xa5000000;
240
241 // Functions
242 static void lcd_drawc(cyg_int8 c, int x, int y);
243
244 static inline void
245 set_pixel(int row, int col, unsigned short val)
246 {
247     framebuffer[row*640+col] = val;
248 }
249
250 // Clear screen
251 void
252 lcd_clear(void)
253 {
254     int row, col;
255     int pos;
256
257     for (row = 0;  row < lcd_height;  row++) {
258         for (col = 0;  col < lcd_width;  col++) {
259             set_pixel(row, col, bg);
260         }
261     }
262     for (row = 0;  row < screen_height;  row++) {
263         for (col = 0;  col < screen_width;  col++) {
264             screen[row][col] = ' ';
265         }
266     }
267     // Note: Row 0 seems to wrap incorrectly
268 #ifdef LOGO_AT_TOP
269     pos = 0;
270 #else
271     pos = (LCD_HEIGHT-1);
272 #endif
273     kbd_pos = show_xpm(banner_xpm, pos);
274     curX = 0;  curY = screen_start;
275     if (cursor_enable) {
276         lcd_drawc(CURSOR_ON, curX-screen_pan, curY);
277     }
278 }
279
280
281 // Position cursor
282 void
283 lcd_moveto(int X, int Y)
284 {
285     if (cursor_enable) {
286         lcd_drawc(screen[curY][curX], curX-screen_pan, curY);
287     }
288     if (X < 0) X = 0;
289     if (X >= screen_width) X = screen_width-1;
290     curX = X;
291     if (Y < screen_start) Y = screen_start;
292     if (Y >= screen_height) Y = screen_height-1;
293     curY = Y;
294     if (cursor_enable) {
295         lcd_drawc(CURSOR_ON, curX-screen_pan, curY);
296     }
297 }
298
299 // Render a character at position (X,Y) with current background/foreground
300 static void
301 lcd_drawc(cyg_int8 c, int x, int y)
302 {
303     cyg_uint8 bits;
304     int l, p;
305
306     if ((x < 0) || (x >= VISIBLE_SCREEN_WIDTH) || 
307         (y < 0) || (y >= screen_height)) return;  
308     for (l = 0;  l < FONT_HEIGHT;  l++) {
309         bits = font_table[c-FIRST_CHAR][l]; 
310         for (p = 0;  p < FONT_WIDTH;  p++) {
311             if (bits & 0x01) {
312                 set_pixel(y*FONT_HEIGHT+l, x*FONT_WIDTH + p, fg);
313             } else {
314                 set_pixel(y*FONT_HEIGHT+l, x*FONT_WIDTH + p, bg);
315             }
316             bits >>= 1;
317         }
318     }
319 }
320
321 static void
322 lcd_refresh(void)
323 {
324     int row, col;
325     cyg_uint16 *p1, *p2;
326     // Now the physical screen
327     for (row = FONT_HEIGHT*(screen_start+1);  row < LCD_HEIGHT;  row++) {
328         p1 = &framebuffer[(row-FONT_HEIGHT)*LCD_WIDTH+0];
329         p2 = &framebuffer[row*LCD_WIDTH+0];
330         for (col = 0;  col < LCD_WIDTH;  col++) {
331             *p1++ = *p2++;
332         }
333     }
334     for (row = LCD_HEIGHT-FONT_HEIGHT;  row < LCD_HEIGHT;  row++) {
335         p1 = &framebuffer[row*LCD_WIDTH+0];
336         for (col = 0;  col < LCD_WIDTH;  col++) {
337             *p1++ = bg;
338         }
339     }
340     if (cursor_enable) {
341         lcd_drawc(CURSOR_ON, curX-screen_pan, curY);
342     }
343 }
344
345 static void
346 lcd_scroll(void)
347 {
348     int row, col;
349     cyg_uint8 *c1, *c2;
350
351     // First scroll up the virtual screen
352     for (row = (screen_start+1);  row < screen_height;  row++) {
353         c1 = &screen[row-1][0];
354         c2 = &screen[row][0];
355         for (col = 0;  col < screen_width;  col++) {
356             *c1++ = *c2++;
357         }
358     } 
359     c1 = &screen[screen_height-1][0];
360     for (col = 0;  col < screen_width;  col++) {
361         *c1++ = 0x20;
362     }
363     lcd_refresh();
364 }
365
366 // Draw one character at the current position
367 void
368 lcd_putc(cyg_int8 c)
369 {
370     if (cursor_enable) {
371         lcd_drawc(screen[curY][curX], curX-screen_pan, curY);
372     }
373     switch (c) {
374     case '\r':
375         curX = 0;
376         break;
377     case '\n':
378         curY++;
379         break;
380     case '\b':
381         curX--;
382         if (curX < 0) {
383             curY--;
384             if (curY < 0) curY = 0;
385             curX = screen_width-1;
386         }
387         break;
388     default:
389         if (((cyg_uint8)c < FIRST_CHAR) || ((cyg_uint8)c > LAST_CHAR)) c = '.';
390         screen[curY][curX] = c;
391         lcd_drawc(c, curX-screen_pan, curY);
392         curX++;
393         if (curX == screen_width) {
394             curY++;
395             curX = 0;
396         }
397     } 
398     if (curY >= screen_height) {
399         lcd_scroll();
400         curY = (screen_height-1);
401     }
402     if (cursor_enable) {
403         lcd_drawc(CURSOR_ON, curX-screen_pan, curY);
404     }
405 }
406
407 void
408 lcd_setbg(int red, int green, int blue)
409 {
410     bg = RGB_RED(red) | RGB_GREEN(green) | RGB_BLUE(blue);
411 }
412
413 void
414 lcd_setfg(int red, int green, int blue)
415 {
416     fg = RGB_RED(red) | RGB_GREEN(green) | RGB_BLUE(blue);
417 }
418
419
420 static int  _timeout = 500;
421
422
423 static int
424 _hexdigit(char c)
425 {
426     if ((c >= '0') && (c <= '9')) {
427         return c - '0';
428     } else
429     if ((c >= 'A') && (c <= 'F')) {
430         return (c - 'A') + 0x0A;
431     } else
432     if ((c >= 'a') && (c <= 'f')) {
433         return (c - 'a') + 0x0a;
434     }
435 }
436
437 static int
438 _hex(char *cp)
439 {
440     return (_hexdigit(*cp)<<4) | _hexdigit(*(cp+1));
441 }
442
443 static unsigned short
444 parse_color(char *cp)
445 {
446     int red, green, blue;
447
448     while (*cp && (*cp != 'c')) cp++;
449     if (cp) {
450         cp += 2;
451         if (*cp == '#') {
452             red = _hex(cp+1);
453             green = _hex(cp+3);
454             blue = _hex(cp+5);
455 #ifdef USE_RGB565
456             return RGB_RED(red>>3) | RGB_GREEN(green>>2) | RGB_BLUE(blue>>3);
457 #else
458             return RGB_RED(red>>3) | RGB_GREEN(green>>3) | RGB_BLUE(blue>>3);
459 #endif
460         } else {
461             // Should be "None"
462             return 0xFFFF;
463         }
464     } else {
465         return 0xFFFF;
466     }
467 }
468
469 #ifndef CYGINT_ISO_STDIO_FORMATTED_IO
470 static int
471 get_int(char **_cp)
472 {
473     char *cp = *_cp;
474     char c;
475     int val = 0;
476     
477     while ((c = *cp++) && (c != ' ')) {
478         if ((c >= '0') && (c <= '9')) {
479             val = val * 10 + (c - '0');
480         } else {
481             return -1;
482         }
483     }
484     *_cp = cp;
485     return val;
486 }
487 #endif
488
489 int
490 show_xpm(char *xpm[], int screen_pos)
491 {
492     int i, row, col, offset;
493     char *cp;
494     int nrows, ncols, nclrs;
495     unsigned short colors[256];  // Mapped by character index
496
497     cp = xpm[0];
498 #ifdef CYGINT_ISO_STDIO_FORMATTED_IO
499     if (sscanf(cp, "%d %d %d", &ncols, &nrows, &nclrs) != 3) {
500 #else
501     if (((ncols = get_int(&cp)) < 0) ||
502         ((nrows = get_int(&cp)) < 0) ||
503         ((nclrs = get_int(&cp)) < 0)) {
504
505 #endif
506         diag_printf("Can't parse XPM data, sorry\n");
507         return 0;
508     }
509     // printf("%d rows, %d cols, %d colors\n", nrows, ncols, nclrs);
510
511     for (i = 0;  i < 256;  i++) {
512         colors[i] = 0x0000;
513     }
514     for (i = 0;  i < nclrs;  i++) {
515         cp = xpm[i+1];
516         colors[(unsigned int)*cp] = parse_color(&cp[1]);
517         // printf("Color[%c] = %x\n", *cp, colors[(unsigned int)*cp]);
518     }
519
520 #ifdef LOGO_AT_TOP
521     offset = screen_pos;
522 #else
523     offset = screen_pos-nrows;
524 #endif
525     for (row = 0;  row < nrows;  row++) {            
526         cp = xpm[nclrs+1+row];        
527         for (col = 0;  col < ncols;  col++) {
528             set_pixel(row+offset, col, colors[(unsigned int)*cp++]);
529         }
530     }
531 #ifdef LOGO_AT_TOP
532     screen_start = (nrows + (FONT_HEIGHT-1))/FONT_HEIGHT;
533     return offset+nrows;
534 #else    
535     screen_height = offset / FONT_HEIGHT;
536     return offset;
537 #endif
538 }
539
540
541 void fb_init(int depth)
542 {
543     int cable = dcfb_cable_check();
544     unsigned long **parm_list[4] = {
545         dc_parm_vga, dc_parm_vga, dc_parm_interlace, dc_parm_composite,
546     };
547     unsigned long **dc_parms = parm_list[cable];
548
549     unsigned long a, d, *p;
550   
551     switch(depth) {
552     default:
553     case 16:
554         p = dc_parms[0];
555         break;
556     case 32:
557         p = dc_parms[1];
558         break;
559     }
560   
561     HAL_WRITE_UINT32(RESETREG, 0);
562     HAL_WRITE_UINT32(BORDERRGB, 0);
563
564     while(1) {
565         a = *p++; d = *p++;
566         if (!a) break;
567         HAL_WRITE_UINT32(a, d);
568     }
569
570     lcd_clear();
571 }
572
573
574 static cyg_bool
575 lcd_comm_getc_nonblock(void* __ch_data, cyg_uint8* ch)
576 {
577     return false;
578 }
579
580 static cyg_uint8
581 lcd_comm_getc(void* __ch_data)
582 {
583     cyg_uint8 ch;
584
585     while (!lcd_comm_getc_nonblock(__ch_data, &ch)) ;
586     return ch;
587 }
588
589 static void
590 lcd_comm_putc(void* __ch_data, cyg_uint8 c)
591 {
592     lcd_putc(c);
593 }
594
595 static void
596 lcd_comm_write(void* __ch_data, const cyg_uint8* __buf, cyg_uint32 __len)
597 {
598 }
599
600 static void
601 lcd_comm_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
602 {
603 }
604
605 static cyg_bool
606 lcd_comm_getc_timeout(void* __ch_data, cyg_uint8* ch)
607 {
608     int delay_count;
609     cyg_bool res;
610
611     delay_count = _timeout * 10; // delay in .1 ms steps
612     for(;;) {
613         res = lcd_comm_getc_nonblock(__ch_data, ch);
614         if (res || 0 == delay_count--)
615             break;
616         CYGACC_CALL_IF_DELAY_US(100);
617     }
618     return res;
619 }
620
621 static int
622 lcd_comm_control(void *__ch_data, __comm_control_cmd_t __func, ...)
623 {
624     int ret = 0;
625
626     switch (__func) {
627     case __COMMCTL_SET_TIMEOUT:
628     {
629         va_list ap;
630         va_start(ap, __func);
631         ret = _timeout;
632         _timeout = va_arg(ap, cyg_uint32);
633         va_end(ap);
634         break;
635     }
636     case __COMMCTL_FLUSH_OUTPUT:
637         break;
638     default:
639         break;
640     }
641
642     return ret;
643 }
644
645 static int
646 lcd_comm_isr(void *__ch_data, int* __ctrlc, 
647            CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
648 {
649     return 0;
650 }
651
652 void fb_comm_init(void)
653 {
654     static int init = 0;
655   
656     if (!init) {
657         hal_virtual_comm_table_t* comm;
658         int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
659     
660         // Setup procs in the vector table
661         CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
662         comm = CYGACC_CALL_IF_CONSOLE_PROCS();
663         //CYGACC_COMM_IF_CH_DATA_SET(*comm, chan);
664         CYGACC_COMM_IF_WRITE_SET(*comm, lcd_comm_write);
665         CYGACC_COMM_IF_READ_SET(*comm, lcd_comm_read);
666         CYGACC_COMM_IF_PUTC_SET(*comm, lcd_comm_putc);
667         CYGACC_COMM_IF_GETC_SET(*comm, lcd_comm_getc);
668         CYGACC_COMM_IF_CONTROL_SET(*comm, lcd_comm_control);
669         CYGACC_COMM_IF_DBG_ISR_SET(*comm, lcd_comm_isr);
670         CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, lcd_comm_getc_timeout);
671     
672         // Restore original console
673         CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
674         
675         init = 1;
676     }
677 }
678
679 //-----------------------------------------------------------------------------
680 // End of fb_support.c