Merge tag 'u-boot-imx-20200107' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[platform/kernel/u-boot.git] / common / lcd.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Common LCD routines
4  *
5  * (C) Copyright 2001-2002
6  * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
7  */
8
9 /* #define DEBUG */
10 #include <config.h>
11 #include <common.h>
12 #include <command.h>
13 #include <cpu_func.h>
14 #include <env_callback.h>
15 #include <linux/types.h>
16 #include <stdio_dev.h>
17 #include <lcd.h>
18 #include <mapmem.h>
19 #include <watchdog.h>
20 #include <asm/unaligned.h>
21 #include <splash.h>
22 #include <asm/io.h>
23 #include <asm/unaligned.h>
24 #include <video_font.h>
25
26 #ifdef CONFIG_LCD_LOGO
27 #include <bmp_logo.h>
28 #include <bmp_logo_data.h>
29 #if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
30 #error Default Color Map overlaps with Logo Color Map
31 #endif
32 #endif
33
34 #ifndef CONFIG_LCD_ALIGNMENT
35 #define CONFIG_LCD_ALIGNMENT PAGE_SIZE
36 #endif
37
38 #if (LCD_BPP != LCD_COLOR8) && (LCD_BPP != LCD_COLOR16) && \
39         (LCD_BPP != LCD_COLOR32)
40 #error Unsupported LCD BPP.
41 #endif
42
43 DECLARE_GLOBAL_DATA_PTR;
44
45 static int lcd_init(void *lcdbase);
46 static void lcd_logo(void);
47 static void lcd_setfgcolor(int color);
48 static void lcd_setbgcolor(int color);
49
50 static int lcd_color_fg;
51 static int lcd_color_bg;
52 int lcd_line_length;
53 char lcd_is_enabled = 0;
54 static void *lcd_base;                  /* Start of framebuffer memory  */
55 static char lcd_flush_dcache;   /* 1 to flush dcache after each lcd update */
56
57 /* Flush LCD activity to the caches */
58 void lcd_sync(void)
59 {
60         /*
61          * flush_dcache_range() is declared in common.h but it seems that some
62          * architectures do not actually implement it. Is there a way to find
63          * out whether it exists? For now, ARM is safe.
64          */
65 #if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
66         int line_length;
67
68         if (lcd_flush_dcache)
69                 flush_dcache_range((ulong)lcd_base,
70                         (ulong)(lcd_base + lcd_get_size(&line_length)));
71 #endif
72 }
73
74 void lcd_set_flush_dcache(int flush)
75 {
76         lcd_flush_dcache = (flush != 0);
77 }
78
79 static void lcd_stub_putc(struct stdio_dev *dev, const char c)
80 {
81         lcd_putc(c);
82 }
83
84 static void lcd_stub_puts(struct stdio_dev *dev, const char *s)
85 {
86         lcd_puts(s);
87 }
88
89 /* Small utility to check that you got the colours right */
90 #ifdef LCD_TEST_PATTERN
91
92 #if LCD_BPP == LCD_COLOR8
93 #define N_BLK_VERT      2
94 #define N_BLK_HOR       3
95
96 static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
97         CONSOLE_COLOR_RED,      CONSOLE_COLOR_GREEN,    CONSOLE_COLOR_YELLOW,
98         CONSOLE_COLOR_BLUE,     CONSOLE_COLOR_MAGENTA,  CONSOLE_COLOR_CYAN,
99 }; /*LCD_BPP == LCD_COLOR8 */
100
101 #elif LCD_BPP == LCD_COLOR16
102 #define N_BLK_VERT      2
103 #define N_BLK_HOR       4
104
105 static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
106         CONSOLE_COLOR_RED,      CONSOLE_COLOR_GREEN,    CONSOLE_COLOR_YELLOW,   CONSOLE_COLOR_BLUE,
107         CONSOLE_COLOR_MAGENTA,  CONSOLE_COLOR_CYAN,     CONSOLE_COLOR_GREY,     CONSOLE_COLOR_WHITE,
108 };
109 #endif /*LCD_BPP == LCD_COLOR16 */
110
111 static void test_pattern(void)
112 {
113         ushort v_max  = panel_info.vl_row;
114         ushort h_max  = panel_info.vl_col;
115         ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
116         ushort h_step = (h_max + N_BLK_HOR  - 1) / N_BLK_HOR;
117         ushort v, h;
118 #if LCD_BPP == LCD_COLOR8
119         uchar *pix = (uchar *)lcd_base;
120 #elif LCD_BPP == LCD_COLOR16
121         ushort *pix = (ushort *)lcd_base;
122 #endif
123
124         printf("[LCD] Test Pattern: %d x %d [%d x %d]\n",
125                 h_max, v_max, h_step, v_step);
126
127         for (v = 0; v < v_max; ++v) {
128                 uchar iy = v / v_step;
129                 for (h = 0; h < h_max; ++h) {
130                         uchar ix = N_BLK_HOR * iy + h / h_step;
131                         *pix++ = test_colors[ix];
132                 }
133         }
134 }
135 #endif /* LCD_TEST_PATTERN */
136
137 /*
138  * With most lcd drivers the line length is set up
139  * by calculating it from panel_info parameters. Some
140  * drivers need to calculate the line length differently,
141  * so make the function weak to allow overriding it.
142  */
143 __weak int lcd_get_size(int *line_length)
144 {
145         *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
146         return *line_length * panel_info.vl_row;
147 }
148
149 int drv_lcd_init(void)
150 {
151         struct stdio_dev lcddev;
152         int rc;
153
154         lcd_base = map_sysmem(gd->fb_base, 0);
155
156         lcd_init(lcd_base);
157
158         /* Device initialization */
159         memset(&lcddev, 0, sizeof(lcddev));
160
161         strcpy(lcddev.name, "lcd");
162         lcddev.ext   = 0;                       /* No extensions */
163         lcddev.flags = DEV_FLAGS_OUTPUT;        /* Output only */
164         lcddev.putc  = lcd_stub_putc;           /* 'putc' function */
165         lcddev.puts  = lcd_stub_puts;           /* 'puts' function */
166
167         rc = stdio_register(&lcddev);
168
169         return (rc == 0) ? 1 : rc;
170 }
171
172 void lcd_clear(void)
173 {
174         int bg_color;
175         __maybe_unused ulong addr;
176         static int do_splash = 1;
177 #if LCD_BPP == LCD_COLOR8
178         /* Setting the palette */
179         lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0);
180         lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0);
181         lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
182         lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
183         lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
184         lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
185         lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
186         lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
187         lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
188 #endif
189
190 #ifndef CONFIG_SYS_WHITE_ON_BLACK
191         lcd_setfgcolor(CONSOLE_COLOR_BLACK);
192         lcd_setbgcolor(CONSOLE_COLOR_WHITE);
193         bg_color = CONSOLE_COLOR_WHITE;
194 #else
195         lcd_setfgcolor(CONSOLE_COLOR_WHITE);
196         lcd_setbgcolor(CONSOLE_COLOR_BLACK);
197         bg_color = CONSOLE_COLOR_BLACK;
198 #endif  /* CONFIG_SYS_WHITE_ON_BLACK */
199
200 #ifdef  LCD_TEST_PATTERN
201         test_pattern();
202 #else
203         /* set framebuffer to background color */
204 #if (LCD_BPP != LCD_COLOR32)
205         memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row);
206 #else
207         u32 *ppix = lcd_base;
208         u32 i;
209         for (i = 0;
210            i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix);
211            i++) {
212                 *ppix++ = bg_color;
213         }
214 #endif
215 #endif
216         /* setup text-console */
217         debug("[LCD] setting up console...\n");
218         lcd_init_console(lcd_base,
219                          panel_info.vl_col,
220                          panel_info.vl_row,
221                          panel_info.vl_rot);
222         /* Paint the logo and retrieve LCD base address */
223         debug("[LCD] Drawing the logo...\n");
224         if (do_splash) {
225                 if (splash_display() == 0) {
226                         do_splash = 0;
227                         lcd_sync();
228                         return;
229                 }
230         }
231
232         lcd_logo();
233 #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
234         addr = (ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length;
235         lcd_init_console((void *)addr, panel_info.vl_col,
236                          panel_info.vl_row, panel_info.vl_rot);
237 #endif
238         lcd_sync();
239 }
240
241 static int lcd_init(void *lcdbase)
242 {
243         debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
244         lcd_ctrl_init(lcdbase);
245
246         /*
247          * lcd_ctrl_init() of some drivers (i.e. bcm2835 on rpi) ignores
248          * the 'lcdbase' argument and uses custom lcd base address
249          * by setting up gd->fb_base. Check for this condition and fixup
250          * 'lcd_base' address.
251          */
252         if (map_to_sysmem(lcdbase) != gd->fb_base)
253                 lcd_base = map_sysmem(gd->fb_base, 0);
254
255         debug("[LCD] Using LCD frambuffer at %p\n", lcd_base);
256
257         lcd_get_size(&lcd_line_length);
258         lcd_is_enabled = 1;
259         lcd_clear();
260         lcd_enable();
261
262         /* Initialize the console */
263         lcd_set_col(0);
264 #ifdef CONFIG_LCD_INFO_BELOW_LOGO
265         lcd_set_row(7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT);
266 #else
267         lcd_set_row(1); /* leave 1 blank line below logo */
268 #endif
269
270         return 0;
271 }
272
273 /*
274  * This is called early in the system initialization to grab memory
275  * for the LCD controller.
276  * Returns new address for monitor, after reserving LCD buffer memory
277  *
278  * Note that this is running from ROM, so no write access to global data.
279  */
280 ulong lcd_setmem(ulong addr)
281 {
282         ulong size;
283         int line_length;
284
285         debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,
286                 panel_info.vl_row, NBITS(panel_info.vl_bpix));
287
288         size = lcd_get_size(&line_length);
289
290         /* Round up to nearest full page, or MMU section if defined */
291         size = ALIGN(size, CONFIG_LCD_ALIGNMENT);
292         addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT);
293
294         /* Allocate pages for the frame buffer. */
295         addr -= size;
296
297         debug("Reserving %ldk for LCD Framebuffer at: %08lx\n",
298               size >> 10, addr);
299
300         return addr;
301 }
302
303 static void lcd_setfgcolor(int color)
304 {
305         lcd_color_fg = color;
306 }
307
308 int lcd_getfgcolor(void)
309 {
310         return lcd_color_fg;
311 }
312
313 static void lcd_setbgcolor(int color)
314 {
315         lcd_color_bg = color;
316 }
317
318 int lcd_getbgcolor(void)
319 {
320         return lcd_color_bg;
321 }
322
323 #ifdef CONFIG_LCD_LOGO
324 __weak void lcd_logo_set_cmap(void)
325 {
326         int i;
327         ushort *cmap = configuration_get_cmap();
328
329         for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i)
330                 *cmap++ = bmp_logo_palette[i];
331 }
332
333 void lcd_logo_plot(int x, int y)
334 {
335         ushort i, j;
336         uchar *bmap = &bmp_logo_bitmap[0];
337         unsigned bpix = NBITS(panel_info.vl_bpix);
338         uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8);
339         ushort *fb16;
340
341         debug("Logo: width %d  height %d  colors %d\n",
342               BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS);
343
344         if (bpix < 12) {
345                 WATCHDOG_RESET();
346                 lcd_logo_set_cmap();
347                 WATCHDOG_RESET();
348
349                 for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
350                         memcpy(fb, bmap, BMP_LOGO_WIDTH);
351                         bmap += BMP_LOGO_WIDTH;
352                         fb += panel_info.vl_col;
353                 }
354         }
355         else { /* true color mode */
356                 u16 col16;
357                 fb16 = (ushort *)fb;
358                 for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
359                         for (j = 0; j < BMP_LOGO_WIDTH; j++) {
360                                 col16 = bmp_logo_palette[(bmap[j]-16)];
361                                 fb16[j] =
362                                         ((col16 & 0x000F) << 1) |
363                                         ((col16 & 0x00F0) << 3) |
364                                         ((col16 & 0x0F00) << 4);
365                                 }
366                         bmap += BMP_LOGO_WIDTH;
367                         fb16 += panel_info.vl_col;
368                 }
369         }
370
371         WATCHDOG_RESET();
372         lcd_sync();
373 }
374 #else
375 static inline void lcd_logo_plot(int x, int y) {}
376 #endif /* CONFIG_LCD_LOGO */
377
378 #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
379 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
380
381 static void splash_align_axis(int *axis, unsigned long panel_size,
382                                         unsigned long picture_size)
383 {
384         unsigned long panel_picture_delta = panel_size - picture_size;
385         unsigned long axis_alignment;
386
387         if (*axis == BMP_ALIGN_CENTER)
388                 axis_alignment = panel_picture_delta / 2;
389         else if (*axis < 0)
390                 axis_alignment = panel_picture_delta + *axis + 1;
391         else
392                 return;
393
394         *axis = max(0, (int)axis_alignment);
395 }
396 #endif
397
398 #ifdef CONFIG_LCD_BMP_RLE8
399 #define BMP_RLE8_ESCAPE         0
400 #define BMP_RLE8_EOL            0
401 #define BMP_RLE8_EOBMP          1
402 #define BMP_RLE8_DELTA          2
403
404 static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
405                                   int cnt)
406 {
407         while (cnt > 0) {
408                 *(*fbp)++ = cmap[*bmap++];
409                 cnt--;
410         }
411 }
412
413 static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt)
414 {
415         ushort *fb = *fbp;
416         int cnt_8copy = cnt >> 3;
417
418         cnt -= cnt_8copy << 3;
419         while (cnt_8copy > 0) {
420                 *fb++ = c;
421                 *fb++ = c;
422                 *fb++ = c;
423                 *fb++ = c;
424                 *fb++ = c;
425                 *fb++ = c;
426                 *fb++ = c;
427                 *fb++ = c;
428                 cnt_8copy--;
429         }
430         while (cnt > 0) {
431                 *fb++ = c;
432                 cnt--;
433         }
434         *fbp = fb;
435 }
436
437 /*
438  * Do not call this function directly, must be called from lcd_display_bitmap.
439  */
440 static void lcd_display_rle8_bitmap(struct bmp_image *bmp, ushort *cmap,
441                                     uchar *fb, int x_off, int y_off)
442 {
443         uchar *bmap;
444         ulong width, height;
445         ulong cnt, runlen;
446         int x, y;
447         int decode = 1;
448
449         width = get_unaligned_le32(&bmp->header.width);
450         height = get_unaligned_le32(&bmp->header.height);
451         bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
452
453         x = 0;
454         y = height - 1;
455
456         while (decode) {
457                 if (bmap[0] == BMP_RLE8_ESCAPE) {
458                         switch (bmap[1]) {
459                         case BMP_RLE8_EOL:
460                                 /* end of line */
461                                 bmap += 2;
462                                 x = 0;
463                                 y--;
464                                 /* 16bpix, 2-byte per pixel, width should *2 */
465                                 fb -= (width * 2 + lcd_line_length);
466                                 break;
467                         case BMP_RLE8_EOBMP:
468                                 /* end of bitmap */
469                                 decode = 0;
470                                 break;
471                         case BMP_RLE8_DELTA:
472                                 /* delta run */
473                                 x += bmap[2];
474                                 y -= bmap[3];
475                                 /* 16bpix, 2-byte per pixel, x should *2 */
476                                 fb = (uchar *) (lcd_base + (y + y_off - 1)
477                                         * lcd_line_length + (x + x_off) * 2);
478                                 bmap += 4;
479                                 break;
480                         default:
481                                 /* unencoded run */
482                                 runlen = bmap[1];
483                                 bmap += 2;
484                                 if (y < height) {
485                                         if (x < width) {
486                                                 if (x + runlen > width)
487                                                         cnt = width - x;
488                                                 else
489                                                         cnt = runlen;
490                                                 draw_unencoded_bitmap(
491                                                         (ushort **)&fb,
492                                                         bmap, cmap, cnt);
493                                         }
494                                         x += runlen;
495                                 }
496                                 bmap += runlen;
497                                 if (runlen & 1)
498                                         bmap++;
499                         }
500                 } else {
501                         /* encoded run */
502                         if (y < height) {
503                                 runlen = bmap[0];
504                                 if (x < width) {
505                                         /* aggregate the same code */
506                                         while (bmap[0] == 0xff &&
507                                                bmap[2] != BMP_RLE8_ESCAPE &&
508                                                bmap[1] == bmap[3]) {
509                                                 runlen += bmap[2];
510                                                 bmap += 2;
511                                         }
512                                         if (x + runlen > width)
513                                                 cnt = width - x;
514                                         else
515                                                 cnt = runlen;
516                                         draw_encoded_bitmap((ushort **)&fb,
517                                                 cmap[bmap[1]], cnt);
518                                 }
519                                 x += runlen;
520                         }
521                         bmap += 2;
522                 }
523         }
524 }
525 #endif
526
527 __weak void fb_put_byte(uchar **fb, uchar **from)
528 {
529         *(*fb)++ = *(*from)++;
530 }
531
532 #if defined(CONFIG_BMP_16BPP)
533 __weak void fb_put_word(uchar **fb, uchar **from)
534 {
535         *(*fb)++ = *(*from)++;
536         *(*fb)++ = *(*from)++;
537 }
538 #endif /* CONFIG_BMP_16BPP */
539
540 __weak void lcd_set_cmap(struct bmp_image *bmp, unsigned colors)
541 {
542         int i;
543         struct bmp_color_table_entry cte;
544         ushort *cmap = configuration_get_cmap();
545
546         for (i = 0; i < colors; ++i) {
547                 cte = bmp->color_table[i];
548                 *cmap = (((cte.red)   << 8) & 0xf800) |
549                         (((cte.green) << 3) & 0x07e0) |
550                         (((cte.blue)  >> 3) & 0x001f);
551                 cmap++;
552         }
553 }
554
555 int lcd_display_bitmap(ulong bmp_image, int x, int y)
556 {
557         ushort *cmap_base = NULL;
558         ushort i, j;
559         uchar *fb;
560         struct bmp_image *bmp = (struct bmp_image *)map_sysmem(bmp_image, 0);
561         uchar *bmap;
562         ushort padded_width;
563         unsigned long width, height, byte_width;
564         unsigned long pwidth = panel_info.vl_col;
565         unsigned colors, bpix, bmp_bpix;
566         int hdr_size;
567         struct bmp_color_table_entry *palette;
568
569         if (!bmp || !(bmp->header.signature[0] == 'B' &&
570                 bmp->header.signature[1] == 'M')) {
571                 printf("Error: no valid bmp image at %lx\n", bmp_image);
572
573                 return 1;
574         }
575
576         palette = bmp->color_table;
577         width = get_unaligned_le32(&bmp->header.width);
578         height = get_unaligned_le32(&bmp->header.height);
579         bmp_bpix = get_unaligned_le16(&bmp->header.bit_count);
580         hdr_size = get_unaligned_le16(&bmp->header.size);
581         debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size, bmp_bpix);
582
583         colors = 1 << bmp_bpix;
584
585         bpix = NBITS(panel_info.vl_bpix);
586
587         if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) {
588                 printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
589                         bpix, bmp_bpix);
590
591                 return 1;
592         }
593
594         /*
595          * We support displaying 8bpp BMPs on 16bpp LCDs
596          * and displaying 24bpp BMPs on 32bpp LCDs
597          * */
598         if (bpix != bmp_bpix &&
599             !(bmp_bpix == 8 && bpix == 16) &&
600             !(bmp_bpix == 24 && bpix == 32)) {
601                 printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
602                         bpix, get_unaligned_le16(&bmp->header.bit_count));
603                 return 1;
604         }
605
606         debug("Display-bmp: %d x %d  with %d colors, display %d\n",
607               (int)width, (int)height, (int)colors, 1 << bpix);
608
609         if (bmp_bpix == 8)
610                 lcd_set_cmap(bmp, colors);
611
612         padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width);
613
614 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
615         splash_align_axis(&x, pwidth, width);
616         splash_align_axis(&y, panel_info.vl_row, height);
617 #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
618
619         if ((x + width) > pwidth)
620                 width = pwidth - x;
621         if ((y + height) > panel_info.vl_row)
622                 height = panel_info.vl_row - y;
623
624         bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
625         fb   = (uchar *)(lcd_base +
626                 (y + height - 1) * lcd_line_length + x * bpix / 8);
627
628         switch (bmp_bpix) {
629         case 1:
630         case 8: {
631                 cmap_base = configuration_get_cmap();
632 #ifdef CONFIG_LCD_BMP_RLE8
633                 u32 compression = get_unaligned_le32(&bmp->header.compression);
634                 debug("compressed %d %d\n", compression, BMP_BI_RLE8);
635                 if (compression == BMP_BI_RLE8) {
636                         if (bpix != 16) {
637                                 /* TODO implement render code for bpix != 16 */
638                                 printf("Error: only support 16 bpix");
639                                 return 1;
640                         }
641                         lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y);
642                         break;
643                 }
644 #endif
645
646                 if (bpix != 16)
647                         byte_width = width;
648                 else
649                         byte_width = width * 2;
650
651                 for (i = 0; i < height; ++i) {
652                         WATCHDOG_RESET();
653                         for (j = 0; j < width; j++) {
654                                 if (bpix != 16) {
655                                         fb_put_byte(&fb, &bmap);
656                                 } else {
657                                         struct bmp_color_table_entry *entry;
658                                         uint val;
659
660                                         if (cmap_base) {
661                                                 val = cmap_base[*bmap];
662                                         } else {
663                                                 entry = &palette[*bmap];
664                                                 val = entry->blue >> 3 |
665                                                         entry->green >> 2 << 5 |
666                                                         entry->red >> 3 << 11;
667                                         }
668                                         *(uint16_t *)fb = val;
669                                         bmap++;
670                                         fb += sizeof(uint16_t) / sizeof(*fb);
671                                 }
672                         }
673                         bmap += (padded_width - width);
674                         fb -= byte_width + lcd_line_length;
675                 }
676                 break;
677         }
678 #if defined(CONFIG_BMP_16BPP)
679         case 16:
680                 for (i = 0; i < height; ++i) {
681                         WATCHDOG_RESET();
682                         for (j = 0; j < width; j++)
683                                 fb_put_word(&fb, &bmap);
684
685                         bmap += (padded_width - width) * 2;
686                         fb -= width * 2 + lcd_line_length;
687                 }
688                 break;
689 #endif /* CONFIG_BMP_16BPP */
690 #if defined(CONFIG_BMP_24BPP)
691         case 24:
692                 for (i = 0; i < height; ++i) {
693                         for (j = 0; j < width; j++) {
694                                 *(fb++) = *(bmap++);
695                                 *(fb++) = *(bmap++);
696                                 *(fb++) = *(bmap++);
697                                 *(fb++) = 0;
698                         }
699                         fb -= lcd_line_length + width * (bpix / 8);
700                 }
701                 break;
702 #endif /* CONFIG_BMP_24BPP */
703 #if defined(CONFIG_BMP_32BPP)
704         case 32:
705                 for (i = 0; i < height; ++i) {
706                         for (j = 0; j < width; j++) {
707                                 *(fb++) = *(bmap++);
708                                 *(fb++) = *(bmap++);
709                                 *(fb++) = *(bmap++);
710                                 *(fb++) = *(bmap++);
711                         }
712                         fb -= lcd_line_length + width * (bpix / 8);
713                 }
714                 break;
715 #endif /* CONFIG_BMP_32BPP */
716         default:
717                 break;
718         };
719
720         lcd_sync();
721         return 0;
722 }
723 #endif
724
725 static void lcd_logo(void)
726 {
727         lcd_logo_plot(0, 0);
728
729 #ifdef CONFIG_LCD_INFO
730         lcd_set_col(LCD_INFO_X / VIDEO_FONT_WIDTH);
731         lcd_set_row(LCD_INFO_Y / VIDEO_FONT_HEIGHT);
732         lcd_show_board_info();
733 #endif /* CONFIG_LCD_INFO */
734 }
735
736 #ifdef CONFIG_SPLASHIMAGE_GUARD
737 static int on_splashimage(const char *name, const char *value, enum env_op op,
738         int flags)
739 {
740         ulong addr;
741         int aligned;
742
743         if (op == env_op_delete)
744                 return 0;
745
746         addr = simple_strtoul(value, NULL, 16);
747         /* See README.displaying-bmps */
748         aligned = (addr % 4 == 2);
749         if (!aligned) {
750                 printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n");
751                 return -1;
752         }
753
754         return 0;
755 }
756
757 U_BOOT_ENV_CALLBACK(splashimage, on_splashimage);
758 #endif
759
760 int lcd_get_pixel_width(void)
761 {
762         return panel_info.vl_col;
763 }
764
765 int lcd_get_pixel_height(void)
766 {
767         return panel_info.vl_row;
768 }