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