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