mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
781 lines
18 KiB
781 lines
18 KiB
// SPDX-License-Identifier: GPL-2.0+ |
|
/* |
|
* Common LCD routines |
|
* |
|
* (C) Copyright 2001-2002 |
|
* Wolfgang Denk, DENX Software Engineering -- [email protected] |
|
*/ |
|
|
|
/* #define DEBUG */ |
|
#include <config.h> |
|
#include <common.h> |
|
#include <command.h> |
|
#include <env_callback.h> |
|
#include <linux/types.h> |
|
#include <stdio_dev.h> |
|
#include <lcd.h> |
|
#include <mapmem.h> |
|
#include <watchdog.h> |
|
#include <asm/unaligned.h> |
|
#include <splash.h> |
|
#include <asm/io.h> |
|
#include <asm/unaligned.h> |
|
#include <video_font.h> |
|
|
|
#ifdef CONFIG_LCD_LOGO |
|
#include <bmp_logo.h> |
|
#include <bmp_logo_data.h> |
|
#if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16) |
|
#error Default Color Map overlaps with Logo Color Map |
|
#endif |
|
#endif |
|
|
|
#ifndef CONFIG_LCD_ALIGNMENT |
|
#define CONFIG_LCD_ALIGNMENT PAGE_SIZE |
|
#endif |
|
|
|
#if (LCD_BPP != LCD_COLOR8) && (LCD_BPP != LCD_COLOR16) && \ |
|
(LCD_BPP != LCD_COLOR32) |
|
#error Unsupported LCD BPP. |
|
#endif |
|
|
|
DECLARE_GLOBAL_DATA_PTR; |
|
|
|
static int lcd_init(void *lcdbase); |
|
static void lcd_logo(void); |
|
static void lcd_setfgcolor(int color); |
|
static void lcd_setbgcolor(int color); |
|
|
|
static int lcd_color_fg; |
|
static int lcd_color_bg; |
|
int lcd_line_length; |
|
char lcd_is_enabled = 0; |
|
static void *lcd_base; /* Start of framebuffer memory */ |
|
static char lcd_flush_dcache; /* 1 to flush dcache after each lcd update */ |
|
|
|
/* Flush LCD activity to the caches */ |
|
void lcd_sync(void) |
|
{ |
|
/* |
|
* flush_dcache_range() is declared in common.h but it seems that some |
|
* architectures do not actually implement it. Is there a way to find |
|
* out whether it exists? For now, ARM is safe. |
|
*/ |
|
#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF) |
|
int line_length; |
|
|
|
if (lcd_flush_dcache) |
|
flush_dcache_range((ulong)lcd_base, |
|
(ulong)(lcd_base + lcd_get_size(&line_length))); |
|
#endif |
|
} |
|
|
|
void lcd_set_flush_dcache(int flush) |
|
{ |
|
lcd_flush_dcache = (flush != 0); |
|
} |
|
|
|
static void lcd_stub_putc(struct stdio_dev *dev, const char c) |
|
{ |
|
lcd_putc(c); |
|
} |
|
|
|
static void lcd_stub_puts(struct stdio_dev *dev, const char *s) |
|
{ |
|
lcd_puts(s); |
|
} |
|
|
|
/* Small utility to check that you got the colours right */ |
|
#ifdef LCD_TEST_PATTERN |
|
|
|
#if LCD_BPP == LCD_COLOR8 |
|
#define N_BLK_VERT 2 |
|
#define N_BLK_HOR 3 |
|
|
|
static int test_colors[N_BLK_HOR * N_BLK_VERT] = { |
|
CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW, |
|
CONSOLE_COLOR_BLUE, CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN, |
|
}; /*LCD_BPP == LCD_COLOR8 */ |
|
|
|
#elif LCD_BPP == LCD_COLOR16 |
|
#define N_BLK_VERT 2 |
|
#define N_BLK_HOR 4 |
|
|
|
static int test_colors[N_BLK_HOR * N_BLK_VERT] = { |
|
CONSOLE_COLOR_RED, CONSOLE_COLOR_GREEN, CONSOLE_COLOR_YELLOW, CONSOLE_COLOR_BLUE, |
|
CONSOLE_COLOR_MAGENTA, CONSOLE_COLOR_CYAN, CONSOLE_COLOR_GREY, CONSOLE_COLOR_WHITE, |
|
}; |
|
#endif /*LCD_BPP == LCD_COLOR16 */ |
|
|
|
static void test_pattern(void) |
|
{ |
|
ushort v_max = panel_info.vl_row; |
|
ushort h_max = panel_info.vl_col; |
|
ushort v_step = (v_max + N_BLK_VERT - 1) / N_BLK_VERT; |
|
ushort h_step = (h_max + N_BLK_HOR - 1) / N_BLK_HOR; |
|
ushort v, h; |
|
#if LCD_BPP == LCD_COLOR8 |
|
uchar *pix = (uchar *)lcd_base; |
|
#elif LCD_BPP == LCD_COLOR16 |
|
ushort *pix = (ushort *)lcd_base; |
|
#endif |
|
|
|
printf("[LCD] Test Pattern: %d x %d [%d x %d]\n", |
|
h_max, v_max, h_step, v_step); |
|
|
|
for (v = 0; v < v_max; ++v) { |
|
uchar iy = v / v_step; |
|
for (h = 0; h < h_max; ++h) { |
|
uchar ix = N_BLK_HOR * iy + h / h_step; |
|
*pix++ = test_colors[ix]; |
|
} |
|
} |
|
} |
|
#endif /* LCD_TEST_PATTERN */ |
|
|
|
/* |
|
* With most lcd drivers the line length is set up |
|
* by calculating it from panel_info parameters. Some |
|
* drivers need to calculate the line length differently, |
|
* so make the function weak to allow overriding it. |
|
*/ |
|
__weak int lcd_get_size(int *line_length) |
|
{ |
|
*line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8; |
|
return *line_length * panel_info.vl_row; |
|
} |
|
|
|
int drv_lcd_init(void) |
|
{ |
|
struct stdio_dev lcddev; |
|
int rc; |
|
|
|
lcd_base = map_sysmem(gd->fb_base, 0); |
|
|
|
lcd_init(lcd_base); |
|
|
|
/* Device initialization */ |
|
memset(&lcddev, 0, sizeof(lcddev)); |
|
|
|
strcpy(lcddev.name, "lcd"); |
|
lcddev.ext = 0; /* No extensions */ |
|
lcddev.flags = DEV_FLAGS_OUTPUT; /* Output only */ |
|
lcddev.putc = lcd_stub_putc; /* 'putc' function */ |
|
lcddev.puts = lcd_stub_puts; /* 'puts' function */ |
|
|
|
rc = stdio_register(&lcddev); |
|
|
|
return (rc == 0) ? 1 : rc; |
|
} |
|
|
|
void lcd_clear(void) |
|
{ |
|
int bg_color; |
|
char *s; |
|
ulong addr; |
|
static int do_splash = 1; |
|
#if LCD_BPP == LCD_COLOR8 |
|
/* Setting the palette */ |
|
lcd_setcolreg(CONSOLE_COLOR_BLACK, 0, 0, 0); |
|
lcd_setcolreg(CONSOLE_COLOR_RED, 0xFF, 0, 0); |
|
lcd_setcolreg(CONSOLE_COLOR_GREEN, 0, 0xFF, 0); |
|
lcd_setcolreg(CONSOLE_COLOR_YELLOW, 0xFF, 0xFF, 0); |
|
lcd_setcolreg(CONSOLE_COLOR_BLUE, 0, 0, 0xFF); |
|
lcd_setcolreg(CONSOLE_COLOR_MAGENTA, 0xFF, 0, 0xFF); |
|
lcd_setcolreg(CONSOLE_COLOR_CYAN, 0, 0xFF, 0xFF); |
|
lcd_setcolreg(CONSOLE_COLOR_GREY, 0xAA, 0xAA, 0xAA); |
|
lcd_setcolreg(CONSOLE_COLOR_WHITE, 0xFF, 0xFF, 0xFF); |
|
#endif |
|
|
|
#ifndef CONFIG_SYS_WHITE_ON_BLACK |
|
lcd_setfgcolor(CONSOLE_COLOR_BLACK); |
|
lcd_setbgcolor(CONSOLE_COLOR_WHITE); |
|
bg_color = CONSOLE_COLOR_WHITE; |
|
#else |
|
lcd_setfgcolor(CONSOLE_COLOR_WHITE); |
|
lcd_setbgcolor(CONSOLE_COLOR_BLACK); |
|
bg_color = CONSOLE_COLOR_BLACK; |
|
#endif /* CONFIG_SYS_WHITE_ON_BLACK */ |
|
|
|
#ifdef LCD_TEST_PATTERN |
|
test_pattern(); |
|
#else |
|
/* set framebuffer to background color */ |
|
#if (LCD_BPP != LCD_COLOR32) |
|
memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row); |
|
#else |
|
u32 *ppix = lcd_base; |
|
u32 i; |
|
for (i = 0; |
|
i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix); |
|
i++) { |
|
*ppix++ = bg_color; |
|
} |
|
#endif |
|
#endif |
|
/* setup text-console */ |
|
debug("[LCD] setting up console...\n"); |
|
lcd_init_console(lcd_base, |
|
panel_info.vl_col, |
|
panel_info.vl_row, |
|
panel_info.vl_rot); |
|
/* Paint the logo and retrieve LCD base address */ |
|
debug("[LCD] Drawing the logo...\n"); |
|
if (do_splash) { |
|
s = env_get("splashimage"); |
|
if (s) { |
|
do_splash = 0; |
|
addr = simple_strtoul(s, NULL, 16); |
|
if (lcd_splash(addr) == 0) { |
|
lcd_sync(); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
lcd_logo(); |
|
#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO) |
|
addr = (ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length; |
|
lcd_init_console((void *)addr, panel_info.vl_col, |
|
panel_info.vl_row, panel_info.vl_rot); |
|
#endif |
|
lcd_sync(); |
|
} |
|
|
|
static int do_lcd_clear(cmd_tbl_t *cmdtp, int flag, int argc, |
|
char *const argv[]) |
|
{ |
|
lcd_clear(); |
|
return 0; |
|
} |
|
U_BOOT_CMD(cls, 1, 1, do_lcd_clear, "clear screen", ""); |
|
|
|
static int lcd_init(void *lcdbase) |
|
{ |
|
debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase); |
|
lcd_ctrl_init(lcdbase); |
|
|
|
/* |
|
* lcd_ctrl_init() of some drivers (i.e. bcm2835 on rpi) ignores |
|
* the 'lcdbase' argument and uses custom lcd base address |
|
* by setting up gd->fb_base. Check for this condition and fixup |
|
* 'lcd_base' address. |
|
*/ |
|
if (map_to_sysmem(lcdbase) != gd->fb_base) |
|
lcd_base = map_sysmem(gd->fb_base, 0); |
|
|
|
debug("[LCD] Using LCD frambuffer at %p\n", lcd_base); |
|
|
|
lcd_get_size(&lcd_line_length); |
|
lcd_is_enabled = 1; |
|
lcd_clear(); |
|
lcd_enable(); |
|
|
|
/* Initialize the console */ |
|
lcd_set_col(0); |
|
#ifdef CONFIG_LCD_INFO_BELOW_LOGO |
|
lcd_set_row(7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT); |
|
#else |
|
lcd_set_row(1); /* leave 1 blank line below logo */ |
|
#endif |
|
|
|
return 0; |
|
} |
|
|
|
/* |
|
* This is called early in the system initialization to grab memory |
|
* for the LCD controller. |
|
* Returns new address for monitor, after reserving LCD buffer memory |
|
* |
|
* Note that this is running from ROM, so no write access to global data. |
|
*/ |
|
ulong lcd_setmem(ulong addr) |
|
{ |
|
ulong size; |
|
int line_length; |
|
|
|
debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col, |
|
panel_info.vl_row, NBITS(panel_info.vl_bpix)); |
|
|
|
size = lcd_get_size(&line_length); |
|
|
|
/* Round up to nearest full page, or MMU section if defined */ |
|
size = ALIGN(size, CONFIG_LCD_ALIGNMENT); |
|
addr = ALIGN(addr - CONFIG_LCD_ALIGNMENT + 1, CONFIG_LCD_ALIGNMENT); |
|
|
|
/* Allocate pages for the frame buffer. */ |
|
addr -= size; |
|
|
|
debug("Reserving %ldk for LCD Framebuffer at: %08lx\n", |
|
size >> 10, addr); |
|
|
|
return addr; |
|
} |
|
|
|
static void lcd_setfgcolor(int color) |
|
{ |
|
lcd_color_fg = color; |
|
} |
|
|
|
int lcd_getfgcolor(void) |
|
{ |
|
return lcd_color_fg; |
|
} |
|
|
|
static void lcd_setbgcolor(int color) |
|
{ |
|
lcd_color_bg = color; |
|
} |
|
|
|
int lcd_getbgcolor(void) |
|
{ |
|
return lcd_color_bg; |
|
} |
|
|
|
#ifdef CONFIG_LCD_LOGO |
|
__weak void lcd_logo_set_cmap(void) |
|
{ |
|
int i; |
|
ushort *cmap = configuration_get_cmap(); |
|
|
|
for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i) |
|
*cmap++ = bmp_logo_palette[i]; |
|
} |
|
|
|
void lcd_logo_plot(int x, int y) |
|
{ |
|
ushort i, j; |
|
uchar *bmap = &bmp_logo_bitmap[0]; |
|
unsigned bpix = NBITS(panel_info.vl_bpix); |
|
uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8); |
|
ushort *fb16; |
|
|
|
debug("Logo: width %d height %d colors %d\n", |
|
BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS); |
|
|
|
if (bpix < 12) { |
|
WATCHDOG_RESET(); |
|
lcd_logo_set_cmap(); |
|
WATCHDOG_RESET(); |
|
|
|
for (i = 0; i < BMP_LOGO_HEIGHT; ++i) { |
|
memcpy(fb, bmap, BMP_LOGO_WIDTH); |
|
bmap += BMP_LOGO_WIDTH; |
|
fb += panel_info.vl_col; |
|
} |
|
} |
|
else { /* true color mode */ |
|
u16 col16; |
|
fb16 = (ushort *)fb; |
|
for (i = 0; i < BMP_LOGO_HEIGHT; ++i) { |
|
for (j = 0; j < BMP_LOGO_WIDTH; j++) { |
|
col16 = bmp_logo_palette[(bmap[j]-16)]; |
|
fb16[j] = |
|
((col16 & 0x000F) << 1) | |
|
((col16 & 0x00F0) << 3) | |
|
((col16 & 0x0F00) << 4); |
|
} |
|
bmap += BMP_LOGO_WIDTH; |
|
fb16 += panel_info.vl_col; |
|
} |
|
} |
|
|
|
WATCHDOG_RESET(); |
|
lcd_sync(); |
|
} |
|
#else |
|
static inline void lcd_logo_plot(int x, int y) {} |
|
#endif /* CONFIG_LCD_LOGO */ |
|
|
|
#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) |
|
#ifdef CONFIG_SPLASH_SCREEN_ALIGN |
|
#define BMP_ALIGN_CENTER 0x7FFF |
|
|
|
static void splash_align_axis(int *axis, unsigned long panel_size, |
|
unsigned long picture_size) |
|
{ |
|
unsigned long panel_picture_delta = panel_size - picture_size; |
|
unsigned long axis_alignment; |
|
|
|
if (*axis == BMP_ALIGN_CENTER) |
|
axis_alignment = panel_picture_delta / 2; |
|
else if (*axis < 0) |
|
axis_alignment = panel_picture_delta + *axis + 1; |
|
else |
|
return; |
|
|
|
*axis = max(0, (int)axis_alignment); |
|
} |
|
#endif |
|
|
|
#ifdef CONFIG_LCD_BMP_RLE8 |
|
#define BMP_RLE8_ESCAPE 0 |
|
#define BMP_RLE8_EOL 0 |
|
#define BMP_RLE8_EOBMP 1 |
|
#define BMP_RLE8_DELTA 2 |
|
|
|
static void draw_unencoded_bitmap(ushort **fbp, uchar *bmap, ushort *cmap, |
|
int cnt) |
|
{ |
|
while (cnt > 0) { |
|
*(*fbp)++ = cmap[*bmap++]; |
|
cnt--; |
|
} |
|
} |
|
|
|
static void draw_encoded_bitmap(ushort **fbp, ushort c, int cnt) |
|
{ |
|
ushort *fb = *fbp; |
|
int cnt_8copy = cnt >> 3; |
|
|
|
cnt -= cnt_8copy << 3; |
|
while (cnt_8copy > 0) { |
|
*fb++ = c; |
|
*fb++ = c; |
|
*fb++ = c; |
|
*fb++ = c; |
|
*fb++ = c; |
|
*fb++ = c; |
|
*fb++ = c; |
|
*fb++ = c; |
|
cnt_8copy--; |
|
} |
|
while (cnt > 0) { |
|
*fb++ = c; |
|
cnt--; |
|
} |
|
*fbp = fb; |
|
} |
|
|
|
/* |
|
* Do not call this function directly, must be called from lcd_display_bitmap. |
|
*/ |
|
static void lcd_display_rle8_bitmap(struct bmp_image *bmp, ushort *cmap, |
|
uchar *fb, int x_off, int y_off) |
|
{ |
|
uchar *bmap; |
|
ulong width, height; |
|
ulong cnt, runlen; |
|
int x, y; |
|
int decode = 1; |
|
|
|
width = get_unaligned_le32(&bmp->header.width); |
|
height = get_unaligned_le32(&bmp->header.height); |
|
bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset); |
|
|
|
x = 0; |
|
y = height - 1; |
|
|
|
while (decode) { |
|
if (bmap[0] == BMP_RLE8_ESCAPE) { |
|
switch (bmap[1]) { |
|
case BMP_RLE8_EOL: |
|
/* end of line */ |
|
bmap += 2; |
|
x = 0; |
|
y--; |
|
/* 16bpix, 2-byte per pixel, width should *2 */ |
|
fb -= (width * 2 + lcd_line_length); |
|
break; |
|
case BMP_RLE8_EOBMP: |
|
/* end of bitmap */ |
|
decode = 0; |
|
break; |
|
case BMP_RLE8_DELTA: |
|
/* delta run */ |
|
x += bmap[2]; |
|
y -= bmap[3]; |
|
/* 16bpix, 2-byte per pixel, x should *2 */ |
|
fb = (uchar *) (lcd_base + (y + y_off - 1) |
|
* lcd_line_length + (x + x_off) * 2); |
|
bmap += 4; |
|
break; |
|
default: |
|
/* unencoded run */ |
|
runlen = bmap[1]; |
|
bmap += 2; |
|
if (y < height) { |
|
if (x < width) { |
|
if (x + runlen > width) |
|
cnt = width - x; |
|
else |
|
cnt = runlen; |
|
draw_unencoded_bitmap( |
|
(ushort **)&fb, |
|
bmap, cmap, cnt); |
|
} |
|
x += runlen; |
|
} |
|
bmap += runlen; |
|
if (runlen & 1) |
|
bmap++; |
|
} |
|
} else { |
|
/* encoded run */ |
|
if (y < height) { |
|
runlen = bmap[0]; |
|
if (x < width) { |
|
/* aggregate the same code */ |
|
while (bmap[0] == 0xff && |
|
bmap[2] != BMP_RLE8_ESCAPE && |
|
bmap[1] == bmap[3]) { |
|
runlen += bmap[2]; |
|
bmap += 2; |
|
} |
|
if (x + runlen > width) |
|
cnt = width - x; |
|
else |
|
cnt = runlen; |
|
draw_encoded_bitmap((ushort **)&fb, |
|
cmap[bmap[1]], cnt); |
|
} |
|
x += runlen; |
|
} |
|
bmap += 2; |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
__weak void fb_put_byte(uchar **fb, uchar **from) |
|
{ |
|
*(*fb)++ = *(*from)++; |
|
} |
|
|
|
#if defined(CONFIG_BMP_16BPP) |
|
__weak void fb_put_word(uchar **fb, uchar **from) |
|
{ |
|
*(*fb)++ = *(*from)++; |
|
*(*fb)++ = *(*from)++; |
|
} |
|
#endif /* CONFIG_BMP_16BPP */ |
|
|
|
__weak void lcd_set_cmap(struct bmp_image *bmp, unsigned colors) |
|
{ |
|
int i; |
|
struct bmp_color_table_entry cte; |
|
ushort *cmap = configuration_get_cmap(); |
|
|
|
for (i = 0; i < colors; ++i) { |
|
cte = bmp->color_table[i]; |
|
*cmap = (((cte.red) << 8) & 0xf800) | |
|
(((cte.green) << 3) & 0x07e0) | |
|
(((cte.blue) >> 3) & 0x001f); |
|
cmap++; |
|
} |
|
} |
|
|
|
int lcd_display_bitmap(ulong bmp_image, int x, int y) |
|
{ |
|
ushort *cmap_base = NULL; |
|
ushort i, j; |
|
uchar *fb; |
|
struct bmp_image *bmp = (struct bmp_image *)map_sysmem(bmp_image, 0); |
|
uchar *bmap; |
|
ushort padded_width; |
|
unsigned long width, height, byte_width; |
|
unsigned long pwidth = panel_info.vl_col; |
|
unsigned colors, bpix, bmp_bpix; |
|
int hdr_size; |
|
struct bmp_color_table_entry *palette; |
|
|
|
if (!bmp || !(bmp->header.signature[0] == 'B' && |
|
bmp->header.signature[1] == 'M')) { |
|
printf("Error: no valid bmp image at %lx\n", bmp_image); |
|
|
|
return 1; |
|
} |
|
|
|
palette = bmp->color_table; |
|
width = get_unaligned_le32(&bmp->header.width); |
|
height = get_unaligned_le32(&bmp->header.height); |
|
bmp_bpix = get_unaligned_le16(&bmp->header.bit_count); |
|
hdr_size = get_unaligned_le16(&bmp->header.size); |
|
debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size, bmp_bpix); |
|
|
|
colors = 1 << bmp_bpix; |
|
|
|
bpix = NBITS(panel_info.vl_bpix); |
|
|
|
if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) { |
|
printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n", |
|
bpix, bmp_bpix); |
|
|
|
return 1; |
|
} |
|
|
|
/* |
|
* We support displaying 8bpp BMPs on 16bpp LCDs |
|
* and displaying 24bpp BMPs on 32bpp LCDs |
|
* */ |
|
if (bpix != bmp_bpix && |
|
!(bmp_bpix == 8 && bpix == 16) && |
|
!(bmp_bpix == 24 && bpix == 32)) { |
|
printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n", |
|
bpix, get_unaligned_le16(&bmp->header.bit_count)); |
|
return 1; |
|
} |
|
|
|
debug("Display-bmp: %d x %d with %d colors, display %d\n", |
|
(int)width, (int)height, (int)colors, 1 << bpix); |
|
|
|
if (bmp_bpix == 8) |
|
lcd_set_cmap(bmp, colors); |
|
|
|
padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width); |
|
|
|
#ifdef CONFIG_SPLASH_SCREEN_ALIGN |
|
splash_align_axis(&x, pwidth, width); |
|
splash_align_axis(&y, panel_info.vl_row, height); |
|
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ |
|
|
|
if ((x + width) > pwidth) |
|
width = pwidth - x; |
|
if ((y + height) > panel_info.vl_row) |
|
height = panel_info.vl_row - y; |
|
|
|
bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset); |
|
fb = (uchar *)(lcd_base + |
|
(y + height - 1) * lcd_line_length + x * bpix / 8); |
|
|
|
switch (bmp_bpix) { |
|
case 1: |
|
case 8: { |
|
cmap_base = configuration_get_cmap(); |
|
#ifdef CONFIG_LCD_BMP_RLE8 |
|
u32 compression = get_unaligned_le32(&bmp->header.compression); |
|
debug("compressed %d %d\n", compression, BMP_BI_RLE8); |
|
if (compression == BMP_BI_RLE8) { |
|
if (bpix != 16) { |
|
/* TODO implement render code for bpix != 16 */ |
|
printf("Error: only support 16 bpix"); |
|
return 1; |
|
} |
|
lcd_display_rle8_bitmap(bmp, cmap_base, fb, x, y); |
|
break; |
|
} |
|
#endif |
|
|
|
if (bpix != 16) |
|
byte_width = width; |
|
else |
|
byte_width = width * 2; |
|
|
|
for (i = 0; i < height; ++i) { |
|
WATCHDOG_RESET(); |
|
for (j = 0; j < width; j++) { |
|
if (bpix != 16) { |
|
fb_put_byte(&fb, &bmap); |
|
} else { |
|
struct bmp_color_table_entry *entry; |
|
uint val; |
|
|
|
if (cmap_base) { |
|
val = cmap_base[*bmap]; |
|
} else { |
|
entry = &palette[*bmap]; |
|
val = entry->blue >> 3 | |
|
entry->green >> 2 << 5 | |
|
entry->red >> 3 << 11; |
|
} |
|
*(uint16_t *)fb = val; |
|
bmap++; |
|
fb += sizeof(uint16_t) / sizeof(*fb); |
|
} |
|
} |
|
bmap += (padded_width - width); |
|
fb -= byte_width + lcd_line_length; |
|
} |
|
break; |
|
} |
|
#if defined(CONFIG_BMP_16BPP) |
|
case 16: |
|
for (i = 0; i < height; ++i) { |
|
WATCHDOG_RESET(); |
|
for (j = 0; j < width; j++) |
|
fb_put_word(&fb, &bmap); |
|
|
|
bmap += (padded_width - width) * 2; |
|
fb -= width * 2 + lcd_line_length; |
|
} |
|
break; |
|
#endif /* CONFIG_BMP_16BPP */ |
|
#if defined(CONFIG_BMP_24BPP) |
|
case 24: |
|
for (i = 0; i < height; ++i) { |
|
for (j = 0; j < width; j++) { |
|
*(fb++) = *(bmap++); |
|
*(fb++) = *(bmap++); |
|
*(fb++) = *(bmap++); |
|
*(fb++) = 0; |
|
} |
|
fb -= lcd_line_length + width * (bpix / 8); |
|
} |
|
break; |
|
#endif /* CONFIG_BMP_24BPP */ |
|
#if defined(CONFIG_BMP_32BPP) |
|
case 32: |
|
for (i = 0; i < height; ++i) { |
|
for (j = 0; j < width; j++) { |
|
*(fb++) = *(bmap++); |
|
*(fb++) = *(bmap++); |
|
*(fb++) = *(bmap++); |
|
*(fb++) = *(bmap++); |
|
} |
|
fb -= lcd_line_length + width * (bpix / 8); |
|
} |
|
break; |
|
#endif /* CONFIG_BMP_32BPP */ |
|
default: |
|
break; |
|
}; |
|
|
|
lcd_sync(); |
|
return 0; |
|
} |
|
#endif |
|
|
|
static void lcd_logo(void) |
|
{ |
|
lcd_logo_plot(0, 0); |
|
|
|
#ifdef CONFIG_LCD_INFO |
|
lcd_set_col(LCD_INFO_X / VIDEO_FONT_WIDTH); |
|
lcd_set_row(LCD_INFO_Y / VIDEO_FONT_HEIGHT); |
|
lcd_show_board_info(); |
|
#endif /* CONFIG_LCD_INFO */ |
|
} |
|
|
|
#ifdef CONFIG_SPLASHIMAGE_GUARD |
|
static int on_splashimage(const char *name, const char *value, enum env_op op, |
|
int flags) |
|
{ |
|
ulong addr; |
|
int aligned; |
|
|
|
if (op == env_op_delete) |
|
return 0; |
|
|
|
addr = simple_strtoul(value, NULL, 16); |
|
/* See README.displaying-bmps */ |
|
aligned = (addr % 4 == 2); |
|
if (!aligned) { |
|
printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n"); |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
U_BOOT_ENV_CALLBACK(splashimage, on_splashimage); |
|
#endif |
|
|
|
int lcd_get_pixel_width(void) |
|
{ |
|
return panel_info.vl_col; |
|
} |
|
|
|
int lcd_get_pixel_height(void) |
|
{ |
|
return panel_info.vl_row; |
|
}
|
|
|