2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2004-10-09 23:25:58 +00:00
|
|
|
/*
|
2015-02-03 11:32:29 +00:00
|
|
|
* Common LCD routines
|
2004-10-09 23:25:58 +00:00
|
|
|
*
|
|
|
|
* (C) Copyright 2001-2002
|
|
|
|
* Wolfgang Denk, DENX Software Engineering -- wd@denx.de
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* #define DEBUG */
|
|
|
|
#include <config.h>
|
|
|
|
#include <common.h>
|
|
|
|
#include <command.h>
|
2019-11-14 19:57:39 +00:00
|
|
|
#include <cpu_func.h>
|
2013-02-24 21:28:43 +00:00
|
|
|
#include <env_callback.h>
|
2020-05-10 17:40:05 +00:00
|
|
|
#include <log.h>
|
2020-05-10 17:39:56 +00:00
|
|
|
#include <asm/cache.h>
|
2020-05-10 17:40:02 +00:00
|
|
|
#include <init.h>
|
2020-10-31 03:38:53 +00:00
|
|
|
#include <asm/global_data.h>
|
2004-10-09 23:25:58 +00:00
|
|
|
#include <linux/types.h>
|
2009-05-16 10:14:54 +00:00
|
|
|
#include <stdio_dev.h>
|
2004-10-09 23:25:58 +00:00
|
|
|
#include <lcd.h>
|
2015-03-22 22:08:59 +00:00
|
|
|
#include <mapmem.h>
|
2005-04-03 23:11:38 +00:00
|
|
|
#include <watchdog.h>
|
2014-01-22 10:24:13 +00:00
|
|
|
#include <asm/unaligned.h>
|
2013-06-17 18:31:29 +00:00
|
|
|
#include <splash.h>
|
2014-02-27 20:26:19 +00:00
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/unaligned.h>
|
2015-02-03 11:32:29 +00:00
|
|
|
#include <video_font.h>
|
2013-06-17 18:31:29 +00:00
|
|
|
|
2005-07-04 00:03:16 +00:00
|
|
|
#ifdef CONFIG_LCD_LOGO
|
2015-02-03 11:32:29 +00:00
|
|
|
#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
|
2005-07-04 00:03:16 +00:00
|
|
|
#endif
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-10-17 13:24:54 +00:00
|
|
|
#ifndef CONFIG_LCD_ALIGNMENT
|
|
|
|
#define CONFIG_LCD_ALIGNMENT PAGE_SIZE
|
|
|
|
#endif
|
|
|
|
|
2014-12-08 15:14:42 +00:00
|
|
|
#if (LCD_BPP != LCD_COLOR8) && (LCD_BPP != LCD_COLOR16) && \
|
|
|
|
(LCD_BPP != LCD_COLOR32)
|
2015-02-03 11:32:29 +00:00
|
|
|
#error Unsupported LCD BPP.
|
2013-01-12 12:07:59 +00:00
|
|
|
#endif
|
|
|
|
|
2006-03-31 16:32:53 +00:00
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
static int lcd_init(void *lcdbase);
|
2015-02-03 11:32:32 +00:00
|
|
|
static void lcd_logo(void);
|
2012-05-24 01:42:38 +00:00
|
|
|
static void lcd_setfgcolor(int color);
|
|
|
|
static void lcd_setbgcolor(int color);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2013-01-05 09:45:48 +00:00
|
|
|
static int lcd_color_fg;
|
|
|
|
static int lcd_color_bg;
|
2013-01-22 10:44:11 +00:00
|
|
|
int lcd_line_length;
|
2004-10-09 23:25:58 +00:00
|
|
|
char lcd_is_enabled = 0;
|
2013-01-22 10:44:12 +00:00
|
|
|
static void *lcd_base; /* Start of framebuffer memory */
|
2012-10-30 13:40:18 +00:00
|
|
|
static char lcd_flush_dcache; /* 1 to flush dcache after each lcd update */
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-10-30 13:40:18 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2019-05-03 13:41:00 +00:00
|
|
|
#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
|
2012-10-30 13:40:18 +00:00
|
|
|
int line_length;
|
|
|
|
|
|
|
|
if (lcd_flush_dcache)
|
2016-03-16 14:41:22 +00:00
|
|
|
flush_dcache_range((ulong)lcd_base,
|
|
|
|
(ulong)(lcd_base + lcd_get_size(&line_length)));
|
2012-10-30 13:40:18 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void lcd_set_flush_dcache(int flush)
|
|
|
|
{
|
|
|
|
lcd_flush_dcache = (flush != 0);
|
|
|
|
}
|
|
|
|
|
2014-07-23 12:54:59 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-11-09 10:00:09 +00:00
|
|
|
/*
|
|
|
|
* 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)
|
2012-10-17 13:24:54 +00:00
|
|
|
{
|
|
|
|
*line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
|
|
|
|
return *line_length * panel_info.vl_row;
|
|
|
|
}
|
|
|
|
|
2013-01-12 12:07:56 +00:00
|
|
|
int drv_lcd_init(void)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
2009-05-16 10:14:54 +00:00
|
|
|
struct stdio_dev lcddev;
|
2004-10-09 23:25:58 +00:00
|
|
|
int rc;
|
|
|
|
|
2014-02-27 20:26:19 +00:00
|
|
|
lcd_base = map_sysmem(gd->fb_base, 0);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2015-02-03 11:32:29 +00:00
|
|
|
lcd_init(lcd_base);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
|
|
|
/* Device initialization */
|
2012-05-24 01:42:38 +00:00
|
|
|
memset(&lcddev, 0, sizeof(lcddev));
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
strcpy(lcddev.name, "lcd");
|
2004-10-09 23:25:58 +00:00
|
|
|
lcddev.ext = 0; /* No extensions */
|
|
|
|
lcddev.flags = DEV_FLAGS_OUTPUT; /* Output only */
|
2014-07-23 12:54:59 +00:00
|
|
|
lcddev.putc = lcd_stub_putc; /* 'putc' function */
|
|
|
|
lcddev.puts = lcd_stub_puts; /* 'puts' function */
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2013-01-12 12:07:56 +00:00
|
|
|
rc = stdio_register(&lcddev);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
|
|
|
return (rc == 0) ? 1 : rc;
|
|
|
|
}
|
|
|
|
|
2011-10-20 23:07:03 +00:00
|
|
|
void lcd_clear(void)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
2014-12-08 15:14:43 +00:00
|
|
|
int bg_color;
|
2019-05-29 09:01:43 +00:00
|
|
|
__maybe_unused ulong addr;
|
2015-02-03 11:32:32 +00:00
|
|
|
static int do_splash = 1;
|
2014-12-08 15:14:38 +00:00
|
|
|
#if LCD_BPP == LCD_COLOR8
|
2004-10-09 23:25:58 +00:00
|
|
|
/* Setting the palette */
|
2012-05-24 01:42:38 +00:00
|
|
|
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);
|
2004-10-09 23:25:58 +00:00
|
|
|
#endif
|
|
|
|
|
2008-10-16 13:01:15 +00:00
|
|
|
#ifndef CONFIG_SYS_WHITE_ON_BLACK
|
2012-05-24 01:42:38 +00:00
|
|
|
lcd_setfgcolor(CONSOLE_COLOR_BLACK);
|
|
|
|
lcd_setbgcolor(CONSOLE_COLOR_WHITE);
|
2014-12-08 15:14:43 +00:00
|
|
|
bg_color = CONSOLE_COLOR_WHITE;
|
2004-10-09 23:25:58 +00:00
|
|
|
#else
|
2012-05-24 01:42:38 +00:00
|
|
|
lcd_setfgcolor(CONSOLE_COLOR_WHITE);
|
|
|
|
lcd_setbgcolor(CONSOLE_COLOR_BLACK);
|
2014-12-08 15:14:43 +00:00
|
|
|
bg_color = CONSOLE_COLOR_BLACK;
|
2008-10-16 13:01:15 +00:00
|
|
|
#endif /* CONFIG_SYS_WHITE_ON_BLACK */
|
2004-10-09 23:25:58 +00:00
|
|
|
|
|
|
|
/* set framebuffer to background color */
|
2014-03-07 17:55:40 +00:00
|
|
|
#if (LCD_BPP != LCD_COLOR32)
|
2014-12-08 15:14:43 +00:00
|
|
|
memset((char *)lcd_base, bg_color, lcd_line_length * panel_info.vl_row);
|
2014-03-07 17:55:40 +00:00
|
|
|
#else
|
|
|
|
u32 *ppix = lcd_base;
|
|
|
|
u32 i;
|
|
|
|
for (i = 0;
|
|
|
|
i < (lcd_line_length * panel_info.vl_row)/NBYTES(panel_info.vl_bpix);
|
|
|
|
i++) {
|
2014-12-08 15:14:43 +00:00
|
|
|
*ppix++ = bg_color;
|
2014-03-07 17:55:40 +00:00
|
|
|
}
|
2004-10-09 23:25:58 +00:00
|
|
|
#endif
|
2015-03-27 07:01:38 +00:00
|
|
|
/* 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);
|
2004-10-09 23:25:58 +00:00
|
|
|
/* Paint the logo and retrieve LCD base address */
|
2012-05-24 01:42:38 +00:00
|
|
|
debug("[LCD] Drawing the logo...\n");
|
2015-02-03 11:32:32 +00:00
|
|
|
if (do_splash) {
|
2019-05-29 09:01:43 +00:00
|
|
|
if (splash_display() == 0) {
|
2015-02-03 11:32:32 +00:00
|
|
|
do_splash = 0;
|
2019-05-29 09:01:43 +00:00
|
|
|
lcd_sync();
|
|
|
|
return;
|
2015-02-03 11:32:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lcd_logo();
|
|
|
|
#if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
|
|
|
|
addr = (ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length;
|
2015-08-04 13:49:50 +00:00
|
|
|
lcd_init_console((void *)addr, panel_info.vl_col,
|
|
|
|
panel_info.vl_row, panel_info.vl_rot);
|
2015-02-03 11:32:32 +00:00
|
|
|
#endif
|
2012-10-30 13:40:18 +00:00
|
|
|
lcd_sync();
|
|
|
|
}
|
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
static int lcd_init(void *lcdbase)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
2012-05-24 01:42:38 +00:00
|
|
|
debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase);
|
|
|
|
lcd_ctrl_init(lcdbase);
|
2013-03-29 13:00:13 +00:00
|
|
|
|
|
|
|
/*
|
2014-11-20 03:41:03 +00:00
|
|
|
* lcd_ctrl_init() of some drivers (i.e. bcm2835 on rpi) ignores
|
2013-03-29 13:00:13 +00:00
|
|
|
* the 'lcdbase' argument and uses custom lcd base address
|
|
|
|
* by setting up gd->fb_base. Check for this condition and fixup
|
|
|
|
* 'lcd_base' address.
|
|
|
|
*/
|
2014-02-27 20:26:19 +00:00
|
|
|
if (map_to_sysmem(lcdbase) != gd->fb_base)
|
|
|
|
lcd_base = map_sysmem(gd->fb_base, 0);
|
2013-03-29 13:00:13 +00:00
|
|
|
|
|
|
|
debug("[LCD] Using LCD frambuffer at %p\n", lcd_base);
|
|
|
|
|
2013-01-29 16:37:38 +00:00
|
|
|
lcd_get_size(&lcd_line_length);
|
2008-09-01 14:21:21 +00:00
|
|
|
lcd_is_enabled = 1;
|
2011-10-20 23:07:03 +00:00
|
|
|
lcd_clear();
|
2013-01-12 12:07:56 +00:00
|
|
|
lcd_enable();
|
2004-10-09 23:25:58 +00:00
|
|
|
|
|
|
|
/* Initialize the console */
|
2014-12-08 15:14:41 +00:00
|
|
|
lcd_set_col(0);
|
2005-07-04 00:03:16 +00:00
|
|
|
#ifdef CONFIG_LCD_INFO_BELOW_LOGO
|
2014-12-08 15:14:41 +00:00
|
|
|
lcd_set_row(7 + BMP_LOGO_HEIGHT / VIDEO_FONT_HEIGHT);
|
2004-10-09 23:25:58 +00:00
|
|
|
#else
|
2014-12-08 15:14:41 +00:00
|
|
|
lcd_set_row(1); /* leave 1 blank line below logo */
|
2004-10-09 23:25:58 +00:00
|
|
|
#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.
|
|
|
|
*/
|
2012-05-24 01:42:38 +00:00
|
|
|
ulong lcd_setmem(ulong addr)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
|
|
|
ulong size;
|
2012-10-17 13:24:54 +00:00
|
|
|
int line_length;
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
debug("LCD panel info: %d x %d, %d bit/pix\n", panel_info.vl_col,
|
|
|
|
panel_info.vl_row, NBITS(panel_info.vl_bpix));
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-10-17 13:24:54 +00:00
|
|
|
size = lcd_get_size(&line_length);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-10-17 13:24:54 +00:00
|
|
|
/* 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);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
|
|
|
/* Allocate pages for the frame buffer. */
|
|
|
|
addr -= size;
|
|
|
|
|
2013-01-12 12:07:56 +00:00
|
|
|
debug("Reserving %ldk for LCD Framebuffer at: %08lx\n",
|
|
|
|
size >> 10, addr);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
return addr;
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
static void lcd_setfgcolor(int color)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
2008-05-09 19:57:18 +00:00
|
|
|
lcd_color_fg = color;
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
|
|
|
|
2014-12-08 15:14:43 +00:00
|
|
|
int lcd_getfgcolor(void)
|
|
|
|
{
|
|
|
|
return lcd_color_fg;
|
|
|
|
}
|
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
static void lcd_setbgcolor(int color)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
2008-05-09 19:57:18 +00:00
|
|
|
lcd_color_bg = color;
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
|
|
|
|
2014-12-08 15:14:43 +00:00
|
|
|
int lcd_getbgcolor(void)
|
|
|
|
{
|
|
|
|
return lcd_color_bg;
|
|
|
|
}
|
|
|
|
|
2004-10-09 23:25:58 +00:00
|
|
|
#ifdef CONFIG_LCD_LOGO
|
2015-02-03 11:32:24 +00:00
|
|
|
__weak void lcd_logo_set_cmap(void)
|
|
|
|
{
|
2015-02-03 11:32:26 +00:00
|
|
|
int i;
|
|
|
|
ushort *cmap = configuration_get_cmap();
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(bmp_logo_palette); ++i)
|
|
|
|
*cmap++ = bmp_logo_palette[i];
|
2015-02-03 11:32:24 +00:00
|
|
|
}
|
|
|
|
|
2015-02-03 11:32:30 +00:00
|
|
|
void lcd_logo_plot(int x, int y)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
|
|
|
ushort i, j;
|
2015-02-03 11:32:29 +00:00
|
|
|
uchar *bmap = &bmp_logo_bitmap[0];
|
2013-02-13 17:48:00 +00:00
|
|
|
unsigned bpix = NBITS(panel_info.vl_bpix);
|
2015-02-03 11:32:29 +00:00
|
|
|
uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8);
|
|
|
|
ushort *fb16;
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2015-02-03 11:32:26 +00:00
|
|
|
debug("Logo: width %d height %d colors %d\n",
|
|
|
|
BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2013-02-13 17:48:00 +00:00
|
|
|
if (bpix < 12) {
|
2004-10-09 23:25:58 +00:00
|
|
|
WATCHDOG_RESET();
|
2015-02-03 11:32:24 +00:00
|
|
|
lcd_logo_set_cmap();
|
2004-10-09 23:25:58 +00:00
|
|
|
WATCHDOG_RESET();
|
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
|
|
|
|
memcpy(fb, bmap, BMP_LOGO_WIDTH);
|
2004-10-09 23:25:58 +00:00
|
|
|
bmap += BMP_LOGO_WIDTH;
|
2013-01-12 12:07:56 +00:00
|
|
|
fb += panel_info.vl_col;
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* true color mode */
|
2010-03-13 16:44:08 +00:00
|
|
|
u16 col16;
|
2013-02-13 17:48:00 +00:00
|
|
|
fb16 = (ushort *)fb;
|
2012-05-24 01:42:38 +00:00
|
|
|
for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {
|
|
|
|
for (j = 0; j < BMP_LOGO_WIDTH; j++) {
|
2010-03-13 16:44:08 +00:00
|
|
|
col16 = bmp_logo_palette[(bmap[j]-16)];
|
|
|
|
fb16[j] =
|
|
|
|
((col16 & 0x000F) << 1) |
|
|
|
|
((col16 & 0x00F0) << 3) |
|
|
|
|
((col16 & 0x0F00) << 4);
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
|
|
|
bmap += BMP_LOGO_WIDTH;
|
|
|
|
fb16 += panel_info.vl_col;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WATCHDOG_RESET();
|
2012-10-30 13:40:18 +00:00
|
|
|
lcd_sync();
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
2012-04-27 04:41:27 +00:00
|
|
|
#else
|
2015-02-03 11:32:30 +00:00
|
|
|
static inline void lcd_logo_plot(int x, int y) {}
|
2004-10-09 23:25:58 +00:00
|
|
|
#endif /* CONFIG_LCD_LOGO */
|
|
|
|
|
2007-07-08 23:10:08 +00:00
|
|
|
#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
|
2009-07-09 14:07:30 +00:00
|
|
|
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
|
2012-08-09 00:14:51 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
linux/kernel.h: sync min, max, min3, max3 macros with Linux
U-Boot has never cared about the type when we get max/min of two
values, but Linux Kernel does. This commit gets min, max, min3, max3
macros synced with the kernel introducing type checks.
Many of references of those macros must be fixed to suppress warnings.
We have two options:
- Use min, max, min3, max3 only when the arguments have the same type
(or add casts to the arguments)
- Use min_t/max_t instead with the appropriate type for the first
argument
Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
Acked-by: Pavel Machek <pavel@denx.de>
Acked-by: Lukasz Majewski <l.majewski@samsung.com>
Tested-by: Lukasz Majewski <l.majewski@samsung.com>
[trini: Fixup arch/blackfin/lib/string.c]
Signed-off-by: Tom Rini <trini@ti.com>
2014-11-06 18:03:31 +00:00
|
|
|
*axis = max(0, (int)axis_alignment);
|
2012-08-09 00:14:51 +00:00
|
|
|
}
|
2009-07-09 14:07:30 +00:00
|
|
|
#endif
|
|
|
|
|
2015-02-03 11:32:23 +00:00
|
|
|
__weak void fb_put_byte(uchar **fb, uchar **from)
|
|
|
|
{
|
|
|
|
*(*fb)++ = *(*from)++;
|
|
|
|
}
|
2012-08-09 00:14:53 +00:00
|
|
|
|
|
|
|
#if defined(CONFIG_BMP_16BPP)
|
2015-02-03 11:32:22 +00:00
|
|
|
__weak void fb_put_word(uchar **fb, uchar **from)
|
2012-08-09 00:14:53 +00:00
|
|
|
{
|
|
|
|
*(*fb)++ = *(*from)++;
|
|
|
|
*(*fb)++ = *(*from)++;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BMP_16BPP */
|
|
|
|
|
2015-05-13 13:02:27 +00:00
|
|
|
__weak void lcd_set_cmap(struct bmp_image *bmp, unsigned colors)
|
2015-02-03 11:32:27 +00:00
|
|
|
{
|
|
|
|
int i;
|
2015-05-13 13:02:27 +00:00
|
|
|
struct bmp_color_table_entry cte;
|
2015-02-03 11:32:27 +00:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-09 23:25:58 +00:00
|
|
|
int lcd_display_bitmap(ulong bmp_image, int x, int y)
|
|
|
|
{
|
2009-02-25 19:28:13 +00:00
|
|
|
ushort *cmap_base = NULL;
|
2004-10-09 23:25:58 +00:00
|
|
|
ushort i, j;
|
|
|
|
uchar *fb;
|
2015-05-13 13:02:27 +00:00
|
|
|
struct bmp_image *bmp = (struct bmp_image *)map_sysmem(bmp_image, 0);
|
2004-10-09 23:25:58 +00:00
|
|
|
uchar *bmap;
|
2012-09-28 15:11:14 +00:00
|
|
|
ushort padded_width;
|
2009-02-06 09:37:53 +00:00
|
|
|
unsigned long width, height, byte_width;
|
2006-08-30 21:09:00 +00:00
|
|
|
unsigned long pwidth = panel_info.vl_col;
|
2009-02-06 09:37:53 +00:00
|
|
|
unsigned colors, bpix, bmp_bpix;
|
2015-05-13 13:02:28 +00:00
|
|
|
int hdr_size;
|
2017-07-30 19:59:23 +00:00
|
|
|
struct bmp_color_table_entry *palette;
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2013-01-12 12:07:56 +00:00
|
|
|
if (!bmp || !(bmp->header.signature[0] == 'B' &&
|
|
|
|
bmp->header.signature[1] == 'M')) {
|
2012-05-24 01:42:38 +00:00
|
|
|
printf("Error: no valid bmp image at %lx\n", bmp_image);
|
|
|
|
|
2004-10-09 23:25:58 +00:00
|
|
|
return 1;
|
2009-02-06 09:37:53 +00:00
|
|
|
}
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2017-07-30 19:59:23 +00:00
|
|
|
palette = bmp->color_table;
|
2014-01-22 10:24:13 +00:00
|
|
|
width = get_unaligned_le32(&bmp->header.width);
|
|
|
|
height = get_unaligned_le32(&bmp->header.height);
|
|
|
|
bmp_bpix = get_unaligned_le16(&bmp->header.bit_count);
|
2015-05-13 13:02:28 +00:00
|
|
|
hdr_size = get_unaligned_le16(&bmp->header.size);
|
|
|
|
debug("hdr_size=%d, bmp_bpix=%d\n", hdr_size, bmp_bpix);
|
2014-01-22 10:24:13 +00:00
|
|
|
|
2009-02-06 09:37:53 +00:00
|
|
|
colors = 1 << bmp_bpix;
|
2004-10-09 23:25:58 +00:00
|
|
|
|
|
|
|
bpix = NBITS(panel_info.vl_bpix);
|
|
|
|
|
2013-01-12 12:07:56 +00:00
|
|
|
if (bpix != 1 && bpix != 8 && bpix != 16 && bpix != 32) {
|
2009-02-06 09:37:53 +00:00
|
|
|
printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
|
|
|
|
bpix, bmp_bpix);
|
2012-05-24 01:42:38 +00:00
|
|
|
|
2004-10-09 23:25:58 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-15 14:28:46 +00:00
|
|
|
/*
|
|
|
|
* 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)) {
|
2004-10-09 23:25:58 +00:00
|
|
|
printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
|
2014-01-22 10:24:13 +00:00
|
|
|
bpix, get_unaligned_le16(&bmp->header.bit_count));
|
2004-10-09 23:25:58 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-05-13 13:02:28 +00:00
|
|
|
debug("Display-bmp: %d x %d with %d colors, display %d\n",
|
|
|
|
(int)width, (int)height, (int)colors, 1 << bpix);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2015-02-03 11:32:27 +00:00
|
|
|
if (bmp_bpix == 8)
|
|
|
|
lcd_set_cmap(bmp, colors);
|
2006-08-30 21:09:00 +00:00
|
|
|
|
2013-01-12 12:07:56 +00:00
|
|
|
padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width);
|
2009-07-09 14:07:30 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_SPLASH_SCREEN_ALIGN
|
2012-08-09 00:14:51 +00:00
|
|
|
splash_align_axis(&x, pwidth, width);
|
|
|
|
splash_align_axis(&y, panel_info.vl_row, height);
|
2009-07-09 14:07:30 +00:00
|
|
|
#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
|
|
|
|
|
2012-05-24 01:42:38 +00:00
|
|
|
if ((x + width) > pwidth)
|
2006-08-30 21:09:00 +00:00
|
|
|
width = pwidth - x;
|
2012-05-24 01:42:38 +00:00
|
|
|
if ((y + height) > panel_info.vl_row)
|
2004-10-09 23:25:58 +00:00
|
|
|
height = panel_info.vl_row - y;
|
|
|
|
|
2014-01-22 10:24:13 +00:00
|
|
|
bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset);
|
|
|
|
fb = (uchar *)(lcd_base +
|
2011-01-11 07:29:58 +00:00
|
|
|
(y + height - 1) * lcd_line_length + x * bpix / 8);
|
2009-02-06 09:37:49 +00:00
|
|
|
|
2009-02-06 09:37:53 +00:00
|
|
|
switch (bmp_bpix) {
|
2015-02-03 11:32:29 +00:00
|
|
|
case 1:
|
2014-10-15 10:53:04 +00:00
|
|
|
case 8: {
|
2015-02-03 11:32:27 +00:00
|
|
|
cmap_base = configuration_get_cmap();
|
2012-09-28 15:11:16 +00:00
|
|
|
|
2009-02-06 09:37:53 +00:00
|
|
|
if (bpix != 16)
|
|
|
|
byte_width = width;
|
|
|
|
else
|
|
|
|
byte_width = width * 2;
|
|
|
|
|
2009-02-06 09:37:49 +00:00
|
|
|
for (i = 0; i < height; ++i) {
|
|
|
|
WATCHDOG_RESET();
|
2009-02-06 09:37:53 +00:00
|
|
|
for (j = 0; j < width; j++) {
|
|
|
|
if (bpix != 16) {
|
2015-02-03 11:32:23 +00:00
|
|
|
fb_put_byte(&fb, &bmap);
|
2009-02-06 09:37:53 +00:00
|
|
|
} else {
|
2015-05-13 13:02:28 +00:00
|
|
|
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++;
|
2009-02-06 09:37:53 +00:00
|
|
|
fb += sizeof(uint16_t) / sizeof(*fb);
|
|
|
|
}
|
|
|
|
}
|
2012-09-28 15:11:14 +00:00
|
|
|
bmap += (padded_width - width);
|
2013-01-12 12:07:56 +00:00
|
|
|
fb -= byte_width + lcd_line_length;
|
2009-02-06 09:37:49 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-10-15 10:53:04 +00:00
|
|
|
}
|
2009-02-06 09:37:49 +00:00
|
|
|
#if defined(CONFIG_BMP_16BPP)
|
|
|
|
case 16:
|
|
|
|
for (i = 0; i < height; ++i) {
|
|
|
|
WATCHDOG_RESET();
|
2012-08-09 00:14:53 +00:00
|
|
|
for (j = 0; j < width; j++)
|
|
|
|
fb_put_word(&fb, &bmap);
|
|
|
|
|
2012-09-28 15:11:14 +00:00
|
|
|
bmap += (padded_width - width) * 2;
|
2013-01-12 12:07:56 +00:00
|
|
|
fb -= width * 2 + lcd_line_length;
|
2009-02-06 09:37:49 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BMP_16BPP */
|
2017-05-05 19:48:30 +00:00
|
|
|
#if defined(CONFIG_BMP_24BPP)
|
2014-07-15 14:28:46 +00:00
|
|
|
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;
|
2017-05-05 19:48:30 +00:00
|
|
|
#endif /* CONFIG_BMP_24BPP */
|
2012-05-09 19:23:37 +00:00
|
|
|
#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++);
|
|
|
|
}
|
2013-01-12 12:07:56 +00:00
|
|
|
fb -= lcd_line_length + width * (bpix / 8);
|
2012-05-09 19:23:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BMP_32BPP */
|
2009-02-06 09:37:49 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
};
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2012-10-30 13:40:18 +00:00
|
|
|
lcd_sync();
|
2012-05-24 01:42:38 +00:00
|
|
|
return 0;
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
2007-07-08 23:10:08 +00:00
|
|
|
#endif
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2015-02-03 11:32:32 +00:00
|
|
|
static void lcd_logo(void)
|
2004-10-09 23:25:58 +00:00
|
|
|
{
|
2015-02-03 11:32:30 +00:00
|
|
|
lcd_logo_plot(0, 0);
|
2004-10-09 23:25:58 +00:00
|
|
|
|
2008-09-01 14:21:22 +00:00
|
|
|
#ifdef CONFIG_LCD_INFO
|
2014-12-08 15:14:41 +00:00
|
|
|
lcd_set_col(LCD_INFO_X / VIDEO_FONT_WIDTH);
|
|
|
|
lcd_set_row(LCD_INFO_Y / VIDEO_FONT_HEIGHT);
|
2008-09-01 14:21:22 +00:00
|
|
|
lcd_show_board_info();
|
|
|
|
#endif /* CONFIG_LCD_INFO */
|
2004-10-09 23:25:58 +00:00
|
|
|
}
|
|
|
|
|
2013-02-24 21:28:43 +00:00
|
|
|
#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;
|
|
|
|
|
2021-07-24 15:03:29 +00:00
|
|
|
addr = hextoul(value, NULL);
|
2013-02-24 21:28:43 +00:00
|
|
|
/* 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
|
|
|
|
|
2012-09-28 15:11:13 +00:00
|
|
|
int lcd_get_pixel_width(void)
|
|
|
|
{
|
|
|
|
return panel_info.vl_col;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lcd_get_pixel_height(void)
|
|
|
|
{
|
|
|
|
return panel_info.vl_row;
|
|
|
|
}
|