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