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