]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/lcd.c
common/lcd.c: cleanup use of global variables
[karo-tx-uboot.git] / common / lcd.c
1 /*
2  * Common LCD routines for supported CPUs
3  *
4  * (C) Copyright 2001-2002
5  * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
6  *
7  * See file CREDITS for list of people who contributed to this
8  * project.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23  * MA 02111-1307 USA
24  */
25
26 /************************************************************************/
27 /* ** HEADER FILES                                                      */
28 /************************************************************************/
29
30 /* #define DEBUG */
31
32 #include <config.h>
33 #include <common.h>
34 #include <command.h>
35 #include <stdarg.h>
36 #include <search.h>
37 #include <env_callback.h>
38 #include <linux/types.h>
39 #include <stdio_dev.h>
40 #if defined(CONFIG_POST)
41 #include <post.h>
42 #endif
43 #include <lcd.h>
44 #include <watchdog.h>
45
46 #if defined(CONFIG_CPU_PXA25X) || defined(CONFIG_CPU_PXA27X) || \
47         defined(CONFIG_CPU_MONAHANS)
48 #define CONFIG_CPU_PXA
49 #include <asm/byteorder.h>
50 #endif
51
52 #if defined(CONFIG_MPC823)
53 #include <lcdvideo.h>
54 #endif
55
56 #if defined(CONFIG_ATMEL_LCD)
57 #include <atmel_lcdc.h>
58 #endif
59
60 /************************************************************************/
61 /* ** FONT DATA                                                         */
62 /************************************************************************/
63 #include <video_font.h>         /* Get font data, width and height      */
64 #include <video_font_data.h>
65
66 /************************************************************************/
67 /* ** LOGO DATA                                                         */
68 /************************************************************************/
69 #ifdef CONFIG_LCD_LOGO
70 # include <bmp_logo.h>          /* Get logo data, width and height      */
71 # include <bmp_logo_data.h>
72 # if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
73 #  error Default Color Map overlaps with Logo Color Map
74 # endif
75 #endif
76
77 #ifndef CONFIG_LCD_ALIGNMENT
78 #define CONFIG_LCD_ALIGNMENT PAGE_SIZE
79 #endif
80
81 /* By default we scroll by a single line */
82 #ifndef CONFIG_CONSOLE_SCROLL_LINES
83 #define CONFIG_CONSOLE_SCROLL_LINES 1
84 #endif
85
86 DECLARE_GLOBAL_DATA_PTR;
87
88 ulong lcd_setmem (ulong addr);
89
90 static void lcd_drawchars(ushort x, ushort y, uchar *str, int count);
91 static inline void lcd_puts_xy(ushort x, ushort y, uchar *s);
92 static inline void lcd_putc_xy(ushort x, ushort y, uchar  c);
93
94 static int lcd_init(void *lcdbase);
95
96 static void *lcd_logo (void);
97
98 static int lcd_getbgcolor(void);
99 static void lcd_setfgcolor(int color);
100 static void lcd_setbgcolor(int color);
101
102 static int lcd_color_fg;
103 static int lcd_color_bg;
104
105 char lcd_is_enabled = 0;
106
107 static char lcd_flush_dcache;   /* 1 to flush dcache after each lcd update */
108
109
110 #ifdef  NOT_USED_SO_FAR
111 static void lcd_getcolreg(ushort regno,
112                                 ushort *red, ushort *green, ushort *blue);
113 static int lcd_getfgcolor(void);
114 #endif  /* NOT_USED_SO_FAR */
115
116 /************************************************************************/
117
118 /* Flush LCD activity to the caches */
119 void lcd_sync(void)
120 {
121         /*
122          * flush_dcache_range() is declared in common.h but it seems that some
123          * architectures do not actually implement it. Is there a way to find
124          * out whether it exists? For now, ARM is safe.
125          */
126 #if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF)
127         int line_length;
128
129         if (lcd_flush_dcache)
130                 flush_dcache_range((u32)lcd_base,
131                         (u32)(lcd_base + lcd_get_size(&line_length)));
132 #endif
133 }
134
135 void lcd_set_flush_dcache(int flush)
136 {
137         lcd_flush_dcache = (flush != 0);
138 }
139
140 /*----------------------------------------------------------------------*/
141
142 static void console_scrollup(void)
143 {
144         const int rows = CONFIG_CONSOLE_SCROLL_LINES;
145
146         /* Copy up rows ignoring those that will be overwritten */
147         memcpy(CONSOLE_ROW_FIRST,
148                lcd_console_address + CONSOLE_ROW_SIZE * rows,
149                CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows);
150
151         /* Clear the last rows */
152         memset(lcd_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows,
153                 COLOR_MASK(lcd_color_bg),
154                CONSOLE_ROW_SIZE * rows);
155
156         lcd_sync();
157         console_row -= rows;
158 }
159
160 /*----------------------------------------------------------------------*/
161
162 static inline void console_back(void)
163 {
164         if (--console_col < 0) {
165                 console_col = CONSOLE_COLS-1 ;
166                 if (--console_row < 0) {
167                         console_row = 0;
168                 }
169         }
170
171         lcd_putc_xy(console_col * VIDEO_FONT_WIDTH,
172                 console_row * VIDEO_FONT_HEIGHT, ' ');
173 }
174
175 /*----------------------------------------------------------------------*/
176
177 static inline void console_newline(void)
178 {
179         ++console_row;
180         console_col = 0;
181
182         /* Check if we need to scroll the terminal */
183         if (console_row >= CONSOLE_ROWS) {
184                 /* Scroll everything up */
185                 console_scrollup();
186         } else {
187                 lcd_sync();
188         }
189 }
190
191 /*----------------------------------------------------------------------*/
192
193 void lcd_putc(const char c)
194 {
195         if (!lcd_is_enabled) {
196                 serial_putc(c);
197
198                 return;
199         }
200
201         switch (c) {
202         case '\r':
203                 console_col = 0;
204
205                 return;
206         case '\n':
207                 console_newline();
208
209                 return;
210         case '\t':      /* Tab (8 chars alignment) */
211                 console_col +=  8;
212                 console_col &= ~7;
213
214                 if (console_col >= CONSOLE_COLS)
215                         console_newline();
216
217                 return;
218         case '\b':
219                 console_back();
220
221                 return;
222         default:
223                 lcd_putc_xy(console_col * VIDEO_FONT_WIDTH,
224                         console_row * VIDEO_FONT_HEIGHT, c);
225                 if (++console_col >= CONSOLE_COLS)
226                         console_newline();
227         }
228 }
229
230 /*----------------------------------------------------------------------*/
231
232 void lcd_puts(const char *s)
233 {
234         if (!lcd_is_enabled) {
235                 serial_puts(s);
236
237                 return;
238         }
239
240         while (*s) {
241                 lcd_putc(*s++);
242         }
243         lcd_sync();
244 }
245
246 /*----------------------------------------------------------------------*/
247
248 void lcd_printf(const char *fmt, ...)
249 {
250         va_list args;
251         char buf[CONFIG_SYS_PBSIZE];
252
253         va_start(args, fmt);
254         vsprintf(buf, fmt, args);
255         va_end(args);
256
257         lcd_puts(buf);
258 }
259
260 /************************************************************************/
261 /* ** Low-Level Graphics Routines                                       */
262 /************************************************************************/
263
264 static void lcd_drawchars(ushort x, ushort y, uchar *str, int count)
265 {
266         uchar *dest;
267         ushort row;
268
269 #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
270         y += BMP_LOGO_HEIGHT;
271 #endif
272
273 #if LCD_BPP == LCD_MONOCHROME
274         ushort off  = x * (1 << LCD_BPP) % 8;
275 #endif
276
277         dest = (uchar *)(lcd_base + y * lcd_line_length + x * (1 << LCD_BPP) / 8);
278
279         for (row = 0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) {
280                 uchar *s = str;
281                 int i;
282 #if LCD_BPP == LCD_COLOR16
283                 ushort *d = (ushort *)dest;
284 #else
285                 uchar *d = dest;
286 #endif
287
288 #if LCD_BPP == LCD_MONOCHROME
289                 uchar rest = *d & -(1 << (8-off));
290                 uchar sym;
291 #endif
292                 for (i = 0; i < count; ++i) {
293                         uchar c, bits;
294
295                         c = *s++;
296                         bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
297
298 #if LCD_BPP == LCD_MONOCHROME
299                         sym  = (COLOR_MASK(lcd_color_fg) & bits) |
300                                 (COLOR_MASK(lcd_color_bg) & ~bits);
301
302                         *d++ = rest | (sym >> off);
303                         rest = sym << (8-off);
304 #elif LCD_BPP == LCD_COLOR8
305                         for (c = 0; c < 8; ++c) {
306                                 *d++ = (bits & 0x80) ?
307                                                 lcd_color_fg : lcd_color_bg;
308                                 bits <<= 1;
309                         }
310 #elif LCD_BPP == LCD_COLOR16
311                         for (c = 0; c < 8; ++c) {
312                                 *d++ = (bits & 0x80) ?
313                                                 lcd_color_fg : lcd_color_bg;
314                                 bits <<= 1;
315                         }
316 #endif
317                 }
318 #if LCD_BPP == LCD_MONOCHROME
319                 *d  = rest | (*d & ((1 << (8-off)) - 1));
320 #endif
321         }
322 }
323
324 /*----------------------------------------------------------------------*/
325
326 static inline void lcd_puts_xy(ushort x, ushort y, uchar *s)
327 {
328         lcd_drawchars(x, y, s, strlen((char *)s));
329 }
330
331 /*----------------------------------------------------------------------*/
332
333 static inline void lcd_putc_xy(ushort x, ushort y, uchar c)
334 {
335         lcd_drawchars(x, y, &c, 1);
336 }
337
338 /************************************************************************/
339 /**  Small utility to check that you got the colours right              */
340 /************************************************************************/
341 #ifdef LCD_TEST_PATTERN
342
343 #define N_BLK_VERT      2
344 #define N_BLK_HOR       3
345
346 static int test_colors[N_BLK_HOR*N_BLK_VERT] = {
347         CONSOLE_COLOR_RED,      CONSOLE_COLOR_GREEN,    CONSOLE_COLOR_YELLOW,
348         CONSOLE_COLOR_BLUE,     CONSOLE_COLOR_MAGENTA,  CONSOLE_COLOR_CYAN,
349 };
350
351 static void test_pattern(void)
352 {
353         ushort v_max  = panel_info.vl_row;
354         ushort h_max  = panel_info.vl_col;
355         ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
356         ushort h_step = (h_max + N_BLK_HOR  - 1) / N_BLK_HOR;
357         ushort v, h;
358         uchar *pix = (uchar *)lcd_base;
359
360         printf("[LCD] Test Pattern: %d x %d [%d x %d]\n",
361                 h_max, v_max, h_step, v_step);
362
363         /* WARNING: Code silently assumes 8bit/pixel */
364         for (v = 0; v < v_max; ++v) {
365                 uchar iy = v / v_step;
366                 for (h = 0; h < h_max; ++h) {
367                         uchar ix = N_BLK_HOR * iy + (h/h_step);
368                         *pix++ = test_colors[ix];
369                 }
370         }
371 }
372 #endif /* LCD_TEST_PATTERN */
373
374
375 /************************************************************************/
376 /* ** GENERIC Initialization Routines                                   */
377 /************************************************************************/
378
379 int lcd_get_size(int *line_length)
380 {
381         *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
382         return *line_length * panel_info.vl_row;
383 }
384
385 int drv_lcd_init (void)
386 {
387         struct stdio_dev lcddev;
388         int rc;
389
390         lcd_base = (void *)(gd->fb_base);
391
392         lcd_get_size(&lcd_line_length);
393
394         lcd_init(lcd_base);             /* LCD initialization */
395
396         /* Device initialization */
397         memset(&lcddev, 0, sizeof(lcddev));
398
399         strcpy(lcddev.name, "lcd");
400         lcddev.ext   = 0;                       /* No extensions */
401         lcddev.flags = DEV_FLAGS_OUTPUT;        /* Output only */
402         lcddev.putc  = lcd_putc;                /* 'putc' function */
403         lcddev.puts  = lcd_puts;                /* 'puts' function */
404
405         rc = stdio_register (&lcddev);
406
407         return (rc == 0) ? 1 : rc;
408 }
409
410 /*----------------------------------------------------------------------*/
411 void lcd_clear(void)
412 {
413 #if LCD_BPP == LCD_MONOCHROME
414         /* Setting the palette */
415         lcd_initcolregs();
416
417 #elif LCD_BPP == LCD_COLOR8
418         /* Setting the palette */
419         lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0);
420         lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0);
421         lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
422         lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
423         lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
424         lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
425         lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
426         lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
427         lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
428 #endif
429
430 #ifndef CONFIG_SYS_WHITE_ON_BLACK
431         lcd_setfgcolor(CONSOLE_COLOR_BLACK);
432         lcd_setbgcolor(CONSOLE_COLOR_WHITE);
433 #else
434         lcd_setfgcolor(CONSOLE_COLOR_WHITE);
435         lcd_setbgcolor(CONSOLE_COLOR_BLACK);
436 #endif  /* CONFIG_SYS_WHITE_ON_BLACK */
437
438 #ifdef  LCD_TEST_PATTERN
439         test_pattern();
440 #else
441         /* set framebuffer to background color */
442         memset((char *)lcd_base,
443                 COLOR_MASK(lcd_getbgcolor()),
444                 lcd_line_length*panel_info.vl_row);
445 #endif
446         /* Paint the logo and retrieve LCD base address */
447         debug("[LCD] Drawing the logo...\n");
448         lcd_console_address = lcd_logo ();
449
450         console_col = 0;
451         console_row = 0;
452         lcd_sync();
453 }
454
455 static int do_lcd_clear(cmd_tbl_t *cmdtp, int flag, int argc,
456                         char *const argv[])
457 {
458         lcd_clear();
459         return 0;
460 }
461
462 U_BOOT_CMD(
463         cls,    1,      1,      do_lcd_clear,
464         "clear screen",
465         ""
466 );
467
468 /*----------------------------------------------------------------------*/
469
470 static int lcd_init(void *lcdbase)
471 {
472         /* Initialize the lcd controller */
473         debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
474
475         lcd_ctrl_init(lcdbase);
476         lcd_is_enabled = 1;
477         lcd_clear();
478         lcd_enable ();
479
480         /* Initialize the console */
481         console_col = 0;
482 #ifdef CONFIG_LCD_INFO_BELOW_LOGO
483         console_row = 7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT;
484 #else
485         console_row = 1;        /* leave 1 blank line below logo */
486 #endif
487
488         return 0;
489 }
490
491
492 /************************************************************************/
493 /* ** ROM capable initialization part - needed to reserve FB memory     */
494 /************************************************************************/
495 /*
496  * This is called early in the system initialization to grab memory
497  * for the LCD controller.
498  * Returns new address for monitor, after reserving LCD buffer memory
499  *
500  * Note that this is running from ROM, so no write access to global data.
501  */
502 ulong lcd_setmem(ulong addr)
503 {
504         ulong size;
505         int line_length;
506
507         debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,
508                 panel_info.vl_row, NBITS(panel_info.vl_bpix));
509
510         size = lcd_get_size(&line_length);
511
512         /* Round up to nearest full page, or MMU section if defined */
513         size = ALIGN(size, CONFIG_LCD_ALIGNMENT);
514         addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT);
515
516         /* Allocate pages for the frame buffer. */
517         addr -= size;
518
519         debug("Reserving %ldk for LCD Framebuffer at: %08lx\n", size>>10, addr);
520
521         return addr;
522 }
523
524 /*----------------------------------------------------------------------*/
525
526 static void lcd_setfgcolor(int color)
527 {
528         lcd_color_fg = color;
529 }
530
531 /*----------------------------------------------------------------------*/
532
533 static void lcd_setbgcolor(int color)
534 {
535         lcd_color_bg = color;
536 }
537
538 /*----------------------------------------------------------------------*/
539
540 int lcd_getfgcolor(void)
541 {
542         return lcd_color_fg;
543 }
544
545 /*----------------------------------------------------------------------*/
546
547 static int lcd_getbgcolor(void)
548 {
549         return lcd_color_bg;
550 }
551
552 /*----------------------------------------------------------------------*/
553
554 /************************************************************************/
555 /* ** Chipset depending Bitmap / Logo stuff...                          */
556 /************************************************************************/
557 static inline ushort *configuration_get_cmap(void)
558 {
559 #if defined CONFIG_CPU_PXA
560         struct pxafb_info *fbi = &panel_info.pxa;
561         return (ushort *)fbi->palette;
562 #elif defined(CONFIG_MPC823)
563         immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
564         cpm8xx_t *cp = &(immr->im_cpm);
565         return (ushort *)&(cp->lcd_cmap[255 * sizeof(ushort)]);
566 #elif defined(CONFIG_ATMEL_LCD)
567         return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0));
568 #elif !defined(CONFIG_ATMEL_HLCD) && !defined(CONFIG_EXYNOS_FB)
569         return panel_info.cmap;
570 #else
571 #if defined(CONFIG_LCD_LOGO)
572         return bmp_logo_palette;
573 #else
574         return NULL;
575 #endif
576 #endif
577 }
578
579 #ifdef CONFIG_LCD_LOGO
580 void bitmap_plot(int x, int y)
581 {
582 #ifdef CONFIG_ATMEL_LCD
583         uint *cmap = (uint *)bmp_logo_palette;
584 #else
585         ushort *cmap = (ushort *)bmp_logo_palette;
586 #endif
587         ushort i, j;
588         uchar *bmap;
589         uchar *fb;
590         ushort *fb16;
591 #if defined(CONFIG_MPC823)
592         immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
593         cpm8xx_t *cp = &(immr->im_cpm);
594 #endif
595
596         debug("Logo: width %d  height %d  colors %d  cmap %d\n",
597                 BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS,
598                 ARRAY_SIZE(bmp_logo_palette));
599
600         bmap = &bmp_logo_bitmap[0];
601         fb   = (uchar *)(lcd_base + y * lcd_line_length + x);
602
603         if (NBITS(panel_info.vl_bpix) < 12) {
604                 /* Leave room for default color map
605                  * default case: generic system with no cmap (most likely 16bpp)
606                  * cmap was set to the source palette, so no change is done.
607                  * This avoids even more ifdefs in the next stanza
608                  */
609 #if defined(CONFIG_MPC823)
610                 cmap = (ushort *) &(cp->lcd_cmap[BMP_LOGO_OFFSET * sizeof(ushort)]);
611 #elif defined(CONFIG_ATMEL_LCD)
612                 cmap = (uint *)configuration_get_cmap();
613 #else
614                 cmap = configuration_get_cmap();
615 #endif
616
617                 WATCHDOG_RESET();
618
619                 /* Set color map */
620                 for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i) {
621                         ushort colreg = bmp_logo_palette[i];
622 #ifdef CONFIG_ATMEL_LCD
623                         uint lut_entry;
624 #ifdef CONFIG_ATMEL_LCD_BGR555
625                         lut_entry = ((colreg & 0x000F) << 11) |
626                                         ((colreg & 0x00F0) <<  2) |
627                                         ((colreg & 0x0F00) >>  7);
628 #else /* CONFIG_ATMEL_LCD_RGB565 */
629                         lut_entry = ((colreg & 0x000F) << 1) |
630                                         ((colreg & 0x00F0) << 3) |
631                                         ((colreg & 0x0F00) << 4);
632 #endif
633                         *(cmap + BMP_LOGO_OFFSET) = lut_entry;
634                         cmap++;
635 #else /* !CONFIG_ATMEL_LCD */
636 #ifdef  CONFIG_SYS_INVERT_COLORS
637                         *cmap++ = 0xffff - colreg;
638 #else
639                         *cmap++ = colreg;
640 #endif
641 #endif /* CONFIG_ATMEL_LCD */
642                 }
643
644                 WATCHDOG_RESET();
645
646                 for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
647                         memcpy(fb, bmap, BMP_LOGO_WIDTH);
648                         bmap += BMP_LOGO_WIDTH;
649                         fb   += panel_info.vl_col;
650                 }
651         }
652         else { /* true color mode */
653                 u16 col16;
654                 fb16 = (ushort *)(lcd_base + y * lcd_line_length + x);
655                 for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
656                         for (j = 0; j < BMP_LOGO_WIDTH; j++) {
657                                 col16 = bmp_logo_palette[(bmap[j]-16)];
658                                 fb16[j] =
659                                         ((col16 & 0x000F) << 1) |
660                                         ((col16 & 0x00F0) << 3) |
661                                         ((col16 & 0x0F00) << 4);
662                                 }
663                         bmap += BMP_LOGO_WIDTH;
664                         fb16 += panel_info.vl_col;
665                 }
666         }
667
668         WATCHDOG_RESET();
669         lcd_sync();
670 }
671 #else
672 static inline void bitmap_plot(int x, int y) {}
673 #endif /* CONFIG_LCD_LOGO */
674
675 /*----------------------------------------------------------------------*/
676 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
677 /*
678  * Display the BMP file located at address bmp_image.
679  * Only uncompressed.
680  */
681
682 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
683 #define BMP_ALIGN_CENTER        0x7FFF
684
685 static void splash_align_axis(int *axis, unsigned long panel_size,
686                                         unsigned long picture_size)
687 {
688         unsigned long panel_picture_delta = panel_size - picture_size;
689         unsigned long axis_alignment;
690
691         if (*axis == BMP_ALIGN_CENTER)
692                 axis_alignment = panel_picture_delta / 2;
693         else if (*axis < 0)
694                 axis_alignment = panel_picture_delta + *axis + 1;
695         else
696                 return;
697
698         *axis = max(0, axis_alignment);
699 }
700 #endif
701
702
703 #ifdef CONFIG_LCD_BMP_RLE8
704
705 #define BMP_RLE8_ESCAPE         0
706 #define BMP_RLE8_EOL            0
707 #define BMP_RLE8_EOBMP          1
708 #define BMP_RLE8_DELTA          2
709
710 static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
711                                   int cnt)
712 {
713         while (cnt > 0) {
714                 *(*fbp)++ = cmap[*bmap++];
715                 cnt--;
716         }
717 }
718
719 static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt)
720 {
721         ushort *fb = *fbp;
722         int cnt_8copy = cnt >> 3;
723
724         cnt -= cnt_8copy << 3;
725         while (cnt_8copy > 0) {
726                 *fb++ = c;
727                 *fb++ = c;
728                 *fb++ = c;
729                 *fb++ = c;
730                 *fb++ = c;
731                 *fb++ = c;
732                 *fb++ = c;
733                 *fb++ = c;
734                 cnt_8copy--;
735         }
736         while (cnt > 0) {
737                 *fb++ = c;
738                 cnt--;
739         }
740         (*fbp) = fb;
741 }
742
743 /*
744  * Do not call this function directly, must be called from
745  * lcd_display_bitmap.
746  */
747 static void lcd_display_rle8_bitmap(bmp_image_t *bmp, ushort *cmap, uchar *fb,
748                                     int x_off, int y_off)
749 {
750         uchar *bmap;
751         ulong width, height;
752         ulong cnt, runlen;
753         int x, y;
754         int decode = 1;
755
756         width = le32_to_cpu(bmp->header.width);
757         height = le32_to_cpu(bmp->header.height);
758         bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset);
759
760         x = 0;
761         y = height - 1;
762
763         while (decode) {
764                 if (bmap[0] == BMP_RLE8_ESCAPE) {
765                         switch (bmap[1]) {
766                         case BMP_RLE8_EOL:
767                                 /* end of line */
768                                 bmap += 2;
769                                 x = 0;
770                                 y--;
771                                 /* 16bpix, 2-byte per pixel, width should *2 */
772                                 fb -= (width * 2 + lcd_line_length);
773                                 break;
774                         case BMP_RLE8_EOBMP:
775                                 /* end of bitmap */
776                                 decode = 0;
777                                 break;
778                         case BMP_RLE8_DELTA:
779                                 /* delta run */
780                                 x += bmap[2];
781                                 y -= bmap[3];
782                                 /* 16bpix, 2-byte per pixel, x should *2 */
783                                 fb = (uchar *) (lcd_base + (y + y_off - 1)
784                                         * lcd_line_length + (x + x_off) * 2);
785                                 bmap += 4;
786                                 break;
787                         default:
788                                 /* unencoded run */
789                                 runlen = bmap[1];
790                                 bmap += 2;
791                                 if (y < height) {
792                                         if (x < width) {
793                                                 if (x + runlen > width)
794                                                         cnt = width - x;
795                                                 else
796                                                         cnt = runlen;
797                                                 draw_unencoded_bitmap(
798                                                         (ushort **)&fb,
799                                                         bmap, cmap, cnt);
800                                         }
801                                         x += runlen;
802                                 }
803                                 bmap += runlen;
804                                 if (runlen & 1)
805                                         bmap++;
806                         }
807                 } else {
808                         /* encoded run */
809                         if (y < height) {
810                                 runlen = bmap[0];
811                                 if (x < width) {
812                                         /* aggregate the same code */
813                                         while (bmap[0] == 0xff &&
814                                                bmap[2] != BMP_RLE8_ESCAPE &&
815                                                bmap[1] == bmap[3]) {
816                                                 runlen += bmap[2];
817                                                 bmap += 2;
818                                         }
819                                         if (x + runlen > width)
820                                                 cnt = width - x;
821                                         else
822                                                 cnt = runlen;
823                                         draw_encoded_bitmap((ushort **)&fb,
824                                                 cmap[bmap[1]], cnt);
825                                 }
826                                 x += runlen;
827                         }
828                         bmap += 2;
829                 }
830         }
831 }
832 #endif
833
834 #if defined(CONFIG_MPC823) || defined(CONFIG_MCC200)
835 #define FB_PUT_BYTE(fb, from) *(fb)++ = (255 - *(from)++)
836 #else
837 #define FB_PUT_BYTE(fb, from) *(fb)++ = *(from)++
838 #endif
839
840 #if defined(CONFIG_BMP_16BPP)
841 #if defined(CONFIG_ATMEL_LCD_BGR555)
842 static inline void fb_put_word(uchar **fb, uchar **from)
843 {
844         *(*fb)++ = (((*from)[0] & 0x1f) << 2) | ((*from)[1] & 0x03);
845         *(*fb)++ = ((*from)[0] & 0xe0) | (((*from)[1] & 0x7c) >> 2);
846         *from += 2;
847 }
848 #else
849 static inline void fb_put_word(uchar **fb, uchar **from)
850 {
851         *(*fb)++ = *(*from)++;
852         *(*fb)++ = *(*from)++;
853 }
854 #endif
855 #endif /* CONFIG_BMP_16BPP */
856
857 int lcd_display_bitmap(ulong bmp_image, int x, int y)
858 {
859 #if !defined(CONFIG_MCC200)
860         ushort *cmap = NULL;
861 #endif
862         ushort *cmap_base = NULL;
863         ushort i, j;
864         uchar *fb;
865         bmp_image_t *bmp=(bmp_image_t *)bmp_image;
866         uchar *bmap;
867         ushort padded_width;
868         unsigned long width, height, byte_width;
869         unsigned long pwidth = panel_info.vl_col;
870         unsigned colors, bpix, bmp_bpix;
871
872         if (!bmp || !((bmp->header.signature[0] == 'B') &&
873                 (bmp->header.signature[1] == 'M'))) {
874                 printf("Error: no valid bmp image at %lx\n", bmp_image);
875
876                 return 1;
877         }
878
879         width = le32_to_cpu(bmp->header.width);
880         height = le32_to_cpu(bmp->header.height);
881         bmp_bpix = le16_to_cpu(bmp->header.bit_count);
882         colors = 1 << bmp_bpix;
883
884         bpix = NBITS(panel_info.vl_bpix);
885
886         if ((bpix != 1) && (bpix != 8) && (bpix != 16) && (bpix != 32)) {
887                 printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
888                         bpix, bmp_bpix);
889
890                 return 1;
891         }
892
893         /* We support displaying 8bpp BMPs on 16bpp LCDs */
894         if (bpix != bmp_bpix && !(bmp_bpix == 8 && bpix == 16)) {
895                 printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
896                         bpix,
897                         le16_to_cpu(bmp->header.bit_count));
898
899                 return 1;
900         }
901
902         debug("Display-bmp: %d x %d  with %d colors\n",
903                 (int)width, (int)height, (int)colors);
904
905 #if !defined(CONFIG_MCC200)
906         /* MCC200 LCD doesn't need CMAP, supports 1bpp b&w only */
907         if (bmp_bpix == 8) {
908                 cmap = configuration_get_cmap();
909                 cmap_base = cmap;
910
911                 /* Set color map */
912                 for (i = 0; i < colors; ++i) {
913                         bmp_color_table_entry_t cte = bmp->color_table[i];
914 #if !defined(CONFIG_ATMEL_LCD)
915                         ushort colreg =
916                                 ( ((cte.red)   << 8) & 0xf800) |
917                                 ( ((cte.green) << 3) & 0x07e0) |
918                                 ( ((cte.blue)  >> 3) & 0x001f) ;
919 #ifdef CONFIG_SYS_INVERT_COLORS
920                         *cmap = 0xffff - colreg;
921 #else
922                         *cmap = colreg;
923 #endif
924 #if defined(CONFIG_MPC823)
925                         cmap--;
926 #else
927                         cmap++;
928 #endif
929 #else /* CONFIG_ATMEL_LCD */
930                         lcd_setcolreg(i, cte.red, cte.green, cte.blue);
931 #endif
932                 }
933         }
934 #endif
935
936         /*
937          *  BMP format for Monochrome assumes that the state of a
938          * pixel is described on a per Bit basis, not per Byte.
939          *  So, in case of Monochrome BMP we should align widths
940          * on a byte boundary and convert them from Bit to Byte
941          * units.
942          *  Probably, PXA250 and MPC823 process 1bpp BMP images in
943          * their own ways, so make the converting to be MCC200
944          * specific.
945          */
946 #if defined(CONFIG_MCC200)
947         if (bpix == 1) {
948                 width = ((width + 7) & ~7) >> 3;
949                 x     = ((x + 7) & ~7) >> 3;
950                 pwidth= ((pwidth + 7) & ~7) >> 3;
951         }
952 #endif
953
954         padded_width = (width&0x3) ? ((width&~0x3)+4) : (width);
955
956 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
957         splash_align_axis(&x, pwidth, width);
958         splash_align_axis(&y, panel_info.vl_row, height);
959 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
960
961         if ((x + width) > pwidth)
962                 width = pwidth - x;
963         if ((y + height) > panel_info.vl_row)
964                 height = panel_info.vl_row - y;
965
966         bmap = (uchar *)bmp + le32_to_cpu(bmp->header.data_offset);
967         fb   = (uchar *) (lcd_base +
968                 (y + height - 1) * lcd_line_length + x * bpix / 8);
969
970         switch (bmp_bpix) {
971         case 1: /* pass through */
972         case 8:
973 #ifdef CONFIG_LCD_BMP_RLE8
974                 if (le32_to_cpu(bmp->header.compression) == BMP_BI_RLE8) {
975                         if (bpix != 16) {
976                                 /* TODO implement render code for bpix != 16 */
977                                 printf("Error: only support 16 bpix");
978                                 return 1;
979                         }
980                         lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y);
981                         break;
982                 }
983 #endif
984
985                 if (bpix != 16)
986                         byte_width = width;
987                 else
988                         byte_width = width * 2;
989
990                 for (i = 0; i < height; ++i) {
991                         WATCHDOG_RESET();
992                         for (j = 0; j < width; j++) {
993                                 if (bpix != 16) {
994                                         FB_PUT_BYTE(fb, bmap);
995                                 } else {
996                                         *(uint16_t *)fb = cmap_base[*(bmap++)];
997                                         fb += sizeof(uint16_t) / sizeof(*fb);
998                                 }
999                         }
1000                         bmap += (padded_width - width);
1001                         fb   -= (byte_width + lcd_line_length);
1002                 }
1003                 break;
1004
1005 #if defined(CONFIG_BMP_16BPP)
1006         case 16:
1007                 for (i = 0; i < height; ++i) {
1008                         WATCHDOG_RESET();
1009                         for (j = 0; j < width; j++)
1010                                 fb_put_word(&fb, &bmap);
1011
1012                         bmap += (padded_width - width) * 2;
1013                         fb   -= (width * 2 + lcd_line_length);
1014                 }
1015                 break;
1016 #endif /* CONFIG_BMP_16BPP */
1017
1018 #if defined(CONFIG_BMP_32BPP)
1019         case 32:
1020                 for (i = 0; i < height; ++i) {
1021                         for (j = 0; j < width; j++) {
1022                                 *(fb++) = *(bmap++);
1023                                 *(fb++) = *(bmap++);
1024                                 *(fb++) = *(bmap++);
1025                                 *(fb++) = *(bmap++);
1026                         }
1027                         fb  -= (lcd_line_length + width * (bpix / 8));
1028                 }
1029                 break;
1030 #endif /* CONFIG_BMP_32BPP */
1031         default:
1032                 break;
1033         };
1034
1035         lcd_sync();
1036         return 0;
1037 }
1038 #endif
1039
1040 #ifdef CONFIG_SPLASH_SCREEN_PREPARE
1041 static inline int splash_screen_prepare(void)
1042 {
1043         return board_splash_screen_prepare();
1044 }
1045 #else
1046 static inline int splash_screen_prepare(void)
1047 {
1048         return 0;
1049 }
1050 #endif
1051
1052 static void *lcd_logo(void)
1053 {
1054 #ifdef CONFIG_SPLASH_SCREEN
1055         char *s;
1056         ulong addr;
1057         static int do_splash = 1;
1058
1059         if (do_splash && (s = getenv("splashimage")) != NULL) {
1060                 int x = 0, y = 0;
1061                 do_splash = 0;
1062
1063                 if (splash_screen_prepare())
1064                         return (void *)gd->fb_base;
1065
1066                 addr = simple_strtoul (s, NULL, 16);
1067 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
1068                 s = getenv("splashpos");
1069                 if (s != NULL) {
1070                         if (s[0] == 'm')
1071                                 x = BMP_ALIGN_CENTER;
1072                         else
1073                                 x = simple_strtol(s, NULL, 0);
1074
1075                         s = strchr(s + 1, ',');
1076                         if (s != NULL) {
1077                                 if (s[1] == 'm')
1078                                         y = BMP_ALIGN_CENTER;
1079                                 else
1080                                         y = simple_strtol (s + 1, NULL, 0);
1081                         }
1082                 }
1083 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1084
1085                 if (bmp_display(addr, x, y) == 0)
1086                         return (void *)lcd_base;
1087         }
1088 #endif /* CONFIG_SPLASH_SCREEN */
1089
1090         bitmap_plot(0, 0);
1091
1092 #ifdef CONFIG_LCD_INFO
1093         console_col = LCD_INFO_X / VIDEO_FONT_WIDTH;
1094         console_row = LCD_INFO_Y / VIDEO_FONT_HEIGHT;
1095         lcd_show_board_info();
1096 #endif /* CONFIG_LCD_INFO */
1097
1098 #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
1099         return (void *)((ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length);
1100 #else
1101         return (void *)lcd_base;
1102 #endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */
1103 }
1104
1105 #ifdef CONFIG_SPLASHIMAGE_GUARD
1106 static int on_splashimage(const char *name, const char *value, enum env_op op,
1107         int flags)
1108 {
1109         ulong addr;
1110         int aligned;
1111
1112         if (op == env_op_delete)
1113                 return 0;
1114
1115         addr = simple_strtoul(value, NULL, 16);
1116         /* See README.displaying-bmps */
1117         aligned = (addr % 4 == 2);
1118         if (!aligned) {
1119                 printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n");
1120                 return -1;
1121         }
1122
1123         return 0;
1124 }
1125
1126 U_BOOT_ENV_CALLBACK(splashimage, on_splashimage);
1127 #endif
1128
1129 void lcd_position_cursor(unsigned col, unsigned row)
1130 {
1131         console_col = min(col, CONSOLE_COLS - 1);
1132         console_row = min(row, CONSOLE_ROWS - 1);
1133 }
1134
1135 int lcd_get_pixel_width(void)
1136 {
1137         return panel_info.vl_col;
1138 }
1139
1140 int lcd_get_pixel_height(void)
1141 {
1142         return panel_info.vl_row;
1143 }
1144
1145 int lcd_get_screen_rows(void)
1146 {
1147         return CONSOLE_ROWS;
1148 }
1149
1150 int lcd_get_screen_columns(void)
1151 {
1152         return CONSOLE_COLS;
1153 }
1154
1155 /************************************************************************/
1156 /************************************************************************/