]> git.sur5r.net Git - u-boot/blob - cpu/mpc8xx/lcd.c
Initial revision
[u-boot] / cpu / mpc8xx / lcd.c
1 /*
2  * (C) Copyright 2001-2002
3  * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /************************************************************************/
25 /* ** HEADER FILES                                                      */
26 /************************************************************************/
27
28 #include <config.h>
29 #include <common.h>
30 #include <version.h>
31 #include <stdarg.h>
32 #include <lcdvideo.h>
33 #include <linux/types.h>
34 #include <devices.h>
35
36
37 #ifdef CONFIG_LCD
38
39 /************************************************************************/
40 /* ** CONFIG STUFF -- should be moved to board config file              */
41 /************************************************************************/
42 #ifndef CONFIG_EDT32F10
43 #define CONFIG_LCD_LOGO
44 #define LCD_INFO                /* Display Logo, (C) and system info    */
45 #endif
46 /* #define LCD_TEST_PATTERN */  /* color backgnd for frame/color adjust */
47 /* #define CFG_INVERT_COLORS */ /* Not needed - adjust vl_dp instead    */
48 /************************************************************************/
49
50 /************************************************************************/
51 /* ** FONT AND LOGO DATA                                                */
52 /************************************************************************/
53
54 #include <video_font.h>         /* Get font data, width and height      */
55
56 #ifdef CONFIG_LCD_LOGO
57 # include <bmp_logo.h>          /* Get logo data, width and height      */
58 #endif
59
60 /************************************************************************/
61 /************************************************************************/
62
63 /*
64  *  Information about displays we are using.  This is for configuring
65  *  the LCD controller and memory allocation.  Someone has to know what
66  *  is connected, as we can't autodetect anything.
67  */
68 #define CFG_HIGH        0       /* Pins are active high */
69 #define CFG_LOW         1       /* Pins are active low */
70
71 typedef struct vidinfo {
72     ushort      vl_col;         /* Number of columns (i.e. 640) */
73     ushort      vl_row;         /* Number of rows (i.e. 480) */
74     ushort      vl_width;       /* Width of display area in millimeters */
75     ushort      vl_height;      /* Height of display area in millimeters */
76
77     /* LCD configuration register.
78     */
79     u_char      vl_clkp;        /* Clock polarity */
80     u_char      vl_oep;         /* Output Enable polarity */
81     u_char      vl_hsp;         /* Horizontal Sync polarity */
82     u_char      vl_vsp;         /* Vertical Sync polarity */
83     u_char      vl_dp;          /* Data polarity */
84     u_char      vl_bpix;        /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8 */
85     u_char      vl_lbw;         /* LCD Bus width, 0 = 4, 1 = 8 */
86     u_char      vl_splt;        /* Split display, 0 = single-scan, 1 = dual-scan */
87     u_char      vl_clor;        /* Color, 0 = mono, 1 = color */
88     u_char      vl_tft;         /* 0 = passive, 1 = TFT */
89
90     /* Horizontal control register.  Timing from data sheet.
91     */
92     ushort      vl_wbl;         /* Wait between lines */
93
94     /* Vertical control register.
95     */
96     u_char      vl_vpw;         /* Vertical sync pulse width */
97     u_char      vl_lcdac;       /* LCD AC timing */
98     u_char      vl_wbf;         /* Wait between frames */
99 } vidinfo_t;
100
101 #define LCD_MONOCHROME  0
102 #define LCD_COLOR2      1
103 #define LCD_COLOR4      2
104 #define LCD_COLOR8      3
105
106 /*----------------------------------------------------------------------*/
107 #ifdef CONFIG_KYOCERA_KCS057QV1AJ
108 /*
109  *  Kyocera KCS057QV1AJ-G23. Passive, color, single scan.
110  */
111 #define LCD_BPP LCD_COLOR4
112
113 static vidinfo_t panel_info = {
114     640, 480, 132, 99, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH,
115     LCD_BPP, 1, 0, 1, 0,  5, 0, 0, 0
116                 /* wbl, vpw, lcdac, wbf */
117 };
118 #endif /* CONFIG_KYOCERA_KCS057QV1AJ */
119 /*----------------------------------------------------------------------*/
120
121 /*----------------------------------------------------------------------*/
122 #ifdef CONFIG_NEC_NL6648AC33
123 /*
124  *  NEC NL6648AC33-18. Active, color, single scan.
125  */
126 static vidinfo_t panel_info = {
127     640, 480, 132, 99, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_HIGH,
128     3, 0, 0, 1, 1, 144, 2, 0, 33
129                 /* wbl, vpw, lcdac, wbf */
130 };
131 #endif /* CONFIG_NEC_NL6648AC33 */
132 /*----------------------------------------------------------------------*/
133
134 #ifdef CONFIG_NEC_NL6648BC20
135 /*
136  *  NEC NL6648BC20-08. 6.5", 640x480. Active, color, single scan.
137  */
138 static vidinfo_t panel_info = {
139     640, 480, 132, 99, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_HIGH,
140     3, 0, 0, 1, 1, 144, 2, 0, 33
141                 /* wbl, vpw, lcdac, wbf */
142 };
143 #endif /* CONFIG_NEC_NL6648BC20 */
144 /*----------------------------------------------------------------------*/
145
146 #ifdef CONFIG_SHARP_LQ104V7DS01
147 /*
148  *  SHARP LQ104V7DS01. 6.5", 640x480. Active, color, single scan.
149  */
150 static vidinfo_t panel_info = {
151     640, 480, 132, 99, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_LOW,
152     3, 0, 0, 1, 1, 25, 1, 0, 33
153                 /* wbl, vpw, lcdac, wbf */
154 };
155 #endif /* CONFIG_SHARP_LQ104V7DS01 */
156 /*----------------------------------------------------------------------*/
157
158 #ifdef CONFIG_SHARP_16x9
159 /*
160  * Sharp 320x240. Active, color, single scan.  It isn't 16x9, and I am
161  * not sure what it is.......
162  */
163 static vidinfo_t panel_info = {
164     320, 240, 0, 0, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH,
165     3, 0, 0, 1, 1, 15, 4, 0, 3
166 };
167 #endif /* CONFIG_SHARP_16x9 */
168 /*----------------------------------------------------------------------*/
169
170 #ifdef CONFIG_SHARP_LQ057Q3DC02
171 /*
172  * Sharp LQ057Q3DC02 display. Active, color, single scan.
173  */
174 static vidinfo_t panel_info = {
175     320, 240, 0, 0, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_HIGH,
176     3, 0, 0, 1, 1, 15, 4, 0, 3
177                 /* wbl, vpw, lcdac, wbf */
178 };
179 #define LCD_INFO_BELOW_LOGO
180 #endif /* CONFIG_SHARP_LQ057Q3DC02 */
181 /*----------------------------------------------------------------------*/
182
183 #ifdef CONFIG_SHARP_LQ64D341
184 /*
185  * Sharp LQ64D341 display, 640x480. Active, color, single scan.
186  */
187 static vidinfo_t panel_info = {
188     640, 480, 0, 0, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_HIGH,
189     3, 0, 0, 1, 1, 128, 16, 0, 32
190                 /* wbl, vpw, lcdac, wbf */
191 };
192 #endif /* CONFIG_SHARP_LQ64D341 */
193 /*----------------------------------------------------------------------*/
194
195 #ifdef CONFIG_HLD1045
196 /*
197  * HLD1045 display, 640x480. Active, color, single scan.
198  */
199 static vidinfo_t panel_info = {
200     640, 480, 0, 0, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_HIGH,
201     3, 0, 0, 1, 1, 160, 3, 0, 48
202                 /* wbl, vpw, lcdac, wbf */
203 };
204 #endif /* CONFIG_HLD1045 */
205 /*----------------------------------------------------------------------*/
206
207 #ifdef CONFIG_PRIMEVIEW_V16C6448AC
208 /*
209  * Prime View V16C6448AC
210  */
211 static vidinfo_t panel_info = {
212     640, 480, 130, 98, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_HIGH,
213     3, 0, 0, 1, 1, 144, 2, 0, 35
214                 /* wbl, vpw, lcdac, wbf */
215 };
216 #endif /* CONFIG_PRIMEVIEW_V16C6448AC */
217
218 /*----------------------------------------------------------------------*/
219
220 #ifdef CONFIG_OPTREX_BW
221 /*
222  * Optrex   CBL50840-2 NF-FW 99 22 M5
223  * or
224  * Hitachi  LMG6912RPFC-00T
225  * or
226  * Hitachi  SP14Q002
227  *
228  * 320x240. Black & white.
229  */
230 #define OPTREX_BPP      0       /* 0 - monochrome,     1 bpp */
231                                 /* 1 -  4 grey levels, 2 bpp */
232                                 /* 2 - 16 grey levels, 4 bpp */
233 static vidinfo_t panel_info = {
234     320, 240, 0, 0, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_LOW,
235     OPTREX_BPP, 0, 0, 0, 0, 0, 0, 0, 0, 4
236 };
237 #endif /* CONFIG_OPTREX_BW */
238
239 /*-----------------------------------------------------------------*/
240 #ifdef CONFIG_EDT32F10
241 /*
242  * Emerging Display Technologies 320x240. Passive, monochrome, single scan.
243  */
244 #define LCD_BPP         LCD_MONOCHROME
245 #define LCD_DF          20
246
247 static vidinfo_t panel_info = {
248     320, 240, 0, 0, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_LOW,
249     LCD_BPP,  0, 0, 0, 0, 0, 15, 0, 0
250 };
251 #endif
252 /*----------------------------------------------------------------------*/
253
254 #if defined(LCD_INFO_BELOW_LOGO)
255 # define LCD_INFO_X             0
256 # define LCD_INFO_Y             (BMP_LOGO_HEIGHT + VIDEO_FONT_HEIGHT)
257 #elif defined(CONFIG_LCD_LOGO)
258 # define LCD_INFO_X             (BMP_LOGO_WIDTH + 4 * VIDEO_FONT_WIDTH)
259 # define LCD_INFO_Y             (VIDEO_FONT_HEIGHT)
260 #else
261 # define LCD_INFO_X             (VIDEO_FONT_WIDTH)
262 # define LCD_INFO_Y             (VIDEO_FONT_HEIGHT)
263 #endif
264
265 #ifndef LCD_BPP
266 #define LCD_BPP                 LCD_COLOR8
267 #endif
268 #ifndef LCD_DF
269 #define LCD_DF                  1
270 #endif
271
272 #define NBITS(bit_code)         (1 << (bit_code))
273 #define NCOLORS(bit_code)       (1 << NBITS(bit_code))
274
275 static int lcd_line_length;
276
277 static int lcd_color_fg;
278 static int lcd_color_bg;
279
280 static char lcd_is_enabled = 0;         /* Indicate that LCD is enabled */
281
282 /*
283  * Frame buffer memory information
284  */
285 static void *lcd_base;                  /* Start of framebuffer memory  */
286 static void *lcd_console_address;       /* Start of console buffer      */
287
288
289 /************************************************************************/
290 /* ** CONSOLE CONSTANTS                                                 */
291 /************************************************************************/
292
293 #if LCD_BPP == LCD_MONOCHROME
294
295 /*
296  * Simple color definitions
297  */
298 #define CONSOLE_COLOR_BLACK      0
299 #define CONSOLE_COLOR_WHITE      1      /* Must remain last / highest */
300
301 #else
302
303 /*
304  * Simple color definitions
305  */
306 #define CONSOLE_COLOR_BLACK      0
307 #define CONSOLE_COLOR_RED        1
308 #define CONSOLE_COLOR_GREEN      2
309 #define CONSOLE_COLOR_YELLOW     3
310 #define CONSOLE_COLOR_BLUE       4
311 #define CONSOLE_COLOR_MAGENTA    5
312 #define CONSOLE_COLOR_CYAN       6
313 #define CONSOLE_COLOR_GREY      14
314 #define CONSOLE_COLOR_WHITE     15      /* Must remain last / highest */
315
316 #endif
317
318 #if defined(CONFIG_LCD_LOGO) && (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET)
319 #error Default Color Map overlaps with Logo Color Map
320 #endif
321
322 /************************************************************************/
323
324 #ifndef PAGE_SIZE
325 #define PAGE_SIZE       4096
326 #endif
327
328
329 /************************************************************************/
330 /* ** CONSOLE DEFINITIONS & FUNCTIONS                                   */
331 /************************************************************************/
332
333 #if defined(CONFIG_LCD_LOGO) && !defined(LCD_INFO_BELOW_LOGO)
334 #define CONSOLE_ROWS            ((panel_info.vl_row-BMP_LOGO_HEIGHT) \
335                                         / VIDEO_FONT_HEIGHT)
336 #else
337 #define CONSOLE_ROWS            (panel_info.vl_row / VIDEO_FONT_HEIGHT)
338 #endif
339 #define CONSOLE_COLS            (panel_info.vl_col / VIDEO_FONT_WIDTH)
340 #define CONSOLE_ROW_SIZE        (VIDEO_FONT_HEIGHT * lcd_line_length)
341 #define CONSOLE_ROW_FIRST       (lcd_console_address)
342 #define CONSOLE_ROW_SECOND      (lcd_console_address + CONSOLE_ROW_SIZE)
343 #define CONSOLE_ROW_LAST        (lcd_console_address + CONSOLE_SIZE \
344                                         - CONSOLE_ROW_SIZE)
345 #define CONSOLE_SIZE            (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
346 #define CONSOLE_SCROLL_SIZE     (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
347
348 #if  LCD_BPP == LCD_MONOCHROME
349 #define COLOR_MASK(c)           ((c)      | (c) << 1 | (c) << 2 | (c) << 3 | \
350                                  (c) << 4 | (c) << 5 | (c) << 6 | (c) << 7)
351 #elif LCD_BPP == LCD_COLOR8
352 #define COLOR_MASK(c)           (c)
353 #else
354 #error Unsupported LCD BPP.
355 #endif
356
357 static short console_col;
358 static short console_row;
359
360 /************************************************************************/
361
362 ulong   lcd_setmem (ulong addr);
363
364 static void     lcd_drawchars  (ushort x, ushort y, uchar *str, int count);
365 static inline void lcd_puts_xy (ushort x, ushort y, uchar *s);
366 static inline void lcd_putc_xy (ushort x, ushort y, uchar  c);
367
368 static int      lcd_init (void *lcdbase);
369 static void     lcd_ctrl_init (void *lcdbase);
370 static void     lcd_enable (void);
371 static void    *lcd_logo (void);
372 #if LCD_BPP == LCD_COLOR8
373 static void     lcd_setcolreg (ushort regno,
374                                 ushort red, ushort green, ushort blue);
375 #endif
376 #if LCD_BPP == LCD_MONOCHROME
377 static void     lcd_initcolregs (void);
378 #endif
379 static int      lcd_getbgcolor (void);
380 static void     lcd_setfgcolor (int color);
381 static void     lcd_setbgcolor (int color);
382
383 #ifdef  NOT_USED_SO_FAR
384 static void     lcd_disable (void);
385 static void     lcd_getcolreg (ushort regno,
386                                 ushort *red, ushort *green, ushort *blue);
387 static int      lcd_getfgcolor (void);
388 #endif  /* NOT_USED_SO_FAR */
389
390 /************************************************************************/
391
392 /*----------------------------------------------------------------------*/
393
394 static void console_scrollup (void)
395 {
396 #if 1
397         /* Copy up rows ignoring the first one */
398         memcpy (CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, CONSOLE_SCROLL_SIZE);
399
400         /* Clear the last one */
401         memset (CONSOLE_ROW_LAST, COLOR_MASK(lcd_color_bg), CONSOLE_ROW_SIZE);
402 #else
403         /*
404          * Poor attempt to optimize speed by moving "long"s.
405          * But the code is ugly, and not a bit faster :-(
406          */
407         ulong *t = (ulong *)CONSOLE_ROW_FIRST;
408         ulong *s = (ulong *)CONSOLE_ROW_SECOND;
409         ulong    l = CONSOLE_SCROLL_SIZE / sizeof(ulong);
410         uchar  c = lcd_color_bg & 0xFF;
411         ulong val= (c<<24) | (c<<16) | (c<<8) | c;
412
413         while (l--)
414                 *t++ = *s++;
415
416         t = (ulong *)CONSOLE_ROW_LAST;
417         l = CONSOLE_ROW_SIZE / sizeof(ulong);
418
419         while (l-- > 0)
420                 *t++ = val;
421 #endif
422 }
423
424 /*----------------------------------------------------------------------*/
425
426 static inline void console_back (void)
427 {
428         if (--console_col < 0) {
429                 console_col = CONSOLE_COLS-1 ;
430                 if (--console_row < 0) {
431                         console_row = 0;
432                 }
433         }
434
435         lcd_putc_xy (console_col * VIDEO_FONT_WIDTH,
436                      console_row * VIDEO_FONT_HEIGHT,
437                      ' ');
438 }
439
440 /*----------------------------------------------------------------------*/
441
442 static inline void console_newline (void)
443 {
444         ++console_row;
445         console_col = 0;
446
447         /* Check if we need to scroll the terminal */
448         if (console_row >= CONSOLE_ROWS) {
449                 /* Scroll everything up */
450                 console_scrollup () ;
451                 --console_row;
452         }
453 }
454
455 /*----------------------------------------------------------------------*/
456
457 void lcd_putc (const char c)
458 {
459         if (!lcd_is_enabled) {
460                 serial_putc(c);
461                 return;
462         }
463
464         switch (c) {
465         case '\r':      console_col = 0;
466                         return;
467
468         case '\n':      console_newline();
469                         return;
470
471         case '\t':      /* Tab (8 chars alignment) */
472                         console_col |=  8;
473                         console_col &= ~7;
474
475                         if (console_col >= CONSOLE_COLS) {
476                                 console_newline();
477                         }
478                         return;
479
480         case '\b':      console_back();
481                         return;
482
483         default:        lcd_putc_xy (console_col * VIDEO_FONT_WIDTH,
484                                      console_row * VIDEO_FONT_HEIGHT,
485                                      c);
486                         if (++console_col >= CONSOLE_COLS) {
487                                 console_newline();
488                         }
489                         return;
490         }
491         /* NOTREACHED */
492 }
493
494 /*----------------------------------------------------------------------*/
495
496 void lcd_puts (const char *s)
497 {
498         if (!lcd_is_enabled) {
499                 serial_puts (s);
500                 return;
501         }
502
503         while (*s) {
504                 lcd_putc (*s++);
505         }
506 }
507
508 /************************************************************************/
509 /* ** Low-Level Graphics Routines                                       */
510 /************************************************************************/
511
512 static void lcd_drawchars (ushort x, ushort y, uchar *str, int count)
513 {
514         uchar *dest;
515         ushort off, row;
516
517         dest = (uchar *)(lcd_base + y * lcd_line_length + x * (1 << LCD_BPP) / 8);
518         off  = x * (1 << LCD_BPP) % 8;
519
520         for (row=0;  row < VIDEO_FONT_HEIGHT;  ++row, dest += lcd_line_length)  {
521                 uchar *s = str;
522                 uchar *d = dest;
523                 int i;
524
525 #if LCD_BPP == LCD_MONOCHROME
526                 uchar rest = *d & -(1 << (8-off));
527                 uchar sym;
528 #endif
529                 for (i=0; i<count; ++i) {
530                         uchar c, bits;
531
532                         c = *s++;
533                         bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
534
535 #if LCD_BPP == LCD_MONOCHROME
536                         sym  = (COLOR_MASK(lcd_color_fg) & bits) |
537                                (COLOR_MASK(lcd_color_bg) & ~bits);
538
539                         *d++ = rest | (sym >> off);
540                         rest = sym << (8-off);
541 #elif LCD_BPP == LCD_COLOR8
542                         for (c=0; c<8; ++c) {
543                                 *d++ = (bits & 0x80) ?
544                                                 lcd_color_fg : lcd_color_bg;
545                                 bits <<= 1;
546                         }
547 #endif
548                 }
549
550 #if LCD_BPP == LCD_MONOCHROME
551                 *d  = rest | (*d & ((1 << (8-off)) - 1));
552 #endif
553         }
554 }
555
556 /*----------------------------------------------------------------------*/
557
558 static inline void lcd_puts_xy (ushort x, ushort y, uchar *s)
559 {
560 #if defined(CONFIG_LCD_LOGO) && !defined(LCD_INFO_BELOW_LOGO)
561         lcd_drawchars (x, y+BMP_LOGO_HEIGHT, s, strlen (s));
562 #else
563         lcd_drawchars (x, y, s, strlen (s));
564 #endif
565 }
566
567 /*----------------------------------------------------------------------*/
568
569 static inline void lcd_putc_xy (ushort x, ushort y, uchar c)
570 {
571 #if defined(CONFIG_LCD_LOGO) && !defined(LCD_INFO_BELOW_LOGO)
572         lcd_drawchars (x, y+BMP_LOGO_HEIGHT, &c, 1);
573 #else
574         lcd_drawchars (x, y, &c, 1);
575 #endif
576 }
577
578 /************************************************************************/
579 /**  Small utility to check that you got the colours right              */
580 /************************************************************************/
581 #ifdef LCD_TEST_PATTERN
582
583 #define N_BLK_VERT      2
584 #define N_BLK_HOR       3
585
586 static int test_colors[N_BLK_HOR*N_BLK_VERT] = {
587         CONSOLE_COLOR_RED,      CONSOLE_COLOR_GREEN,    CONSOLE_COLOR_YELLOW,
588         CONSOLE_COLOR_BLUE,     CONSOLE_COLOR_MAGENTA,  CONSOLE_COLOR_CYAN,
589 };
590
591 static void test_pattern (void)
592 {
593         ushort v_max  = panel_info.vl_row;
594         ushort h_max  = panel_info.vl_col;
595         ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
596         ushort h_step = (h_max + N_BLK_HOR  - 1) / N_BLK_HOR;
597         ushort v, h;
598         uchar *pix = (uchar *)lcd_base;
599
600         printf ("[LCD] Test Pattern: %d x %d [%d x %d]\n",
601                 h_max, v_max, h_step, v_step);
602
603         /* WARNING: Code silently assumes 8bit/pixel */
604         for (v=0; v<v_max; ++v) {
605                 uchar iy = v / v_step;
606                 for (h=0; h<h_max; ++h) {
607                         uchar ix = N_BLK_HOR * iy + (h/h_step);
608                         *pix++ = test_colors[ix];
609                 }
610         }
611 }
612 #endif /* LCD_TEST_PATTERN */
613
614
615 /************************************************************************/
616 /* ** GENERIC Initialization Routines                                   */
617 /************************************************************************/
618
619 int drv_lcd_init (void)
620 {
621         DECLARE_GLOBAL_DATA_PTR;
622
623         device_t lcddev;
624         int rc;
625
626         lcd_base = (void *)(gd->fb_base);
627
628         lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
629
630         lcd_init (lcd_base);            /* LCD initialization */
631
632         /* Device initialization */
633         memset (&lcddev, 0, sizeof (lcddev));
634
635         strcpy (lcddev.name, "lcd");
636         lcddev.ext   = 0;                       /* No extensions */
637         lcddev.flags = DEV_FLAGS_OUTPUT;        /* Output only */
638         lcddev.putc  = lcd_putc;                /* 'putc' function */
639         lcddev.puts  = lcd_puts;                /* 'puts' function */
640
641         rc = device_register (&lcddev);
642
643         return (rc == 0) ? 1 : rc;
644 }
645
646 /*----------------------------------------------------------------------*/
647
648 static int lcd_init (void *lcdbase)
649 {
650         /* Initialize the lcd controller */
651         debug ("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
652
653         lcd_ctrl_init (lcdbase);
654
655 #if LCD_BPP == LCD_MONOCHROME
656         /* Setting the palette */
657         lcd_initcolregs();
658
659 #elif LCD_BPP == LCD_COLOR8
660         /* Setting the palette */
661         lcd_setcolreg  (CONSOLE_COLOR_BLACK,       0,    0,    0);
662         lcd_setcolreg  (CONSOLE_COLOR_RED,      0xFF,    0,    0);
663         lcd_setcolreg  (CONSOLE_COLOR_GREEN,       0, 0xFF,    0);
664         lcd_setcolreg  (CONSOLE_COLOR_YELLOW,   0xFF, 0xFF,    0);
665         lcd_setcolreg  (CONSOLE_COLOR_BLUE,        0,    0, 0xFF);
666         lcd_setcolreg  (CONSOLE_COLOR_MAGENTA,  0xFF,    0, 0xFF);
667         lcd_setcolreg  (CONSOLE_COLOR_CYAN,        0, 0xFF, 0xFF);
668         lcd_setcolreg  (CONSOLE_COLOR_GREY,     0xAA, 0xAA, 0xAA);
669         lcd_setcolreg  (CONSOLE_COLOR_WHITE,    0xFF, 0xFF, 0xFF);
670 #endif
671
672 #ifndef CFG_WHITE_ON_BLACK
673         lcd_setfgcolor (CONSOLE_COLOR_BLACK);
674         lcd_setbgcolor (CONSOLE_COLOR_WHITE);
675 #else
676         lcd_setfgcolor (CONSOLE_COLOR_WHITE);
677         lcd_setbgcolor (CONSOLE_COLOR_BLACK);
678 #endif  /* CFG_WHITE_ON_BLACK */
679
680 #ifdef  LCD_TEST_PATTERN
681         test_pattern();
682 #else
683         /* set framebuffer to background color */
684         memset ((char *)lcd_base,
685                 COLOR_MASK(lcd_getbgcolor()),
686                 lcd_line_length*panel_info.vl_row);
687 #endif
688
689         lcd_enable ();
690
691         /* Paint the logo and retrieve LCD base address */
692         debug ("[LCD] Drawing the logo...\n");
693         lcd_console_address = lcd_logo ();
694
695         /* Initialize the console */
696         console_col = 0;
697 #ifdef LCD_INFO_BELOW_LOGO
698         console_row = 7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT;
699 #else
700         console_row = 1;        /* leave 1 blank line below logo */
701 #endif
702         lcd_is_enabled = 1;
703
704         return 0;
705 }
706
707
708 /************************************************************************/
709 /* ** ROM capable initialization part - needed to reserve FB memory     */
710 /************************************************************************/
711
712 /*
713  * This is called early in the system initialization to grab memory
714  * for the LCD controller.
715  * Returns new address for monitor, after reserving LCD buffer memory
716  *
717  * Note that this is running from ROM, so no write access to global data.
718  */
719 ulong lcd_setmem (ulong addr)
720 {
721         ulong size;
722         int line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
723
724         debug ("LCD panel info: %d x %d, %d bit/pix\n",
725                 panel_info.vl_col, panel_info.vl_row, NBITS (panel_info.vl_bpix) );
726
727         size = line_length * panel_info.vl_row;
728
729         /* Round up to nearest full page */
730         size = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
731
732         /* Allocate pages for the frame buffer. */
733         addr -= size;
734
735         debug ("Reserving %ldk for LCD Framebuffer at: %08lx\n", size>>10, addr);
736
737         return (addr);
738 }
739
740
741 /************************************************************************/
742 /* ----------------- chipset specific functions ----------------------- */
743 /************************************************************************/
744
745 static void lcd_ctrl_init (void *lcdbase)
746 {
747         volatile immap_t *immr = (immap_t *) CFG_IMMR;
748         volatile lcd823_t *lcdp = &immr->im_lcd;
749
750         uint lccrtmp;
751
752         /* Initialize the LCD control register according to the LCD
753          * parameters defined.  We do everything here but enable
754          * the controller.
755          */
756
757         lccrtmp  = LCDBIT (LCCR_BNUM_BIT,
758                    (((panel_info.vl_row * panel_info.vl_col) * (1 << LCD_BPP)) / 128));
759
760         lccrtmp |= LCDBIT (LCCR_CLKP_BIT, panel_info.vl_clkp)   |
761                    LCDBIT (LCCR_OEP_BIT,  panel_info.vl_oep)    |
762                    LCDBIT (LCCR_HSP_BIT,  panel_info.vl_hsp)    |
763                    LCDBIT (LCCR_VSP_BIT,  panel_info.vl_vsp)    |
764                    LCDBIT (LCCR_DP_BIT,   panel_info.vl_dp)     |
765                    LCDBIT (LCCR_BPIX_BIT, panel_info.vl_bpix)   |
766                    LCDBIT (LCCR_LBW_BIT,  panel_info.vl_lbw)    |
767                    LCDBIT (LCCR_SPLT_BIT, panel_info.vl_splt)   |
768                    LCDBIT (LCCR_CLOR_BIT, panel_info.vl_clor)   |
769                    LCDBIT (LCCR_TFT_BIT,  panel_info.vl_tft);
770
771 #if 0
772         lccrtmp |= ((SIU_LEVEL5 / 2) << 12);
773         lccrtmp |= LCCR_EIEN;
774 #endif
775
776         lcdp->lcd_lccr = lccrtmp;
777         lcdp->lcd_lcsr = 0xFF;          /* Clear pending interrupts */
778
779         /* Initialize LCD controller bus priorities.
780          */
781         immr->im_siu_conf.sc_sdcr &= ~0x0f;     /* RAID = LAID = 0 */
782
783         /* set SHFT/CLOCK division factor 4
784          * This needs to be set based upon display type and processor
785          * speed.  The TFT displays run about 20 to 30 MHz.
786          * I was running 64 MHz processor speed.
787          * The value for this divider must be chosen so the result is
788          * an integer of the processor speed (i.e., divide by 3 with
789          * 64 MHz would be bad).
790          */
791         immr->im_clkrst.car_sccr &= ~0x1F;
792         immr->im_clkrst.car_sccr |= LCD_DF;     /* was 8 */
793
794 #ifndef CONFIG_EDT32F10
795         /* Enable LCD on port D.
796          */
797         immr->im_ioport.iop_pdpar |= 0x1FFF;
798         immr->im_ioport.iop_pddir |= 0x1FFF;
799
800         /* Enable LCD_A/B/C on port B.
801          */
802         immr->im_cpm.cp_pbpar |= 0x00005001;
803         immr->im_cpm.cp_pbdir |= 0x00005001;
804 #else
805         /* Enable LCD on port D.
806          */
807         immr->im_ioport.iop_pdpar |= 0x1DFF;
808         immr->im_ioport.iop_pdpar &= ~0x0200;
809         immr->im_ioport.iop_pddir |= 0x1FFF;
810         immr->im_ioport.iop_pddat |= 0x0200;
811 #endif
812
813         /* Load the physical address of the linear frame buffer
814          * into the LCD controller.
815          * BIG NOTE:  This has to be modified to load A and B depending
816          * upon the split mode of the LCD.
817          */
818         lcdp->lcd_lcfaa = (ulong)lcd_base;
819         lcdp->lcd_lcfba = (ulong)lcd_base;
820
821         /* MORE HACKS...This must be updated according to 823 manual
822          * for different panels.
823          */
824 #ifndef CONFIG_EDT32F10
825         lcdp->lcd_lchcr = LCHCR_BO |
826                           LCDBIT (LCHCR_AT_BIT, 4) |
827                           LCDBIT (LCHCR_HPC_BIT, panel_info.vl_col) |
828                           panel_info.vl_wbl;
829 #else
830         lcdp->lcd_lchcr = LCHCR_BO |
831                           LCDBIT (LCHCR_AT_BIT, 4) |
832                           LCDBIT (LCHCR_HPC_BIT, panel_info.vl_col/4) |
833                           panel_info.vl_wbl;
834 #endif
835
836         lcdp->lcd_lcvcr = LCDBIT (LCVCR_VPW_BIT, panel_info.vl_vpw) |
837                           LCDBIT (LCVCR_LCD_AC_BIT, panel_info.vl_lcdac) |
838                           LCDBIT (LCVCR_VPC_BIT, panel_info.vl_row) |
839                           panel_info.vl_wbf;
840
841 }
842
843 /*----------------------------------------------------------------------*/
844
845 #ifdef  NOT_USED_SO_FAR
846 static void
847 lcd_getcolreg (ushort regno, ushort *red, ushort *green, ushort *blue)
848 {
849         volatile immap_t *immr = (immap_t *) CFG_IMMR;
850         volatile cpm8xx_t *cp = &(immr->im_cpm);
851         unsigned short colreg, *cmap_ptr;
852
853         cmap_ptr = (unsigned short *)&cp->lcd_cmap[regno * 2];
854
855         colreg = *cmap_ptr;
856 #ifdef  CFG_INVERT_COLORS
857         colreg ^= 0x0FFF;
858 #endif
859
860         *red   = (colreg >> 8) & 0x0F;
861         *green = (colreg >> 4) & 0x0F;
862         *blue  =  colreg       & 0x0F;
863 }
864 #endif  /* NOT_USED_SO_FAR */
865
866 /*----------------------------------------------------------------------*/
867
868 #if LCD_BPP == LCD_COLOR8
869 static void
870 lcd_setcolreg (ushort regno, ushort red, ushort green, ushort blue)
871 {
872         volatile immap_t *immr = (immap_t *) CFG_IMMR;
873         volatile cpm8xx_t *cp = &(immr->im_cpm);
874         unsigned short colreg, *cmap_ptr;
875
876         cmap_ptr = (unsigned short *)&cp->lcd_cmap[regno * 2];
877
878         colreg = ((red   & 0x0F) << 8) |
879                  ((green & 0x0F) << 4) |
880                   (blue  & 0x0F) ;
881 #ifdef  CFG_INVERT_COLORS
882         colreg ^= 0x0FFF;
883 #endif
884         *cmap_ptr = colreg;
885
886         debug ("setcolreg: reg %2d @ %p: R=%02X G=%02X B=%02X => %02X%02X\n",
887                 regno, &(cp->lcd_cmap[regno * 2]),
888                 red, green, blue,
889                 cp->lcd_cmap[ regno * 2 ], cp->lcd_cmap[(regno * 2) + 1]);
890 }
891 #endif  /* LCD_COLOR8 */
892
893 /*----------------------------------------------------------------------*/
894
895 #if LCD_BPP == LCD_MONOCHROME
896 static
897 void lcd_initcolregs (void)
898 {
899         volatile immap_t *immr = (immap_t *) CFG_IMMR;
900         volatile cpm8xx_t *cp = &(immr->im_cpm);
901         ushort regno;
902
903         for (regno = 0; regno < 16; regno++) {
904                 cp->lcd_cmap[regno * 2] = 0;
905                 cp->lcd_cmap[(regno * 2) + 1] = regno & 0x0f;
906         }
907 }
908 #endif
909
910 /*----------------------------------------------------------------------*/
911
912 static void lcd_setfgcolor (int color)
913 {
914         lcd_color_fg = color & 0x0F;
915 }
916
917 /*----------------------------------------------------------------------*/
918
919 static void lcd_setbgcolor (int color)
920 {
921         lcd_color_bg = color & 0x0F;
922 }
923
924 /*----------------------------------------------------------------------*/
925
926 #ifdef  NOT_USED_SO_FAR
927 static int lcd_getfgcolor (void)
928 {
929         return lcd_color_fg;
930 }
931 #endif  /* NOT_USED_SO_FAR */
932
933 /*----------------------------------------------------------------------*/
934
935 static int lcd_getbgcolor (void)
936 {
937         return lcd_color_bg;
938 }
939
940 /*----------------------------------------------------------------------*/
941
942 static void lcd_enable (void)
943 {
944         volatile immap_t *immr = (immap_t *) CFG_IMMR;
945         volatile lcd823_t *lcdp = &immr->im_lcd;
946
947         /* Enable the LCD panel */
948         immr->im_siu_conf.sc_sdcr |= (1 << (31 - 25));          /* LAM = 1 */
949         lcdp->lcd_lccr |= LCCR_PON;
950 #if defined(CONFIG_LWMON)
951     {   uchar c = pic_read (0x60);
952         c |= 0x07;      /* Power on CCFL, Enable CCFL, Chip Enable LCD */
953         pic_write (0x60, c);
954     }
955 #elif defined(CONFIG_R360MPI)
956     {
957         extern void r360_pwm_write (uchar reg, uchar val);
958
959         r360_pwm_write(8, 1);
960         r360_pwm_write(0, 4);
961         r360_pwm_write(1, 6);
962     }
963 #endif /* CONFIG_LWMON */
964 }
965
966 /*----------------------------------------------------------------------*/
967
968 #ifdef  NOT_USED_SO_FAR
969 static void lcd_disable (void)
970 {
971         volatile immap_t *immr = (immap_t *) CFG_IMMR;
972         volatile lcd823_t *lcdp = &immr->im_lcd;
973
974 #if defined(CONFIG_LWMON)
975     {   uchar c = pic_read (0x60);
976         c &= ~0x07;     /* Power off CCFL, Disable CCFL, Chip Disable LCD */
977         pic_write (0x60, c);
978     }
979 #elif defined(CONFIG_R360MPI)
980     {
981         extern void r360_pwm_write (uchar reg, uchar val);
982
983         r360_pwm_write(0, 0);
984         r360_pwm_write(1, 0);
985     }
986 #endif /* CONFIG_LWMON */
987         /* Disable the LCD panel */
988         lcdp->lcd_lccr &= ~LCCR_PON;
989         immr->im_siu_conf.sc_sdcr &= ~(1 << (31 - 25)); /* LAM = 0 */
990 }
991 #endif  /* NOT_USED_SO_FAR */
992
993
994 /************************************************************************/
995 /* ** Chipset depending Bitmap / Logo stuff...                          */
996 /************************************************************************/
997
998
999 #ifdef CONFIG_LCD_LOGO
1000 static void bitmap_plot (int x, int y)
1001 {
1002         volatile immap_t *immr = (immap_t *) CFG_IMMR;
1003         volatile cpm8xx_t *cp = &(immr->im_cpm);
1004         ushort *cmap;
1005         ushort i;
1006         uchar *bmap;
1007         uchar *fb;
1008
1009         debug ("Logo: width %d  height %d  colors %d  cmap %d\n",
1010                 BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS,
1011                 sizeof(bmp_logo_palette)/(sizeof(ushort))
1012         );
1013
1014         /* Leave room for default color map */
1015         cmap = (ushort *)&(cp->lcd_cmap[BMP_LOGO_OFFSET*sizeof(ushort)]);
1016
1017         /* Set color map */
1018         for (i=0; i<(sizeof(bmp_logo_palette)/(sizeof(ushort))); ++i) {
1019                 ushort colreg = bmp_logo_palette[i];
1020 #ifdef  CFG_INVERT_COLORS
1021                 colreg ^= 0xFFF;
1022 #endif
1023                 *cmap++ = colreg;
1024         }
1025
1026         bmap = &bmp_logo_bitmap[0];
1027         fb   = (char *)(lcd_base + y * lcd_line_length + x);
1028
1029         for (i=0; i<BMP_LOGO_HEIGHT; ++i) {
1030                 memcpy (fb, bmap, BMP_LOGO_WIDTH);
1031                 bmap += BMP_LOGO_WIDTH;
1032                 fb   += panel_info.vl_col;
1033         }
1034 }
1035 #endif /* CONFIG_LCD_LOGO */
1036
1037 /*----------------------------------------------------------------------*/
1038
1039 static void *lcd_logo (void)
1040 {
1041 #ifdef LCD_INFO
1042         DECLARE_GLOBAL_DATA_PTR;
1043
1044         char info[80];
1045         char temp[32];
1046 #endif /* LCD_INFO */
1047
1048 #ifdef CONFIG_LCD_LOGO
1049         bitmap_plot (0, 0);
1050 #endif /* CONFIG_LCD_LOGO */
1051
1052
1053 #ifdef LCD_INFO
1054         sprintf (info, "%s (%s - %s) ", U_BOOT_VERSION, __DATE__, __TIME__);
1055         lcd_drawchars (LCD_INFO_X, LCD_INFO_Y, info, strlen(info));
1056
1057         sprintf (info, "(C) 2002 DENX Software Engineering");
1058         lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT,
1059                                         info, strlen(info));
1060
1061         sprintf (info, "    Wolfgang DENK, wd@denx.de");
1062         lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 2,
1063                                         info, strlen(info));
1064 #ifdef LCD_INFO_BELOW_LOGO
1065         sprintf (info, "MPC823 CPU at %s MHz",
1066                 strmhz(temp, gd->cpu_clk));
1067         lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 3,
1068                                         info, strlen(info));
1069         sprintf (info, "  %ld MB RAM, %ld MB Flash",
1070                 gd->ram_size >> 20,
1071                 gd->bd->bi_flashsize >> 20 );
1072         lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 4,
1073                                         info, strlen(info));
1074 #else
1075         /* leave one blank line */
1076
1077         sprintf (info, "MPC823 CPU at %s MHz, %ld MB RAM, %ld MB Flash",
1078                 strmhz(temp, gd->cpu_clk),
1079                 gd->ram_size >> 20,
1080                 gd->bd->bi_flashsize >> 20 );
1081         lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 4,
1082                                         info, strlen(info));
1083 #endif /* LCD_INFO_BELOW_LOGO */
1084 #endif /* LCD_INFO */
1085
1086 #if defined(CONFIG_LCD_LOGO) && !defined(LCD_INFO_BELOW_LOGO)
1087         return ((void *)((ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length));
1088 #else
1089         return ((void *)lcd_base);
1090 #endif  /* CONFIG_LCD_LOGO */
1091 }
1092
1093 /************************************************************************/
1094 /************************************************************************/
1095
1096 #endif /* CONFIG_LCD */