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