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