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