1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
28655b6f8Swdenk /*
3c8d2febcSNikita Kiryanov * Common LCD routines
48655b6f8Swdenk *
58655b6f8Swdenk * (C) Copyright 2001-2002
68655b6f8Swdenk * Wolfgang Denk, DENX Software Engineering -- wd@denx.de
78655b6f8Swdenk */
88655b6f8Swdenk
98655b6f8Swdenk /* #define DEBUG */
108655b6f8Swdenk #include <config.h>
118655b6f8Swdenk #include <common.h>
128655b6f8Swdenk #include <command.h>
13c0880485SNikita Kiryanov #include <env_callback.h>
148655b6f8Swdenk #include <linux/types.h>
1552cb4d4fSJean-Christophe PLAGNIOL-VILLARD #include <stdio_dev.h>
168655b6f8Swdenk #include <lcd.h>
170eb25b61SJoe Hershberger #include <mapmem.h>
188b0bfc68Swdenk #include <watchdog.h>
19dca2a1c1SPrzemyslaw Marczak #include <asm/unaligned.h>
20dd4425e8SRobert Winkler #include <splash.h>
217d95f2a3SSimon Glass #include <asm/io.h>
227d95f2a3SSimon Glass #include <asm/unaligned.h>
23c8d2febcSNikita Kiryanov #include <video_font.h>
24dd4425e8SRobert Winkler
2588804d19Swdenk #ifdef CONFIG_LCD_LOGO
26c8d2febcSNikita Kiryanov #include <bmp_logo.h>
27c270730fSChe-Liang Chiou #include <bmp_logo_data.h>
28acb13868SAlessandro Rubini #if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
2988804d19Swdenk #error Default Color Map overlaps with Logo Color Map
3088804d19Swdenk #endif
3188804d19Swdenk #endif
328655b6f8Swdenk
33676d319eSSimon Glass #ifndef CONFIG_LCD_ALIGNMENT
34676d319eSSimon Glass #define CONFIG_LCD_ALIGNMENT PAGE_SIZE
35676d319eSSimon Glass #endif
36676d319eSSimon Glass
37a7de2953SNikita Kiryanov #if (LCD_BPP != LCD_COLOR8) && (LCD_BPP != LCD_COLOR16) && \
38a7de2953SNikita Kiryanov (LCD_BPP != LCD_COLOR32)
39a5796c51SJeroen Hofstee #error Unsupported LCD BPP.
40a5796c51SJeroen Hofstee #endif
41a5796c51SJeroen Hofstee
42d87080b7SWolfgang Denk DECLARE_GLOBAL_DATA_PTR;
438655b6f8Swdenk
448655b6f8Swdenk static int lcd_init(void *lcdbase);
457bf71d1fSNikita Kiryanov static void lcd_logo(void);
468655b6f8Swdenk static void lcd_setfgcolor(int color);
478655b6f8Swdenk static void lcd_setbgcolor(int color);
488655b6f8Swdenk
4946d1d5ddSWolfgang Denk static int lcd_color_fg;
5046d1d5ddSWolfgang Denk static int lcd_color_bg;
51f1d205a1SJeroen Hofstee int lcd_line_length;
528655b6f8Swdenk char lcd_is_enabled = 0;
5300a0ca59SJeroen Hofstee static void *lcd_base; /* Start of framebuffer memory */
549a8efc46SSimon Glass static char lcd_flush_dcache; /* 1 to flush dcache after each lcd update */
559a8efc46SSimon Glass
569a8efc46SSimon Glass /* Flush LCD activity to the caches */
lcd_sync(void)579a8efc46SSimon Glass void lcd_sync(void)
589a8efc46SSimon Glass {
599a8efc46SSimon Glass /*
609a8efc46SSimon Glass * flush_dcache_range() is declared in common.h but it seems that some
619a8efc46SSimon Glass * architectures do not actually implement it. Is there a way to find
629a8efc46SSimon Glass * out whether it exists? For now, ARM is safe.
639a8efc46SSimon Glass */
649a8efc46SSimon Glass #if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF)
659a8efc46SSimon Glass int line_length;
669a8efc46SSimon Glass
679a8efc46SSimon Glass if (lcd_flush_dcache)
68f8f58fbbSAlexander Graf flush_dcache_range((ulong)lcd_base,
69f8f58fbbSAlexander Graf (ulong)(lcd_base + lcd_get_size(&line_length)));
709a8efc46SSimon Glass #endif
719a8efc46SSimon Glass }
729a8efc46SSimon Glass
lcd_set_flush_dcache(int flush)739a8efc46SSimon Glass void lcd_set_flush_dcache(int flush)
749a8efc46SSimon Glass {
759a8efc46SSimon Glass lcd_flush_dcache = (flush != 0);
769a8efc46SSimon Glass }
779a8efc46SSimon Glass
lcd_stub_putc(struct stdio_dev * dev,const char c)78709ea543SSimon Glass static void lcd_stub_putc(struct stdio_dev *dev, const char c)
79709ea543SSimon Glass {
80709ea543SSimon Glass lcd_putc(c);
81709ea543SSimon Glass }
82709ea543SSimon Glass
lcd_stub_puts(struct stdio_dev * dev,const char * s)83709ea543SSimon Glass static void lcd_stub_puts(struct stdio_dev *dev, const char *s)
84709ea543SSimon Glass {
85709ea543SSimon Glass lcd_puts(s);
86709ea543SSimon Glass }
87709ea543SSimon Glass
88c8d2febcSNikita Kiryanov /* Small utility to check that you got the colours right */
898655b6f8Swdenk #ifdef LCD_TEST_PATTERN
908655b6f8Swdenk
91e32951b5SAndreas Neubacher #if LCD_BPP == LCD_COLOR8
928655b6f8Swdenk #define N_BLK_VERT 2
938655b6f8Swdenk #define N_BLK_HOR 3
948655b6f8Swdenk
958655b6f8Swdenk static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
968655b6f8Swdenk CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW,
978655b6f8Swdenk CONSOLE_COLOR_BLUE, CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN,
98e32951b5SAndreas Neubacher }; /*LCD_BPP == LCD_COLOR8 */
99e32951b5SAndreas Neubacher
100e32951b5SAndreas Neubacher #elif LCD_BPP == LCD_COLOR16
101e32951b5SAndreas Neubacher #define N_BLK_VERT 2
102e32951b5SAndreas Neubacher #define N_BLK_HOR 4
103e32951b5SAndreas Neubacher
104e32951b5SAndreas Neubacher static int test_colors[N_BLK_HOR * N_BLK_VERT] = {
105e32951b5SAndreas Neubacher CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW, CONSOLE_COLOR_BLUE,
106e32951b5SAndreas Neubacher CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN, CONSOLE_COLOR_GREY, CONSOLE_COLOR_WHITE,
1078655b6f8Swdenk };
108e32951b5SAndreas Neubacher #endif /*LCD_BPP == LCD_COLOR16 */
1098655b6f8Swdenk
test_pattern(void)1108655b6f8Swdenk static void test_pattern(void)
1118655b6f8Swdenk {
1128655b6f8Swdenk ushort v_max = panel_info.vl_row;
1138655b6f8Swdenk ushort h_max = panel_info.vl_col;
1148655b6f8Swdenk ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT;
1158655b6f8Swdenk ushort h_step = (h_max + N_BLK_HOR - 1) / N_BLK_HOR;
1168655b6f8Swdenk ushort v, h;
117e32951b5SAndreas Neubacher #if LCD_BPP == LCD_COLOR8
1188655b6f8Swdenk uchar *pix = (uchar *)lcd_base;
119e32951b5SAndreas Neubacher #elif LCD_BPP == LCD_COLOR16
120e32951b5SAndreas Neubacher ushort *pix = (ushort *)lcd_base;
121e32951b5SAndreas Neubacher #endif
1228655b6f8Swdenk
1238655b6f8Swdenk printf("[LCD] Test Pattern: %d x %d [%d x %d]\n",
1248655b6f8Swdenk h_max, v_max, h_step, v_step);
1258655b6f8Swdenk
1268655b6f8Swdenk for (v = 0; v < v_max; ++v) {
1278655b6f8Swdenk uchar iy = v / v_step;
1288655b6f8Swdenk for (h = 0; h < h_max; ++h) {
1296b035141SJeroen Hofstee uchar ix = N_BLK_HOR * iy + h / h_step;
1308655b6f8Swdenk *pix++ = test_colors[ix];
1318655b6f8Swdenk }
1328655b6f8Swdenk }
1338655b6f8Swdenk }
1348655b6f8Swdenk #endif /* LCD_TEST_PATTERN */
1358655b6f8Swdenk
136cefa4717SAnatolij Gustschin /*
137cefa4717SAnatolij Gustschin * With most lcd drivers the line length is set up
138cefa4717SAnatolij Gustschin * by calculating it from panel_info parameters. Some
139cefa4717SAnatolij Gustschin * drivers need to calculate the line length differently,
140cefa4717SAnatolij Gustschin * so make the function weak to allow overriding it.
141cefa4717SAnatolij Gustschin */
lcd_get_size(int * line_length)142cefa4717SAnatolij Gustschin __weak int lcd_get_size(int *line_length)
143676d319eSSimon Glass {
144676d319eSSimon Glass *line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
145676d319eSSimon Glass return *line_length * panel_info.vl_row;
146676d319eSSimon Glass }
147676d319eSSimon Glass
drv_lcd_init(void)1488655b6f8Swdenk int drv_lcd_init(void)
1498655b6f8Swdenk {
15052cb4d4fSJean-Christophe PLAGNIOL-VILLARD struct stdio_dev lcddev;
1518655b6f8Swdenk int rc;
1528655b6f8Swdenk
1537d95f2a3SSimon Glass lcd_base = map_sysmem(gd->fb_base, 0);
1548655b6f8Swdenk
155c8d2febcSNikita Kiryanov lcd_init(lcd_base);
1568655b6f8Swdenk
1578655b6f8Swdenk /* Device initialization */
1588655b6f8Swdenk memset(&lcddev, 0, sizeof(lcddev));
1598655b6f8Swdenk
1608655b6f8Swdenk strcpy(lcddev.name, "lcd");
1618655b6f8Swdenk lcddev.ext = 0; /* No extensions */
1628655b6f8Swdenk lcddev.flags = DEV_FLAGS_OUTPUT; /* Output only */
163709ea543SSimon Glass lcddev.putc = lcd_stub_putc; /* 'putc' function */
164709ea543SSimon Glass lcddev.puts = lcd_stub_puts; /* 'puts' function */
1658655b6f8Swdenk
16652cb4d4fSJean-Christophe PLAGNIOL-VILLARD rc = stdio_register(&lcddev);
1678655b6f8Swdenk
1688655b6f8Swdenk return (rc == 0) ? 1 : rc;
1698655b6f8Swdenk }
1708655b6f8Swdenk
lcd_clear(void)17102110903SChe-Liang Chiou void lcd_clear(void)
1728655b6f8Swdenk {
1734d03634eSNikita Kiryanov int bg_color;
1747bf71d1fSNikita Kiryanov char *s;
1757bf71d1fSNikita Kiryanov ulong addr;
1767bf71d1fSNikita Kiryanov static int do_splash = 1;
177f4469f50SNikita Kiryanov #if LCD_BPP == LCD_COLOR8
1788655b6f8Swdenk /* Setting the palette */
1798655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0);
1808655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0);
1818655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0);
1828655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0);
1838655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF);
1848655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF);
1858655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF);
1868655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA);
1878655b6f8Swdenk lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF);
1888655b6f8Swdenk #endif
1898655b6f8Swdenk
1906d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #ifndef CONFIG_SYS_WHITE_ON_BLACK
1918655b6f8Swdenk lcd_setfgcolor(CONSOLE_COLOR_BLACK);
1928655b6f8Swdenk lcd_setbgcolor(CONSOLE_COLOR_WHITE);
1934d03634eSNikita Kiryanov bg_color = CONSOLE_COLOR_WHITE;
1948655b6f8Swdenk #else
1958655b6f8Swdenk lcd_setfgcolor(CONSOLE_COLOR_WHITE);
1968655b6f8Swdenk lcd_setbgcolor(CONSOLE_COLOR_BLACK);
1974d03634eSNikita Kiryanov bg_color = CONSOLE_COLOR_BLACK;
1986d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_WHITE_ON_BLACK */
1998655b6f8Swdenk
2008655b6f8Swdenk #ifdef LCD_TEST_PATTERN
2018655b6f8Swdenk test_pattern();
2028655b6f8Swdenk #else
2038655b6f8Swdenk /* set framebuffer to background color */
20457d76a89SHannes Petermaier #if (LCD_BPP != LCD_COLOR32)
2054d03634eSNikita Kiryanov memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row);
20657d76a89SHannes Petermaier #else
20757d76a89SHannes Petermaier u32 *ppix = lcd_base;
20857d76a89SHannes Petermaier u32 i;
20957d76a89SHannes Petermaier for (i = 0;
21057d76a89SHannes Petermaier i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix);
21157d76a89SHannes Petermaier i++) {
2124d03634eSNikita Kiryanov *ppix++ = bg_color;
21357d76a89SHannes Petermaier }
21457d76a89SHannes Petermaier #endif
2158655b6f8Swdenk #endif
216604c7d4aSHannes Petermaier /* setup text-console */
217604c7d4aSHannes Petermaier debug("[LCD] setting up console...\n");
218604c7d4aSHannes Petermaier lcd_init_console(lcd_base,
219604c7d4aSHannes Petermaier panel_info.vl_col,
220604c7d4aSHannes Petermaier panel_info.vl_row,
221604c7d4aSHannes Petermaier panel_info.vl_rot);
2228655b6f8Swdenk /* Paint the logo and retrieve LCD base address */
2238655b6f8Swdenk debug("[LCD] Drawing the logo...\n");
2247bf71d1fSNikita Kiryanov if (do_splash) {
22500caae6dSSimon Glass s = env_get("splashimage");
2267bf71d1fSNikita Kiryanov if (s) {
2277bf71d1fSNikita Kiryanov do_splash = 0;
2287bf71d1fSNikita Kiryanov addr = simple_strtoul(s, NULL, 16);
2297bf71d1fSNikita Kiryanov if (lcd_splash(addr) == 0) {
2307bf71d1fSNikita Kiryanov lcd_sync();
2317bf71d1fSNikita Kiryanov return;
2327bf71d1fSNikita Kiryanov }
2337bf71d1fSNikita Kiryanov }
2347bf71d1fSNikita Kiryanov }
2357bf71d1fSNikita Kiryanov
2367bf71d1fSNikita Kiryanov lcd_logo();
2377bf71d1fSNikita Kiryanov #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
2387bf71d1fSNikita Kiryanov addr = (ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length;
2393b96b909SMarcel Ziswiler lcd_init_console((void *)addr, panel_info.vl_col,
2403b96b909SMarcel Ziswiler panel_info.vl_row, panel_info.vl_rot);
2417bf71d1fSNikita Kiryanov #endif
2429a8efc46SSimon Glass lcd_sync();
2439a8efc46SSimon Glass }
2449a8efc46SSimon Glass
lcd_init(void * lcdbase)2458655b6f8Swdenk static int lcd_init(void *lcdbase)
2468655b6f8Swdenk {
2478655b6f8Swdenk debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
2488655b6f8Swdenk lcd_ctrl_init(lcdbase);
2491d3dea12SAnatolij Gustschin
2501d3dea12SAnatolij Gustschin /*
2519316e144SStephen Warren * lcd_ctrl_init() of some drivers (i.e. bcm2835 on rpi) ignores
2521d3dea12SAnatolij Gustschin * the 'lcdbase' argument and uses custom lcd base address
2531d3dea12SAnatolij Gustschin * by setting up gd->fb_base. Check for this condition and fixup
2541d3dea12SAnatolij Gustschin * 'lcd_base' address.
2551d3dea12SAnatolij Gustschin */
2567d95f2a3SSimon Glass if (map_to_sysmem(lcdbase) != gd->fb_base)
2577d95f2a3SSimon Glass lcd_base = map_sysmem(gd->fb_base, 0);
2581d3dea12SAnatolij Gustschin
2591d3dea12SAnatolij Gustschin debug("[LCD] Using LCD frambuffer at %p\n", lcd_base);
2601d3dea12SAnatolij Gustschin
2616d330719SStephen Warren lcd_get_size(&lcd_line_length);
2626f93d2b8SHaavard Skinnemoen lcd_is_enabled = 1;
26302110903SChe-Liang Chiou lcd_clear();
2648655b6f8Swdenk lcd_enable();
2658655b6f8Swdenk
2668655b6f8Swdenk /* Initialize the console */
267140beb94SNikita Kiryanov lcd_set_col(0);
26888804d19Swdenk #ifdef CONFIG_LCD_INFO_BELOW_LOGO
269140beb94SNikita Kiryanov lcd_set_row(7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT);
2708655b6f8Swdenk #else
271140beb94SNikita Kiryanov lcd_set_row(1); /* leave 1 blank line below logo */
2728655b6f8Swdenk #endif
2738655b6f8Swdenk
2748655b6f8Swdenk return 0;
2758655b6f8Swdenk }
2768655b6f8Swdenk
2778655b6f8Swdenk /*
2788655b6f8Swdenk * This is called early in the system initialization to grab memory
2798655b6f8Swdenk * for the LCD controller.
2808655b6f8Swdenk * Returns new address for monitor, after reserving LCD buffer memory
2818655b6f8Swdenk *
2828655b6f8Swdenk * Note that this is running from ROM, so no write access to global data.
2838655b6f8Swdenk */
lcd_setmem(ulong addr)2848655b6f8Swdenk ulong lcd_setmem(ulong addr)
2858655b6f8Swdenk {
2868655b6f8Swdenk ulong size;
287676d319eSSimon Glass int line_length;
2888655b6f8Swdenk
2898f47d917SNikita Kiryanov debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,
2908f47d917SNikita Kiryanov panel_info.vl_row, NBITS(panel_info.vl_bpix));
2918655b6f8Swdenk
292676d319eSSimon Glass size = lcd_get_size(&line_length);
2938655b6f8Swdenk
294676d319eSSimon Glass /* Round up to nearest full page, or MMU section if defined */
295676d319eSSimon Glass size = ALIGN(size, CONFIG_LCD_ALIGNMENT);
296676d319eSSimon Glass addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT);
2978655b6f8Swdenk
2988655b6f8Swdenk /* Allocate pages for the frame buffer. */
2998655b6f8Swdenk addr -= size;
3008655b6f8Swdenk
3016b035141SJeroen Hofstee debug("Reserving %ldk for LCD Framebuffer at: %08lx\n",
3026b035141SJeroen Hofstee size >> 10, addr);
3038655b6f8Swdenk
3048f47d917SNikita Kiryanov return addr;
3058655b6f8Swdenk }
3068655b6f8Swdenk
lcd_setfgcolor(int color)3078655b6f8Swdenk static void lcd_setfgcolor(int color)
3088655b6f8Swdenk {
30939cf4804SStelian Pop lcd_color_fg = color;
3108655b6f8Swdenk }
3118655b6f8Swdenk
lcd_getfgcolor(void)3124d03634eSNikita Kiryanov int lcd_getfgcolor(void)
3134d03634eSNikita Kiryanov {
3144d03634eSNikita Kiryanov return lcd_color_fg;
3154d03634eSNikita Kiryanov }
3164d03634eSNikita Kiryanov
lcd_setbgcolor(int color)3178655b6f8Swdenk static void lcd_setbgcolor(int color)
3188655b6f8Swdenk {
31939cf4804SStelian Pop lcd_color_bg = color;
3208655b6f8Swdenk }
3218655b6f8Swdenk
lcd_getbgcolor(void)3224d03634eSNikita Kiryanov int lcd_getbgcolor(void)
3234d03634eSNikita Kiryanov {
3244d03634eSNikita Kiryanov return lcd_color_bg;
3254d03634eSNikita Kiryanov }
3264d03634eSNikita Kiryanov
3278655b6f8Swdenk #ifdef CONFIG_LCD_LOGO
lcd_logo_set_cmap(void)328a02e9481SNikita Kiryanov __weak void lcd_logo_set_cmap(void)
329a02e9481SNikita Kiryanov {
3302306457cSNikita Kiryanov int i;
3312306457cSNikita Kiryanov ushort *cmap = configuration_get_cmap();
3322306457cSNikita Kiryanov
3332306457cSNikita Kiryanov for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i)
3342306457cSNikita Kiryanov *cmap++ = bmp_logo_palette[i];
335a02e9481SNikita Kiryanov }
336a02e9481SNikita Kiryanov
lcd_logo_plot(int x,int y)337bf21a5deSNikita Kiryanov void lcd_logo_plot(int x, int y)
3388655b6f8Swdenk {
3398655b6f8Swdenk ushort i, j;
340c8d2febcSNikita Kiryanov uchar *bmap = &bmp_logo_bitmap[0];
341317461c1SAndre Renaud unsigned bpix = NBITS(panel_info.vl_bpix);
342c8d2febcSNikita Kiryanov uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8);
343c8d2febcSNikita Kiryanov ushort *fb16;
3448655b6f8Swdenk
3452306457cSNikita Kiryanov debug("Logo: width %d height %d colors %d\n",
3462306457cSNikita Kiryanov BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS);
3478655b6f8Swdenk
348317461c1SAndre Renaud if (bpix < 12) {
3498655b6f8Swdenk WATCHDOG_RESET();
350a02e9481SNikita Kiryanov lcd_logo_set_cmap();
3518655b6f8Swdenk WATCHDOG_RESET();
3528655b6f8Swdenk
3538655b6f8Swdenk for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
3548655b6f8Swdenk memcpy(fb, bmap, BMP_LOGO_WIDTH);
3558655b6f8Swdenk bmap += BMP_LOGO_WIDTH;
3568655b6f8Swdenk fb += panel_info.vl_col;
3578655b6f8Swdenk }
3588655b6f8Swdenk }
3598655b6f8Swdenk else { /* true color mode */
360acb13868SAlessandro Rubini u16 col16;
361317461c1SAndre Renaud fb16 = (ushort *)fb;
3628655b6f8Swdenk for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
3638655b6f8Swdenk for (j = 0; j < BMP_LOGO_WIDTH; j++) {
364acb13868SAlessandro Rubini col16 = bmp_logo_palette[(bmap[j]-16)];
365acb13868SAlessandro Rubini fb16[j] =
366acb13868SAlessandro Rubini ((col16 & 0x000F) << 1) |
367acb13868SAlessandro Rubini ((col16 & 0x00F0) << 3) |
368acb13868SAlessandro Rubini ((col16 & 0x0F00) << 4);
3698655b6f8Swdenk }
3708655b6f8Swdenk bmap += BMP_LOGO_WIDTH;
3718655b6f8Swdenk fb16 += panel_info.vl_col;
3728655b6f8Swdenk }
3738655b6f8Swdenk }
3748655b6f8Swdenk
3758655b6f8Swdenk WATCHDOG_RESET();
3769a8efc46SSimon Glass lcd_sync();
3778655b6f8Swdenk }
3782b5cb3d3SAnatolij Gustschin #else
lcd_logo_plot(int x,int y)379bf21a5deSNikita Kiryanov static inline void lcd_logo_plot(int x, int y) {}
3808655b6f8Swdenk #endif /* CONFIG_LCD_LOGO */
3818655b6f8Swdenk
382c3517f91SJon Loeliger #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
3831ca298ceSMatthias Weisser #ifdef CONFIG_SPLASH_SCREEN_ALIGN
3847c7e280aSNikita Kiryanov
splash_align_axis(int * axis,unsigned long panel_size,unsigned long picture_size)3857c7e280aSNikita Kiryanov static void splash_align_axis(int *axis, unsigned long panel_size,
3867c7e280aSNikita Kiryanov unsigned long picture_size)
3877c7e280aSNikita Kiryanov {
3887c7e280aSNikita Kiryanov unsigned long panel_picture_delta = panel_size - picture_size;
3897c7e280aSNikita Kiryanov unsigned long axis_alignment;
3907c7e280aSNikita Kiryanov
3917c7e280aSNikita Kiryanov if (*axis == BMP_ALIGN_CENTER)
3927c7e280aSNikita Kiryanov axis_alignment = panel_picture_delta / 2;
3937c7e280aSNikita Kiryanov else if (*axis < 0)
3947c7e280aSNikita Kiryanov axis_alignment = panel_picture_delta + *axis + 1;
3957c7e280aSNikita Kiryanov else
3967c7e280aSNikita Kiryanov return;
3977c7e280aSNikita Kiryanov
398b4141195SMasahiro Yamada *axis = max(0, (int)axis_alignment);
3997c7e280aSNikita Kiryanov }
4001ca298ceSMatthias Weisser #endif
4011ca298ceSMatthias Weisser
40245d7f525STom Wai-Hong Tam #ifdef CONFIG_LCD_BMP_RLE8
40345d7f525STom Wai-Hong Tam #define BMP_RLE8_ESCAPE 0
40445d7f525STom Wai-Hong Tam #define BMP_RLE8_EOL 0
40545d7f525STom Wai-Hong Tam #define BMP_RLE8_EOBMP 1
40645d7f525STom Wai-Hong Tam #define BMP_RLE8_DELTA 2
40745d7f525STom Wai-Hong Tam
draw_unencoded_bitmap(ushort ** fbp,uchar * bmap,ushort * cmap,int cnt)40845d7f525STom Wai-Hong Tam static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap,
40945d7f525STom Wai-Hong Tam int cnt)
41045d7f525STom Wai-Hong Tam {
41145d7f525STom Wai-Hong Tam while (cnt > 0) {
41245d7f525STom Wai-Hong Tam *(*fbp)++ = cmap[*bmap++];
41345d7f525STom Wai-Hong Tam cnt--;
41445d7f525STom Wai-Hong Tam }
41545d7f525STom Wai-Hong Tam }
41645d7f525STom Wai-Hong Tam
draw_encoded_bitmap(ushort ** fbp,ushort c,int cnt)41745d7f525STom Wai-Hong Tam static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt)
41845d7f525STom Wai-Hong Tam {
41945d7f525STom Wai-Hong Tam ushort *fb = *fbp;
42045d7f525STom Wai-Hong Tam int cnt_8copy = cnt >> 3;
42145d7f525STom Wai-Hong Tam
42245d7f525STom Wai-Hong Tam cnt -= cnt_8copy << 3;
42345d7f525STom Wai-Hong Tam while (cnt_8copy > 0) {
42445d7f525STom Wai-Hong Tam *fb++ = c;
42545d7f525STom Wai-Hong Tam *fb++ = c;
42645d7f525STom Wai-Hong Tam *fb++ = c;
42745d7f525STom Wai-Hong Tam *fb++ = c;
42845d7f525STom Wai-Hong Tam *fb++ = c;
42945d7f525STom Wai-Hong Tam *fb++ = c;
43045d7f525STom Wai-Hong Tam *fb++ = c;
43145d7f525STom Wai-Hong Tam *fb++ = c;
43245d7f525STom Wai-Hong Tam cnt_8copy--;
43345d7f525STom Wai-Hong Tam }
43445d7f525STom Wai-Hong Tam while (cnt > 0) {
43545d7f525STom Wai-Hong Tam *fb++ = c;
43645d7f525STom Wai-Hong Tam cnt--;
43745d7f525STom Wai-Hong Tam }
4386b035141SJeroen Hofstee *fbp = fb;
43945d7f525STom Wai-Hong Tam }
44045d7f525STom Wai-Hong Tam
44145d7f525STom Wai-Hong Tam /*
4426b035141SJeroen Hofstee * Do not call this function directly, must be called from lcd_display_bitmap.
44345d7f525STom Wai-Hong Tam */
lcd_display_rle8_bitmap(struct bmp_image * bmp,ushort * cmap,uchar * fb,int x_off,int y_off)4441c3dbe56SSimon Glass static void lcd_display_rle8_bitmap(struct bmp_image *bmp, ushort *cmap,
4451c3dbe56SSimon Glass uchar *fb, int x_off, int y_off)
44645d7f525STom Wai-Hong Tam {
44745d7f525STom Wai-Hong Tam uchar *bmap;
44845d7f525STom Wai-Hong Tam ulong width, height;
44945d7f525STom Wai-Hong Tam ulong cnt, runlen;
45045d7f525STom Wai-Hong Tam int x, y;
45145d7f525STom Wai-Hong Tam int decode = 1;
45245d7f525STom Wai-Hong Tam
453dca2a1c1SPrzemyslaw Marczak width = get_unaligned_le32(&bmp->header.width);
454dca2a1c1SPrzemyslaw Marczak height = get_unaligned_le32(&bmp->header.height);
455dca2a1c1SPrzemyslaw Marczak bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
45645d7f525STom Wai-Hong Tam
45745d7f525STom Wai-Hong Tam x = 0;
45845d7f525STom Wai-Hong Tam y = height - 1;
45945d7f525STom Wai-Hong Tam
46045d7f525STom Wai-Hong Tam while (decode) {
46145d7f525STom Wai-Hong Tam if (bmap[0] == BMP_RLE8_ESCAPE) {
46245d7f525STom Wai-Hong Tam switch (bmap[1]) {
46345d7f525STom Wai-Hong Tam case BMP_RLE8_EOL:
46445d7f525STom Wai-Hong Tam /* end of line */
46545d7f525STom Wai-Hong Tam bmap += 2;
46645d7f525STom Wai-Hong Tam x = 0;
46745d7f525STom Wai-Hong Tam y--;
46845d7f525STom Wai-Hong Tam /* 16bpix, 2-byte per pixel, width should *2 */
46945d7f525STom Wai-Hong Tam fb -= (width * 2 + lcd_line_length);
47045d7f525STom Wai-Hong Tam break;
47145d7f525STom Wai-Hong Tam case BMP_RLE8_EOBMP:
47245d7f525STom Wai-Hong Tam /* end of bitmap */
47345d7f525STom Wai-Hong Tam decode = 0;
47445d7f525STom Wai-Hong Tam break;
47545d7f525STom Wai-Hong Tam case BMP_RLE8_DELTA:
47645d7f525STom Wai-Hong Tam /* delta run */
47745d7f525STom Wai-Hong Tam x += bmap[2];
47845d7f525STom Wai-Hong Tam y -= bmap[3];
47945d7f525STom Wai-Hong Tam /* 16bpix, 2-byte per pixel, x should *2 */
48045d7f525STom Wai-Hong Tam fb = (uchar *) (lcd_base + (y + y_off - 1)
48145d7f525STom Wai-Hong Tam * lcd_line_length + (x + x_off) * 2);
48245d7f525STom Wai-Hong Tam bmap += 4;
48345d7f525STom Wai-Hong Tam break;
48445d7f525STom Wai-Hong Tam default:
48545d7f525STom Wai-Hong Tam /* unencoded run */
48645d7f525STom Wai-Hong Tam runlen = bmap[1];
48745d7f525STom Wai-Hong Tam bmap += 2;
48845d7f525STom Wai-Hong Tam if (y < height) {
48945d7f525STom Wai-Hong Tam if (x < width) {
49045d7f525STom Wai-Hong Tam if (x + runlen > width)
49145d7f525STom Wai-Hong Tam cnt = width - x;
49245d7f525STom Wai-Hong Tam else
49345d7f525STom Wai-Hong Tam cnt = runlen;
49445d7f525STom Wai-Hong Tam draw_unencoded_bitmap(
49545d7f525STom Wai-Hong Tam (ushort **)&fb,
49645d7f525STom Wai-Hong Tam bmap, cmap, cnt);
49745d7f525STom Wai-Hong Tam }
49845d7f525STom Wai-Hong Tam x += runlen;
49945d7f525STom Wai-Hong Tam }
50045d7f525STom Wai-Hong Tam bmap += runlen;
50145d7f525STom Wai-Hong Tam if (runlen & 1)
50245d7f525STom Wai-Hong Tam bmap++;
50345d7f525STom Wai-Hong Tam }
50445d7f525STom Wai-Hong Tam } else {
50545d7f525STom Wai-Hong Tam /* encoded run */
50645d7f525STom Wai-Hong Tam if (y < height) {
50745d7f525STom Wai-Hong Tam runlen = bmap[0];
50845d7f525STom Wai-Hong Tam if (x < width) {
50945d7f525STom Wai-Hong Tam /* aggregate the same code */
51045d7f525STom Wai-Hong Tam while (bmap[0] == 0xff &&
51145d7f525STom Wai-Hong Tam bmap[2] != BMP_RLE8_ESCAPE &&
51245d7f525STom Wai-Hong Tam bmap[1] == bmap[3]) {
51345d7f525STom Wai-Hong Tam runlen += bmap[2];
51445d7f525STom Wai-Hong Tam bmap += 2;
51545d7f525STom Wai-Hong Tam }
51645d7f525STom Wai-Hong Tam if (x + runlen > width)
51745d7f525STom Wai-Hong Tam cnt = width - x;
51845d7f525STom Wai-Hong Tam else
51945d7f525STom Wai-Hong Tam cnt = runlen;
52045d7f525STom Wai-Hong Tam draw_encoded_bitmap((ushort **)&fb,
52145d7f525STom Wai-Hong Tam cmap[bmap[1]], cnt);
52245d7f525STom Wai-Hong Tam }
52345d7f525STom Wai-Hong Tam x += runlen;
52445d7f525STom Wai-Hong Tam }
52545d7f525STom Wai-Hong Tam bmap += 2;
52645d7f525STom Wai-Hong Tam }
52745d7f525STom Wai-Hong Tam }
52845d7f525STom Wai-Hong Tam }
52945d7f525STom Wai-Hong Tam #endif
53045d7f525STom Wai-Hong Tam
fb_put_byte(uchar ** fb,uchar ** from)53127fad01bSNikita Kiryanov __weak void fb_put_byte(uchar **fb, uchar **from)
53227fad01bSNikita Kiryanov {
53327fad01bSNikita Kiryanov *(*fb)++ = *(*from)++;
53427fad01bSNikita Kiryanov }
535bfdcc65eSNikita Kiryanov
536bfdcc65eSNikita Kiryanov #if defined(CONFIG_BMP_16BPP)
fb_put_word(uchar ** fb,uchar ** from)537b3d12e9bSNikita Kiryanov __weak void fb_put_word(uchar **fb, uchar **from)
538bfdcc65eSNikita Kiryanov {
539bfdcc65eSNikita Kiryanov *(*fb)++ = *(*from)++;
540bfdcc65eSNikita Kiryanov *(*fb)++ = *(*from)++;
541bfdcc65eSNikita Kiryanov }
542bfdcc65eSNikita Kiryanov #endif /* CONFIG_BMP_16BPP */
543bfdcc65eSNikita Kiryanov
lcd_set_cmap(struct bmp_image * bmp,unsigned colors)5441c3dbe56SSimon Glass __weak void lcd_set_cmap(struct bmp_image *bmp, unsigned colors)
5450b29a896SNikita Kiryanov {
5460b29a896SNikita Kiryanov int i;
5471c3dbe56SSimon Glass struct bmp_color_table_entry cte;
5480b29a896SNikita Kiryanov ushort *cmap = configuration_get_cmap();
5490b29a896SNikita Kiryanov
5500b29a896SNikita Kiryanov for (i = 0; i < colors; ++i) {
5510b29a896SNikita Kiryanov cte = bmp->color_table[i];
5520b29a896SNikita Kiryanov *cmap = (((cte.red) << 8) & 0xf800) |
5530b29a896SNikita Kiryanov (((cte.green) << 3) & 0x07e0) |
5540b29a896SNikita Kiryanov (((cte.blue) >> 3) & 0x001f);
5550b29a896SNikita Kiryanov cmap++;
5560b29a896SNikita Kiryanov }
5570b29a896SNikita Kiryanov }
5580b29a896SNikita Kiryanov
lcd_display_bitmap(ulong bmp_image,int x,int y)5598655b6f8Swdenk int lcd_display_bitmap(ulong bmp_image, int x, int y)
5608655b6f8Swdenk {
56100cc5595SAnatolij Gustschin ushort *cmap_base = NULL;
5628655b6f8Swdenk ushort i, j;
5638655b6f8Swdenk uchar *fb;
5641c3dbe56SSimon Glass struct bmp_image *bmp = (struct bmp_image *)map_sysmem(bmp_image, 0);
5658655b6f8Swdenk uchar *bmap;
566fecac46cSTom Wai-Hong Tam ushort padded_width;
567b245e65eSGuennadi Liakhovetski unsigned long width, height, byte_width;
568e8143e72SWolfgang Denk unsigned long pwidth = panel_info.vl_col;
569b245e65eSGuennadi Liakhovetski unsigned colors, bpix, bmp_bpix;
5708d379f17SSimon Glass int hdr_size;
571021414a3Sxypron.glpk@gmx.de struct bmp_color_table_entry *palette;
5728655b6f8Swdenk
5736b035141SJeroen Hofstee if (!bmp || !(bmp->header.signature[0] == 'B' &&
5746b035141SJeroen Hofstee bmp->header.signature[1] == 'M')) {
5758655b6f8Swdenk printf("Error: no valid bmp image at %lx\n", bmp_image);
5768f47d917SNikita Kiryanov
5778655b6f8Swdenk return 1;
5788655b6f8Swdenk }
5798655b6f8Swdenk
580021414a3Sxypron.glpk@gmx.de palette = bmp->color_table;
581dca2a1c1SPrzemyslaw Marczak width = get_unaligned_le32(&bmp->header.width);
582dca2a1c1SPrzemyslaw Marczak height = get_unaligned_le32(&bmp->header.height);
583dca2a1c1SPrzemyslaw Marczak bmp_bpix = get_unaligned_le16(&bmp->header.bit_count);
5848d379f17SSimon Glass hdr_size = get_unaligned_le16(&bmp->header.size);
5858d379f17SSimon Glass debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size, bmp_bpix);
586dca2a1c1SPrzemyslaw Marczak
587b245e65eSGuennadi Liakhovetski colors = 1 << bmp_bpix;
5888655b6f8Swdenk
5898655b6f8Swdenk bpix = NBITS(panel_info.vl_bpix);
5908655b6f8Swdenk
5916b035141SJeroen Hofstee if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) {
592b245e65eSGuennadi Liakhovetski printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
593b245e65eSGuennadi Liakhovetski bpix, bmp_bpix);
5948f47d917SNikita Kiryanov
5958655b6f8Swdenk return 1;
5968655b6f8Swdenk }
5978655b6f8Swdenk
598a305fb15SHannes Petermaier /*
599a305fb15SHannes Petermaier * We support displaying 8bpp BMPs on 16bpp LCDs
600a305fb15SHannes Petermaier * and displaying 24bpp BMPs on 32bpp LCDs
601a305fb15SHannes Petermaier * */
602a305fb15SHannes Petermaier if (bpix != bmp_bpix &&
603a305fb15SHannes Petermaier !(bmp_bpix == 8 && bpix == 16) &&
604a305fb15SHannes Petermaier !(bmp_bpix == 24 && bpix == 32)) {
6058655b6f8Swdenk printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
606dca2a1c1SPrzemyslaw Marczak bpix, get_unaligned_le16(&bmp->header.bit_count));
6078655b6f8Swdenk return 1;
6088655b6f8Swdenk }
6098655b6f8Swdenk
6108d379f17SSimon Glass debug("Display-bmp: %d x %d with %d colors, display %d\n",
6118d379f17SSimon Glass (int)width, (int)height, (int)colors, 1 << bpix);
6128655b6f8Swdenk
6130b29a896SNikita Kiryanov if (bmp_bpix == 8)
6140b29a896SNikita Kiryanov lcd_set_cmap(bmp, colors);
615e8143e72SWolfgang Denk
6166b035141SJeroen Hofstee padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width);
6171ca298ceSMatthias Weisser
6181ca298ceSMatthias Weisser #ifdef CONFIG_SPLASH_SCREEN_ALIGN
6197c7e280aSNikita Kiryanov splash_align_axis(&x, pwidth, width);
6207c7e280aSNikita Kiryanov splash_align_axis(&y, panel_info.vl_row, height);
6211ca298ceSMatthias Weisser #endif /* CONFIG_SPLASH_SCREEN_ALIGN */
6221ca298ceSMatthias Weisser
623e8143e72SWolfgang Denk if ((x + width) > pwidth)
624e8143e72SWolfgang Denk width = pwidth - x;
6258655b6f8Swdenk if ((y + height) > panel_info.vl_row)
6268655b6f8Swdenk height = panel_info.vl_row - y;
6278655b6f8Swdenk
628dca2a1c1SPrzemyslaw Marczak bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
6298655b6f8Swdenk fb = (uchar *)(lcd_base +
6308d46d5b1SLiu Ying (y + height - 1) * lcd_line_length + x * bpix / 8);
631a303dfb0SMark Jackson
632b245e65eSGuennadi Liakhovetski switch (bmp_bpix) {
633c8d2febcSNikita Kiryanov case 1:
6340156444cSSimon Glass case 8: {
6350b29a896SNikita Kiryanov cmap_base = configuration_get_cmap();
63645d7f525STom Wai-Hong Tam #ifdef CONFIG_LCD_BMP_RLE8
637dca2a1c1SPrzemyslaw Marczak u32 compression = get_unaligned_le32(&bmp->header.compression);
6388d379f17SSimon Glass debug("compressed %d %d\n", compression, BMP_BI_RLE8);
639dca2a1c1SPrzemyslaw Marczak if (compression == BMP_BI_RLE8) {
64045d7f525STom Wai-Hong Tam if (bpix != 16) {
64145d7f525STom Wai-Hong Tam /* TODO implement render code for bpix != 16 */
64245d7f525STom Wai-Hong Tam printf("Error: only support 16 bpix");
64345d7f525STom Wai-Hong Tam return 1;
64445d7f525STom Wai-Hong Tam }
64545d7f525STom Wai-Hong Tam lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y);
64645d7f525STom Wai-Hong Tam break;
64745d7f525STom Wai-Hong Tam }
64845d7f525STom Wai-Hong Tam #endif
64945d7f525STom Wai-Hong Tam
650b245e65eSGuennadi Liakhovetski if (bpix != 16)
651b245e65eSGuennadi Liakhovetski byte_width = width;
652b245e65eSGuennadi Liakhovetski else
653b245e65eSGuennadi Liakhovetski byte_width = width * 2;
654b245e65eSGuennadi Liakhovetski
6558655b6f8Swdenk for (i = 0; i < height; ++i) {
65651152c17Swdenk WATCHDOG_RESET();
657b245e65eSGuennadi Liakhovetski for (j = 0; j < width; j++) {
658b245e65eSGuennadi Liakhovetski if (bpix != 16) {
65927fad01bSNikita Kiryanov fb_put_byte(&fb, &bmap);
660b245e65eSGuennadi Liakhovetski } else {
6618d379f17SSimon Glass struct bmp_color_table_entry *entry;
6628d379f17SSimon Glass uint val;
6638d379f17SSimon Glass
6648d379f17SSimon Glass if (cmap_base) {
6658d379f17SSimon Glass val = cmap_base[*bmap];
6668d379f17SSimon Glass } else {
6678d379f17SSimon Glass entry = &palette[*bmap];
6688d379f17SSimon Glass val = entry->blue >> 3 |
6698d379f17SSimon Glass entry->green >> 2 << 5 |
6708d379f17SSimon Glass entry->red >> 3 << 11;
6718d379f17SSimon Glass }
6728d379f17SSimon Glass *(uint16_t *)fb = val;
6738d379f17SSimon Glass bmap++;
674b245e65eSGuennadi Liakhovetski fb += sizeof(uint16_t) / sizeof(*fb);
675b245e65eSGuennadi Liakhovetski }
676b245e65eSGuennadi Liakhovetski }
677fecac46cSTom Wai-Hong Tam bmap += (padded_width - width);
6786b035141SJeroen Hofstee fb -= byte_width + lcd_line_length;
6798655b6f8Swdenk }
680a303dfb0SMark Jackson break;
6810156444cSSimon Glass }
682a303dfb0SMark Jackson #if defined(CONFIG_BMP_16BPP)
683a303dfb0SMark Jackson case 16:
684a303dfb0SMark Jackson for (i = 0; i < height; ++i) {
685a303dfb0SMark Jackson WATCHDOG_RESET();
686bfdcc65eSNikita Kiryanov for (j = 0; j < width; j++)
687bfdcc65eSNikita Kiryanov fb_put_word(&fb, &bmap);
688bfdcc65eSNikita Kiryanov
689fecac46cSTom Wai-Hong Tam bmap += (padded_width - width) * 2;
6906b035141SJeroen Hofstee fb -= width * 2 + lcd_line_length;
691a303dfb0SMark Jackson }
692a303dfb0SMark Jackson break;
693a303dfb0SMark Jackson #endif /* CONFIG_BMP_16BPP */
69410ba6b33SPhilipp Tomsich #if defined(CONFIG_BMP_24BPP)
695a305fb15SHannes Petermaier case 24:
696a305fb15SHannes Petermaier for (i = 0; i < height; ++i) {
697a305fb15SHannes Petermaier for (j = 0; j < width; j++) {
698a305fb15SHannes Petermaier *(fb++) = *(bmap++);
699a305fb15SHannes Petermaier *(fb++) = *(bmap++);
700a305fb15SHannes Petermaier *(fb++) = *(bmap++);
701a305fb15SHannes Petermaier *(fb++) = 0;
702a305fb15SHannes Petermaier }
703a305fb15SHannes Petermaier fb -= lcd_line_length + width * (bpix / 8);
704a305fb15SHannes Petermaier }
705a305fb15SHannes Petermaier break;
70610ba6b33SPhilipp Tomsich #endif /* CONFIG_BMP_24BPP */
707fb6a9aabSDonghwa Lee #if defined(CONFIG_BMP_32BPP)
708fb6a9aabSDonghwa Lee case 32:
709fb6a9aabSDonghwa Lee for (i = 0; i < height; ++i) {
710fb6a9aabSDonghwa Lee for (j = 0; j < width; j++) {
711fb6a9aabSDonghwa Lee *(fb++) = *(bmap++);
712fb6a9aabSDonghwa Lee *(fb++) = *(bmap++);
713fb6a9aabSDonghwa Lee *(fb++) = *(bmap++);
714fb6a9aabSDonghwa Lee *(fb++) = *(bmap++);
715fb6a9aabSDonghwa Lee }
7166b035141SJeroen Hofstee fb -= lcd_line_length + width * (bpix / 8);
717fb6a9aabSDonghwa Lee }
718fb6a9aabSDonghwa Lee break;
719fb6a9aabSDonghwa Lee #endif /* CONFIG_BMP_32BPP */
720a303dfb0SMark Jackson default:
721a303dfb0SMark Jackson break;
722a303dfb0SMark Jackson };
7238655b6f8Swdenk
7249a8efc46SSimon Glass lcd_sync();
7258f47d917SNikita Kiryanov return 0;
7268655b6f8Swdenk }
727c3517f91SJon Loeliger #endif
7288655b6f8Swdenk
lcd_logo(void)7297bf71d1fSNikita Kiryanov static void lcd_logo(void)
7308655b6f8Swdenk {
731bf21a5deSNikita Kiryanov lcd_logo_plot(0, 0);
7328655b6f8Swdenk
73388804d19Swdenk #ifdef CONFIG_LCD_INFO
734140beb94SNikita Kiryanov lcd_set_col(LCD_INFO_X / VIDEO_FONT_WIDTH);
735140beb94SNikita Kiryanov lcd_set_row(LCD_INFO_Y / VIDEO_FONT_HEIGHT);
7366b59e03eSHaavard Skinnemoen lcd_show_board_info();
73788804d19Swdenk #endif /* CONFIG_LCD_INFO */
7388655b6f8Swdenk }
7398655b6f8Swdenk
740c0880485SNikita Kiryanov #ifdef CONFIG_SPLASHIMAGE_GUARD
on_splashimage(const char * name,const char * value,enum env_op op,int flags)741c0880485SNikita Kiryanov static int on_splashimage(const char *name, const char *value, enum env_op op,
742c0880485SNikita Kiryanov int flags)
743c0880485SNikita Kiryanov {
744c0880485SNikita Kiryanov ulong addr;
745c0880485SNikita Kiryanov int aligned;
746c0880485SNikita Kiryanov
747c0880485SNikita Kiryanov if (op == env_op_delete)
748c0880485SNikita Kiryanov return 0;
749c0880485SNikita Kiryanov
750c0880485SNikita Kiryanov addr = simple_strtoul(value, NULL, 16);
751c0880485SNikita Kiryanov /* See README.displaying-bmps */
752c0880485SNikita Kiryanov aligned = (addr % 4 == 2);
753c0880485SNikita Kiryanov if (!aligned) {
754c0880485SNikita Kiryanov printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n");
755c0880485SNikita Kiryanov return -1;
756c0880485SNikita Kiryanov }
757c0880485SNikita Kiryanov
758c0880485SNikita Kiryanov return 0;
759c0880485SNikita Kiryanov }
760c0880485SNikita Kiryanov
761c0880485SNikita Kiryanov U_BOOT_ENV_CALLBACK(splashimage, on_splashimage);
762c0880485SNikita Kiryanov #endif
763c0880485SNikita Kiryanov
lcd_get_pixel_width(void)764395166cfSVadim Bendebury int lcd_get_pixel_width(void)
765395166cfSVadim Bendebury {
766395166cfSVadim Bendebury return panel_info.vl_col;
767395166cfSVadim Bendebury }
768395166cfSVadim Bendebury
lcd_get_pixel_height(void)769395166cfSVadim Bendebury int lcd_get_pixel_height(void)
770395166cfSVadim Bendebury {
771395166cfSVadim Bendebury return panel_info.vl_row;
772395166cfSVadim Bendebury }
773