From 7d95f2a329c964b54cf505503a61e8fd4f12e2a3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 27 Feb 2014 13:26:19 -0700 Subject: [PATCH] sandbox: Add LCD driver Add a simple LCD driver which uses SDL to display the image. We update the image regularly, while still providing for reasonable performance. Adjust the common lcd code to support sandbox. For command-line runs we do not want the LCD to be displayed, so add a --show_lcd option to enable it. Tested-by: Che-Liang Chiou Signed-off-by: Simon Glass --- arch/sandbox/cpu/start.c | 9 +++ arch/sandbox/include/asm/state.h | 1 + arch/sandbox/include/asm/u-boot-sandbox.h | 3 + board/sandbox/sandbox/sandbox.c | 18 +++++ common/lcd.c | 21 ++++- doc/device-tree-bindings/video/sandbox-fb.txt | 13 +++ drivers/serial/sandbox.c | 4 + drivers/video/Makefile | 1 + drivers/video/sandbox_sdl.c | 79 +++++++++++++++++++ include/fdtdec.h | 1 + include/lcd.h | 3 + lib/fdtdec.c | 1 + 12 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 doc/device-tree-bindings/video/sandbox-fb.txt create mode 100644 drivers/video/sandbox_sdl.c diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 2d19fe795e..4d5569e647 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -175,6 +175,15 @@ static int sandbox_cmdline_cb_ignore_missing(struct sandbox_state *state, SANDBOX_CMDLINE_OPT_SHORT(ignore_missing, 'n', 0, "Ignore missing state on read"); +static int sandbox_cmdline_cb_show_lcd(struct sandbox_state *state, + const char *arg) +{ + state->show_lcd = true; + return 0; +} +SANDBOX_CMDLINE_OPT_SHORT(show_lcd, 'l', 0, + "Show the sandbox LCD display"); + int main(int argc, char *argv[]) { struct sandbox_state *state; diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 304104e058..895b3a4ec7 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -41,6 +41,7 @@ struct sandbox_state { bool read_state; /* Read sandbox state on startup */ bool write_state; /* Write sandbox state on exit */ bool ignore_missing_state_on_read; /* No error if state missing */ + bool show_lcd; /* Show LCD on start-up */ /* Pointer to information for each SPI bus/cs */ struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS] diff --git a/arch/sandbox/include/asm/u-boot-sandbox.h b/arch/sandbox/include/asm/u-boot-sandbox.h index 5707c2710d..d2f1b6566d 100644 --- a/arch/sandbox/include/asm/u-boot-sandbox.h +++ b/arch/sandbox/include/asm/u-boot-sandbox.h @@ -25,4 +25,7 @@ int sandbox_main_loop_init(void); int cleanup_before_linux(void); +/* drivers/video/sandbox_sdl.c */ +int sandbox_lcd_sdl_early_init(void); + #endif /* _U_BOOT_SANDBOX_H_ */ diff --git a/board/sandbox/sandbox/sandbox.c b/board/sandbox/sandbox/sandbox.c index 402afea811..e4d4e021bc 100644 --- a/board/sandbox/sandbox/sandbox.c +++ b/board/sandbox/sandbox/sandbox.c @@ -7,6 +7,7 @@ #include #include #include +#include /* * Pointer to initial global data area @@ -35,6 +36,23 @@ int dram_init(void) return 0; } +#ifdef CONFIG_BOARD_EARLY_INIT_F +int board_early_init_f(void) +{ +#ifdef CONFIG_VIDEO_SANDBOX_SDL + int ret; + + ret = sandbox_lcd_sdl_early_init(); + if (ret) { + puts("Could not init sandbox LCD emulation\n"); + return ret; + } +#endif + + return 0; +} +#endif + int arch_early_init_r(void) { #ifdef CONFIG_CROS_EC diff --git a/common/lcd.c b/common/lcd.c index aa81522fff..19b86b7c55 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #if defined(CONFIG_CPU_PXA25X) || defined(CONFIG_CPU_PXA27X) || \ defined(CONFIG_CPU_MONAHANS) @@ -63,6 +65,10 @@ # endif #endif +#ifdef CONFIG_SANDBOX +#include +#endif + #ifndef CONFIG_LCD_ALIGNMENT #define CONFIG_LCD_ALIGNMENT PAGE_SIZE #endif @@ -144,6 +150,13 @@ void lcd_sync(void) if (lcd_flush_dcache) flush_dcache_range((u32)lcd_base, (u32)(lcd_base + lcd_get_size(&line_length))); +#elif defined(CONFIG_SANDBOX) && defined(CONFIG_VIDEO_SANDBOX_SDL) + static ulong last_sync; + + if (get_timer(last_sync) > 10) { + sandbox_sdl_sync(lcd_base); + last_sync = get_timer(0); + } #endif } @@ -403,7 +416,7 @@ int drv_lcd_init(void) struct stdio_dev lcddev; int rc; - lcd_base = (void *) gd->fb_base; + lcd_base = map_sysmem(gd->fb_base, 0); lcd_init(lcd_base); /* LCD initialization */ @@ -494,8 +507,8 @@ static int lcd_init(void *lcdbase) * by setting up gd->fb_base. Check for this condition and fixup * 'lcd_base' address. */ - if ((unsigned long)lcdbase != gd->fb_base) - lcd_base = (void *)gd->fb_base; + 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); @@ -886,7 +899,7 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) ushort *cmap_base = NULL; ushort i, j; uchar *fb; - bmp_image_t *bmp=(bmp_image_t *)bmp_image; + bmp_image_t *bmp = (bmp_image_t *)map_sysmem(bmp_image, 0); uchar *bmap; ushort padded_width; unsigned long width, height, byte_width; diff --git a/doc/device-tree-bindings/video/sandbox-fb.txt b/doc/device-tree-bindings/video/sandbox-fb.txt new file mode 100644 index 0000000000..eb91b30e3f --- /dev/null +++ b/doc/device-tree-bindings/video/sandbox-fb.txt @@ -0,0 +1,13 @@ +Sandbox LCD +=========== + +This uses the displaymode.txt binding except that only xres and yres are +required properties. + +Example: + + lcd { + compatible = "sandbox,lcd-sdl"; + xres = <800>; + yres = <600>; + }; diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index ffff5e1497..c27b5b8fe5 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -60,6 +61,9 @@ static int sandbox_serial_tstc(void) ssize_t count; os_usleep(100); +#ifdef CONFIG_LCD + lcd_sync(); +#endif if (next_index == serial_buf_read) return 1; /* buffer full */ diff --git a/drivers/video/Makefile b/drivers/video/Makefile index a7f54698ac..c527029241 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o obj-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o +obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o obj-$(CONFIG_VIDEO_SED13806) += sed13806.o obj-$(CONFIG_VIDEO_SM501) += sm501.o obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o diff --git a/drivers/video/sandbox_sdl.c b/drivers/video/sandbox_sdl.c new file mode 100644 index 0000000000..ba4578e9d1 --- /dev/null +++ b/drivers/video/sandbox_sdl.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +enum { + /* Maximum LCD size we support */ + LCD_MAX_WIDTH = 1366, + LCD_MAX_HEIGHT = 768, + LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ +}; + +vidinfo_t panel_info; + +void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +{ +} + +void lcd_ctrl_init(void *lcdbase) +{ + /* + * Allocate memory to keep BMP color conversion map. This is required + * for 8 bit BMPs only (hence 256 colors). If malloc fails - keep + * going, it is not even clear if displyaing the bitmap will be + * required on the way up. + */ + panel_info.cmap = malloc(256 * NBITS(panel_info.vl_bpix) / 8); +} + +void lcd_enable(void) +{ + if (sandbox_sdl_init_display(panel_info.vl_col, panel_info.vl_row, + panel_info.vl_bpix)) + puts("LCD init failed\n"); +} + +int sandbox_lcd_sdl_early_init(void) +{ + const void *blob = gd->fdt_blob; + int xres = LCD_MAX_WIDTH, yres = LCD_MAX_HEIGHT; + int node; + int ret = 0; + + /* + * The code in common/lcd.c does not cope with not being able to + * set up a frame buffer. It will just happily keep writing to + * invalid memory. So here we make sure that at least some buffer + * is available even if it actually won't be displayed. + */ + node = fdtdec_next_compatible(blob, 0, COMPAT_SANDBOX_LCD_SDL); + if (node >= 0) { + xres = fdtdec_get_int(blob, node, "xres", LCD_MAX_WIDTH); + yres = fdtdec_get_int(blob, node, "yres", LCD_MAX_HEIGHT); + if (xres < 0 || xres > LCD_MAX_WIDTH) { + xres = LCD_MAX_WIDTH; + ret = -EINVAL; + } + if (yres < 0 || yres > LCD_MAX_HEIGHT) { + yres = LCD_MAX_HEIGHT; + ret = -EINVAL; + } + } + + panel_info.vl_col = xres; + panel_info.vl_row = yres; + panel_info.vl_bpix = LCD_COLOR16; + + return ret; +} diff --git a/include/fdtdec.h b/include/fdtdec.h index bcd2ee5f9c..6e859ce64c 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -89,6 +89,7 @@ enum fdt_compat_id { COMPAT_INFINEON_SLB9645_TPM, /* Infineon SLB9645 TPM */ COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */ COMPAT_SANDBOX_HOST_EMULATION, /* Sandbox emulation of a function */ + COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */ COMPAT_COUNT, }; diff --git a/include/lcd.h b/include/lcd.h index d06d6f1072..5f84cd3c5b 100644 --- a/include/lcd.h +++ b/include/lcd.h @@ -313,6 +313,9 @@ int lcd_get_size(int *line_length); int lcd_dt_simplefb_add_node(void *blob); int lcd_dt_simplefb_enable_existing_node(void *blob); +/* Update the LCD / flush the cache */ +void lcd_sync(void); + /************************************************************************/ /* ** BITMAP DISPLAY SUPPORT */ /************************************************************************/ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e0b8927ac8..f65ab4f58f 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -62,6 +62,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"), COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"), COMPAT(SANDBOX_HOST_EMULATION, "sandbox,host-emulation"), + COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) -- 2.25.1