diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 62 | ||||
-rw-r--r-- | drivers/video/Makefile | 3 | ||||
-rw-r--r-- | drivers/video/console_normal.c | 141 | ||||
-rw-r--r-- | drivers/video/console_rotate.c | 436 | ||||
-rw-r--r-- | drivers/video/sandbox_sdl.c | 90 | ||||
-rw-r--r-- | drivers/video/vidconsole-uclass.c | 239 | ||||
-rw-r--r-- | drivers/video/video-uclass.c | 249 | ||||
-rw-r--r-- | drivers/video/video_bmp.c | 353 |
8 files changed, 1524 insertions, 49 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index caf1efcbb3..ae122daa04 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -4,6 +4,59 @@ menu "Graphics support" +config DM_VIDEO + bool "Enable driver model support for LCD/video" + depends on DM + help + This enables driver model for LCD and video devices. These support + a bitmap display of various sizes and depths which can be drawn on + to display a command-line console or splash screen. Enabling this + option compiles in the video uclass and routes all LCD/video access + through this. + +config VIDEO_BPP8 + bool "Support 8-bit-per-pixel displays" + depends on DM_VIDEO + default y if DM_VIDEO + help + Support drawing text and bitmaps onto a 8-bit-per-pixel display. + Enabling this will include code to support this display. Without + this option, such displays will not be supported and console output + will be empty. + +config VIDEO_BPP16 + bool "Support 16-bit-per-pixel displays" + depends on DM_VIDEO + default y if DM_VIDEO + help + Support drawing text and bitmaps onto a 16-bit-per-pixel display. + Enabling this will include code to support this display. Without + this option, such displays will not be supported and console output + will be empty. + +config VIDEO_BPP32 + bool "Support 32-bit-per-pixel displays" + depends on DM_VIDEO + default y if DM_VIDEO + help + Support drawing text and bitmaps onto a 32-bit-per-pixel display. + Enabling this will include code to support this display. Without + this option, such displays will not be supported and console output + will be empty. + +config VIDEO_ROTATION + bool "Support rotated displays" + depends on DM_VIDEO + help + Sometimes, for example if the display is mounted in portrait + mode or even if it's mounted landscape but rotated by 180degree, + we need to rotate our content of the display relative to the + framebuffer, so that user can read the messages which are + printed out. Enable this option to include a text driver which can + support this. The rotation is set by the 'rot' parameter in + struct video_priv: 0=unrotated, 1=90 degrees clockwise, 2=180 + degrees, 3=270 degrees. + config VIDEO_VESA bool "Enable VESA video driver support" default n @@ -247,6 +300,15 @@ config DISPLAY_PORT to drive LCD panels. This framework provides support for enabling these displays where supported by the video hardware. +config VIDEO_SANDBOX_SDL + bool "Enable sandbox video console using SDL" + depends on SANDBOX + help + When using sandbox you can enable an emulated LCD display which + appears as an SDL (Simple DirectMedia Layer) window. This is a + console device and can display stdout output. Within U-Boot is is + a normal bitmap display and can display images as well as text. + config VIDEO_TEGRA124 bool "Enable video support on Tegra124" help diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e85fd8a677..ee046296e6 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -7,6 +7,9 @@ ifdef CONFIG_DM obj-$(CONFIG_DISPLAY_PORT) += dp-uclass.o +obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o console_normal.o +obj-$(CONFIG_DM_VIDEO) += video_bmp.o +obj-$(CONFIG_VIDEO_ROTATION) += console_rotate.o endif obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c new file mode 100644 index 0000000000..d1031c8ed1 --- /dev/null +++ b/drivers/video/console_normal.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2015 Google, Inc + * (C) Copyright 2001-2015 + * DENX Software Engineering -- wd@denx.de + * Compulab Ltd - http://compulab.co.il/ + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <video.h> +#include <video_console.h> +#include <video_font.h> /* Get font data, width and height */ + +static int console_normal_set_row(struct udevice *dev, uint row, int clr) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + void *line; + int pixels = VIDEO_FONT_HEIGHT * vid_priv->line_length; + int i; + + line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * vid_priv->line_length; + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < pixels; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < pixels; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < pixels; i++) + *dst++ = clr; + break; + } +#endif + default: + return -ENOSYS; + } + + return 0; +} + +static int console_normal_move_rows(struct udevice *dev, uint rowdst, + uint rowsrc, uint count) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + void *dst; + void *src; + + dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * vid_priv->line_length; + src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * vid_priv->line_length; + memmove(dst, src, VIDEO_FONT_HEIGHT * vid_priv->line_length * count); + + return 0; +} + +static int console_normal_putc_xy(struct udevice *dev, uint x, uint y, char ch) +{ + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + int i, row; + void *line = vid_priv->fb + y * vid_priv->line_length + + x * VNBYTES(vid_priv->bpix); + + for (row = 0; row < VIDEO_FONT_HEIGHT; row++) { + uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row]; + + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < VIDEO_FONT_WIDTH; i++) { + *dst++ = (bits & 0x80) ? vid_priv->colour_fg + : vid_priv->colour_bg; + bits <<= 1; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < VIDEO_FONT_WIDTH; i++) { + *dst++ = (bits & 0x80) ? vid_priv->colour_fg + : vid_priv->colour_bg; + bits <<= 1; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < VIDEO_FONT_WIDTH; i++) { + *dst++ = (bits & 0x80) ? vid_priv->colour_fg + : vid_priv->colour_bg; + bits <<= 1; + } + break; + } +#endif + default: + return -ENOSYS; + } + line += vid_priv->line_length; + } + + return 0; +} + +struct vidconsole_ops console_normal_ops = { + .putc_xy = console_normal_putc_xy, + .move_rows = console_normal_move_rows, + .set_row = console_normal_set_row, +}; + +U_BOOT_DRIVER(vidconsole_normal) = { + .name = "vidconsole0", + .id = UCLASS_VIDEO_CONSOLE, + .ops = &console_normal_ops, +}; diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c new file mode 100644 index 0000000000..ebb31d8cd0 --- /dev/null +++ b/drivers/video/console_rotate.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2015 Google, Inc + * (C) Copyright 2015 + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <video.h> +#include <video_console.h> +#include <video_font.h> /* Get font data, width and height */ + +static int console_set_row_1(struct udevice *dev, uint row, int clr) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + int pbytes = VNBYTES(vid_priv->bpix); + void *line; + int i, j; + + line = vid_priv->fb + vid_priv->line_length - + (row + 1) * VIDEO_FONT_HEIGHT * pbytes; + for (j = 0; j < vid_priv->ysize; j++) { + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) + *dst++ = clr; + break; + } +#endif + default: + return -ENOSYS; + } + line += vid_priv->line_length; + } + + return 0; +} + +static int console_move_rows_1(struct udevice *dev, uint rowdst, uint rowsrc, + uint count) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + void *dst; + void *src; + int pbytes = VNBYTES(vid_priv->bpix); + int j; + + dst = vid_priv->fb + vid_priv->line_length - + (rowdst + count) * VIDEO_FONT_HEIGHT * pbytes; + src = vid_priv->fb + vid_priv->line_length - + (rowsrc + count) * VIDEO_FONT_HEIGHT * pbytes; + + for (j = 0; j < vid_priv->ysize; j++) { + memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count); + src += vid_priv->line_length; + dst += vid_priv->line_length; + } + + return 0; +} + +static int console_putc_xy_1(struct udevice *dev, uint x, uint y, char ch) +{ + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + int pbytes = VNBYTES(vid_priv->bpix); + int i, col; + int mask = 0x80; + void *line = vid_priv->fb + (x + 1) * vid_priv->line_length - + (y + 1) * pbytes; + uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT; + + for (col = 0; col < VIDEO_FONT_HEIGHT; col++) { + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { + *dst-- = (pfont[i] & mask) ? vid_priv->colour_fg + : vid_priv->colour_bg; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { + *dst-- = (pfont[i] & mask) ? vid_priv->colour_fg + : vid_priv->colour_bg; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { + *dst-- = (pfont[i] & mask) ? vid_priv->colour_fg + : vid_priv->colour_bg; + } + break; + } +#endif + default: + return -ENOSYS; + } + line += vid_priv->line_length; + mask >>= 1; + } + + return 0; +} + + +static int console_set_row_2(struct udevice *dev, uint row, int clr) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + void *line; + int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize; + int i; + + line = vid_priv->fb + vid_priv->ysize * vid_priv->line_length - + (row + 1) * VIDEO_FONT_HEIGHT * vid_priv->line_length; + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < pixels; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < pixels; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < pixels; i++) + *dst++ = clr; + break; + } +#endif + default: + return -ENOSYS; + } + + return 0; +} + +static int console_move_rows_2(struct udevice *dev, uint rowdst, uint rowsrc, + uint count) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + void *dst; + void *src; + void *end; + + end = vid_priv->fb + vid_priv->ysize * vid_priv->line_length; + dst = end - (rowdst + count) * VIDEO_FONT_HEIGHT * + vid_priv->line_length; + src = end - (rowsrc + count) * VIDEO_FONT_HEIGHT * + vid_priv->line_length; + memmove(dst, src, VIDEO_FONT_HEIGHT * vid_priv->line_length * count); + + return 0; +} + +static int console_putc_xy_2(struct udevice *dev, uint x, uint y, char ch) +{ + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + int i, row; + void *line; + + line = vid_priv->fb + (vid_priv->ysize - y - 1) * + vid_priv->line_length + + (vid_priv->xsize - x - VIDEO_FONT_WIDTH - 1) * + VNBYTES(vid_priv->bpix); + + for (row = 0; row < VIDEO_FONT_HEIGHT; row++) { + uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row]; + + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < VIDEO_FONT_WIDTH; i++) { + *dst-- = (bits & 0x80) ? vid_priv->colour_fg + : vid_priv->colour_bg; + bits <<= 1; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < VIDEO_FONT_WIDTH; i++) { + *dst-- = (bits & 0x80) ? vid_priv->colour_fg + : vid_priv->colour_bg; + bits <<= 1; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < VIDEO_FONT_WIDTH; i++) { + *dst-- = (bits & 0x80) ? vid_priv->colour_fg + : vid_priv->colour_bg; + bits <<= 1; + } + break; + } +#endif + default: + return -ENOSYS; + } + line -= vid_priv->line_length; + } + + return 0; +} + +static int console_set_row_3(struct udevice *dev, uint row, int clr) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + int pbytes = VNBYTES(vid_priv->bpix); + void *line; + int i, j; + + line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * pbytes; + for (j = 0; j < vid_priv->ysize; j++) { + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) + *dst++ = clr; + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) + *dst++ = clr; + break; + } +#endif + default: + return -ENOSYS; + } + line += vid_priv->line_length; + } + + return 0; +} + +static int console_move_rows_3(struct udevice *dev, uint rowdst, uint rowsrc, + uint count) +{ + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + void *dst; + void *src; + int pbytes = VNBYTES(vid_priv->bpix); + int j; + + dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * pbytes; + src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * pbytes; + + for (j = 0; j < vid_priv->ysize; j++) { + memmove(dst, src, VIDEO_FONT_HEIGHT * pbytes * count); + src += vid_priv->line_length; + dst += vid_priv->line_length; + } + + return 0; +} + +static int console_putc_xy_3(struct udevice *dev, uint x, uint y, char ch) +{ + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + int pbytes = VNBYTES(vid_priv->bpix); + int i, col; + int mask = 0x80; + void *line = vid_priv->fb + (vid_priv->ysize - x - 1) * + vid_priv->line_length + y * pbytes; + uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT; + + for (col = 0; col < VIDEO_FONT_HEIGHT; col++) { + switch (vid_priv->bpix) { +#ifdef CONFIG_VIDEO_BPP8 + case VIDEO_BPP8: { + uint8_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { + *dst++ = (pfont[i] & mask) ? vid_priv->colour_fg + : vid_priv->colour_bg; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP16 + case VIDEO_BPP16: { + uint16_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { + *dst++ = (pfont[i] & mask) ? vid_priv->colour_fg + : vid_priv->colour_bg; + } + break; + } +#endif +#ifdef CONFIG_VIDEO_BPP32 + case VIDEO_BPP32: { + uint32_t *dst = line; + + for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { + *dst++ = (pfont[i] & mask) ? vid_priv->colour_fg + : vid_priv->colour_bg; + } + break; + } +#endif + default: + return -ENOSYS; + } + line -= vid_priv->line_length; + mask >>= 1; + } + + return 0; +} + + +static int console_probe_1_3(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + + priv->cols = vid_priv->ysize / VIDEO_FONT_WIDTH; + priv->rows = vid_priv->xsize / VIDEO_FONT_HEIGHT; + + return 0; +} + +struct vidconsole_ops console_ops_1 = { + .putc_xy = console_putc_xy_1, + .move_rows = console_move_rows_1, + .set_row = console_set_row_1, +}; + +struct vidconsole_ops console_ops_2 = { + .putc_xy = console_putc_xy_2, + .move_rows = console_move_rows_2, + .set_row = console_set_row_2, +}; + +struct vidconsole_ops console_ops_3 = { + .putc_xy = console_putc_xy_3, + .move_rows = console_move_rows_3, + .set_row = console_set_row_3, +}; + +U_BOOT_DRIVER(vidconsole_1) = { + .name = "vidconsole1", + .id = UCLASS_VIDEO_CONSOLE, + .ops = &console_ops_1, + .probe = console_probe_1_3, +}; + +U_BOOT_DRIVER(vidconsole_2) = { + .name = "vidconsole2", + .id = UCLASS_VIDEO_CONSOLE, + .ops = &console_ops_2, +}; + +U_BOOT_DRIVER(vidconsole_3) = { + .name = "vidconsole3", + .id = UCLASS_VIDEO_CONSOLE, + .ops = &console_ops_3, + .probe = console_probe_1_3, +}; diff --git a/drivers/video/sandbox_sdl.c b/drivers/video/sandbox_sdl.c index ba4578e9d1..21448a1411 100644 --- a/drivers/video/sandbox_sdl.c +++ b/drivers/video/sandbox_sdl.c @@ -5,75 +5,67 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> -#include <lcd.h> -#include <malloc.h> +#include <video.h> #include <asm/sdl.h> #include <asm/u-boot-sandbox.h> +#include <dm/test.h> DECLARE_GLOBAL_DATA_PTR; enum { - /* Maximum LCD size we support */ + /* Default 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) +static int sandbox_sdl_probe(struct udevice *dev) { -} + struct sandbox_sdl_plat *plat = dev_get_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + int ret; -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)) + ret = sandbox_sdl_init_display(plat->xres, plat->yres, plat->bpix); + if (ret) { puts("LCD init failed\n"); + return ret; + } + uc_priv->xsize = plat->xres; + uc_priv->ysize = plat->yres; + uc_priv->bpix = plat->bpix; + uc_priv->rot = plat->rot; + + return 0; } -int sandbox_lcd_sdl_early_init(void) +static int sandbox_sdl_bind(struct udevice *dev) { + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); + struct sandbox_sdl_plat *plat = dev_get_platdata(dev); const void *blob = gd->fdt_blob; - int xres = LCD_MAX_WIDTH, yres = LCD_MAX_HEIGHT; - int node; + int node = dev->of_offset; 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; + plat->xres = fdtdec_get_int(blob, node, "xres", LCD_MAX_WIDTH); + plat->yres = fdtdec_get_int(blob, node, "yres", LCD_MAX_HEIGHT); + plat->bpix = VIDEO_BPP16; + uc_plat->size = plat->xres * plat->yres * (1 << plat->bpix) / 8; + debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); return ret; } + +static const struct udevice_id sandbox_sdl_ids[] = { + { .compatible = "sandbox,lcd-sdl" }, + { } +}; + +U_BOOT_DRIVER(sdl_sandbox) = { + .name = "sdl_sandbox", + .id = UCLASS_VIDEO, + .of_match = sandbox_sdl_ids, + .bind = sandbox_sdl_bind, + .probe = sandbox_sdl_probe, + .platdata_auto_alloc_size = sizeof(struct sandbox_sdl_plat), +}; diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c new file mode 100644 index 0000000000..ea10189432 --- /dev/null +++ b/drivers/video/vidconsole-uclass.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015 Google, Inc + * (C) Copyright 2001-2015 + * DENX Software Engineering -- wd@denx.de + * Compulab Ltd - http://compulab.co.il/ + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <video.h> +#include <video_console.h> +#include <video_font.h> /* Get font data, width and height */ + +/* By default we scroll by a single line */ +#ifndef CONFIG_CONSOLE_SCROLL_LINES +#define CONFIG_CONSOLE_SCROLL_LINES 1 +#endif + +int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + + if (!ops->putc_xy) + return -ENOSYS; + return ops->putc_xy(dev, x, y, ch); +} + +int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc, + uint count) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + + if (!ops->move_rows) + return -ENOSYS; + return ops->move_rows(dev, rowdst, rowsrc, count); +} + +int vidconsole_set_row(struct udevice *dev, uint row, int clr) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + + if (!ops->set_row) + return -ENOSYS; + return ops->set_row(dev, row, clr); +} + +/* Move backwards one space */ +static void vidconsole_back(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + + if (--priv->curr_col < 0) { + priv->curr_col = priv->cols - 1; + if (--priv->curr_row < 0) + priv->curr_row = 0; + } + + vidconsole_putc_xy(dev, priv->curr_col * VIDEO_FONT_WIDTH, + priv->curr_row * VIDEO_FONT_HEIGHT, ' '); +} + +/* Move to a newline, scrolling the display if necessary */ +static void vidconsole_newline(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct udevice *vid_dev = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); + const int rows = CONFIG_CONSOLE_SCROLL_LINES; + int i; + + priv->curr_col = 0; + + /* Check if we need to scroll the terminal */ + if (++priv->curr_row >= priv->rows) { + vidconsole_move_rows(dev, 0, rows, priv->rows - rows); + for (i = 0; i < rows; i++) + vidconsole_set_row(dev, priv->rows - i - 1, + vid_priv->colour_bg); + priv->curr_row -= rows; + } + video_sync(dev->parent); +} + +int vidconsole_put_char(struct udevice *dev, char ch) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + int ret; + + switch (ch) { + case '\r': + priv->curr_col = 0; + break; + case '\n': + vidconsole_newline(dev); + break; + case '\t': /* Tab (8 chars alignment) */ + priv->curr_col += 8; + priv->curr_col &= ~7; + + if (priv->curr_col >= priv->cols) + vidconsole_newline(dev); + break; + case '\b': + vidconsole_back(dev); + break; + default: + /* + * Failure of this function normally indicates an unsupported + * colour depth. Check this and return an error to help with + * diagnosis. + */ + ret = vidconsole_putc_xy(dev, + priv->curr_col * VIDEO_FONT_WIDTH, + priv->curr_row * VIDEO_FONT_HEIGHT, + ch); + if (ret) + return ret; + if (++priv->curr_col >= priv->cols) + vidconsole_newline(dev); + break; + } + + return 0; +} + +static void vidconsole_putc(struct stdio_dev *sdev, const char ch) +{ + struct udevice *dev = sdev->priv; + + vidconsole_put_char(dev, ch); +} + +static void vidconsole_puts(struct stdio_dev *sdev, const char *s) +{ + struct udevice *dev = sdev->priv; + + while (*s) + vidconsole_put_char(dev, *s++); +} + +/* Set up the number of rows and colours (rotated drivers override this) */ +static int vidconsole_pre_probe(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + + priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT; + priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH; + + return 0; +} + +/* Register the device with stdio */ +static int vidconsole_post_probe(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct stdio_dev *sdev = &priv->sdev; + int ret; + + strlcpy(sdev->name, dev->name, sizeof(sdev->name)); + sdev->flags = DEV_FLAGS_OUTPUT; + sdev->putc = vidconsole_putc; + sdev->puts = vidconsole_puts; + sdev->priv = dev; + ret = stdio_register(sdev); + if (ret) + return ret; + + return 0; +} + +UCLASS_DRIVER(vidconsole) = { + .id = UCLASS_VIDEO_CONSOLE, + .name = "vidconsole0", + .pre_probe = vidconsole_pre_probe, + .post_probe = vidconsole_post_probe, + .per_device_auto_alloc_size = sizeof(struct vidconsole_priv), +}; + +void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + + priv->curr_col = min_t(short, col, priv->cols - 1); + priv->curr_row = min_t(short, row, priv->rows - 1); +} + +static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + unsigned int col, row; + struct udevice *dev; + + if (argc != 3) + return CMD_RET_USAGE; + + uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); + if (!dev) + return CMD_RET_FAILURE; + col = simple_strtoul(argv[1], NULL, 10); + row = simple_strtoul(argv[2], NULL, 10); + vidconsole_position_cursor(dev, col, row); + + return 0; +} + +static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + const char *s; + + if (argc != 2) + return CMD_RET_USAGE; + + uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); + if (!dev) + return CMD_RET_FAILURE; + for (s = argv[1]; *s; s++) + vidconsole_put_char(dev, *s); + + return 0; +} + +U_BOOT_CMD( + setcurs, 3, 1, do_video_setcursor, + "set cursor position within screen", + " <col> <row> in character" +); + +U_BOOT_CMD( + lcdputs, 2, 1, do_video_puts, + "print string on video framebuffer", + " <string>" +); diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c new file mode 100644 index 0000000000..63d0d9d7d3 --- /dev/null +++ b/drivers/video/video-uclass.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <mapmem.h> +#include <stdio_dev.h> +#include <video.h> +#include <video_console.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#ifdef CONFIG_SANDBOX +#include <asm/sdl.h> +#endif + +/* + * Theory of operation: + * + * Before relocation each device is bound. The driver for each device must + * set the @align and @size values in struct video_uc_platdata. This + * information represents the requires size and alignment of the frame buffer + * for the device. The values can be an over-estimate but cannot be too + * small. The actual values will be suppled (in the same manner) by the bind() + * method after relocation. + * + * This information is then picked up by video_reserve() which works out how + * much memory is needed for all devices. This is allocated between + * gd->video_bottom and gd->video_top. + * + * After relocation the same process occurs. The driver supplies the same + * @size and @align information and this time video_post_bind() checks that + * the drivers does not overflow the allocated memory. + * + * The frame buffer address is actually set (to plat->base) in + * video_post_probe(). This function also clears the frame buffer and + * allocates a suitable text console device. This can then be used to write + * text to the video device. + */ +DECLARE_GLOBAL_DATA_PTR; + +static ulong alloc_fb(struct udevice *dev, ulong *addrp) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + ulong base, align, size; + + align = plat->align ? plat->align : 1 << 20; + base = *addrp - plat->size; + base &= ~(align - 1); + plat->base = base; + size = *addrp - base; + *addrp = base; + + return size; +} + +int video_reserve(ulong *addrp) +{ + struct udevice *dev; + ulong size; + + gd->video_top = *addrp; + for (uclass_find_first_device(UCLASS_VIDEO, &dev); + dev; + uclass_find_next_device(&dev)) { + size = alloc_fb(dev, addrp); + debug("%s: Reserving %lx bytes at %lx for video device '%s'\n", + __func__, size, *addrp, dev->name); + } + gd->video_bottom = *addrp; + debug("Video frame buffers from %lx to %lx\n", gd->video_bottom, + gd->video_top); + + return 0; +} + +static int video_clear(struct udevice *dev) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + + if (priv->bpix == VIDEO_BPP32) { + u32 *ppix = priv->fb; + u32 *end = priv->fb + priv->fb_size; + + while (ppix < end) + *ppix++ = priv->colour_bg; + } else { + memset(priv->fb, priv->colour_bg, priv->fb_size); + } + + return 0; +} + +/* Flush video activity to the caches */ +void video_sync(struct udevice *vid) +{ + /* + * 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) + struct video_priv *priv = dev_get_uclass_priv(vid); + + if (priv->flush_dcache) { + flush_dcache_range((ulong)priv->fb, + (ulong)priv->fb + priv->fb_size); + } +#elif defined(CONFIG_VIDEO_SANDBOX_SDL) + struct video_priv *priv = dev_get_uclass_priv(vid); + static ulong last_sync; + + if (get_timer(last_sync) > 10) { + sandbox_sdl_sync(priv->fb); + last_sync = get_timer(0); + } +#endif +} + +void video_sync_all(void) +{ + struct udevice *dev; + + for (uclass_find_first_device(UCLASS_VIDEO, &dev); + dev; + uclass_find_next_device(&dev)) { + if (device_active(dev)) + video_sync(dev); + } +} + +int video_get_xsize(struct udevice *dev) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + + return priv->xsize; +} + +int video_get_ysize(struct udevice *dev) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + + return priv->ysize; +} + +/* Set up the colour map */ +static int video_pre_probe(struct udevice *dev) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + + priv->cmap = calloc(256, sizeof(ushort)); + if (!priv->cmap) + return -ENOMEM; + + return 0; +} + +static int video_pre_remove(struct udevice *dev) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + + free(priv->cmap); + + return 0; +} + +/* Set up the display ready for use */ +static int video_post_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *priv = dev_get_uclass_priv(dev); + char name[30], drv[15], *str; + struct udevice *cons; + int ret; + + /* Set up the line and display size */ + priv->fb = map_sysmem(plat->base, plat->size); + priv->line_length = priv->xsize * VNBYTES(priv->bpix); + priv->fb_size = priv->line_length * priv->ysize; + + /* Set up colours - we could in future support other colours */ +#ifdef CONFIG_SYS_WHITE_ON_BLACK + priv->colour_fg = 0xffffff; +#else + priv->colour_bg = 0xffffff; +#endif + video_clear(dev); + + /* + * Create a text console devices. For now we always do this, although + * it might be useful to support only bitmap drawing on the device + * for boards that don't need to display text. + */ + snprintf(name, sizeof(name), "%s.vidconsole", dev->name); + str = strdup(name); + if (!str) + return -ENOMEM; + snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot); + ret = device_bind_driver(dev, drv, str, &cons); + if (ret) { + debug("%s: Cannot bind console driver\n", __func__); + return ret; + } + ret = device_probe(cons); + if (ret) { + debug("%s: Cannot probe console driver\n", __func__); + return ret; + } + + return 0; +}; + +/* Post-relocation, allocate memory for the frame buffer */ +static int video_post_bind(struct udevice *dev) +{ + ulong addr = gd->video_top; + ulong size; + + /* Before relocation there is nothing to do here */ + if ((!gd->flags & GD_FLG_RELOC)) + return 0; + size = alloc_fb(dev, &addr); + if (addr < gd->video_bottom) { + /* Device tree node may need the 'u-boot,dm-pre-reloc' tag */ + printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n", + dev->name); + return -ENOSPC; + } + debug("%s: Claiming %lx bytes at %lx for video device '%s'\n", + __func__, size, addr, dev->name); + gd->video_bottom = addr; + + return 0; +} + +UCLASS_DRIVER(video) = { + .id = UCLASS_VIDEO, + .name = "video", + .flags = DM_UC_FLAG_SEQ_ALIAS, + .post_bind = video_post_bind, + .pre_probe = video_pre_probe, + .post_probe = video_post_probe, + .pre_remove = video_pre_remove, + .per_device_auto_alloc_size = sizeof(struct video_priv), + .per_device_platdata_auto_alloc_size = sizeof(struct video_uc_platdata), +}; diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c new file mode 100644 index 0000000000..c9075d62dd --- /dev/null +++ b/drivers/video/video_bmp.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <bmp_layout.h> +#include <dm.h> +#include <mapmem.h> +#include <video.h> +#include <watchdog.h> +#include <asm/unaligned.h> + +#ifdef CONFIG_VIDEO_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 col, int cnt) +{ + ushort *fb = *fbp; + + while (cnt > 0) { + *fb++ = col; + cnt--; + } + *fbp = fb; +} + +static void video_display_rle8_bitmap(struct udevice *dev, + struct bmp_image *bmp, ushort *cmap, + uchar *fb, int x_off, int y_off) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + uchar *bmap; + ulong width, height; + ulong cnt, runlen; + int x, y; + int decode = 1; + + debug("%s\n", __func__); + 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 + priv->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 *)(priv->fb + (y + y_off - 1) + * priv->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 */ + +#define BMP_ALIGN_CENTER 0x7fff + +/** + * video_splash_align_axis() - Align a single coordinate + * + *- if a coordinate is 0x7fff then the image will be centred in + * that direction + *- if a coordinate is -ve then it will be offset to the + * left/top of the centre by that many pixels + *- if a coordinate is positive it will be used unchnaged. + * + * @axis: Input and output coordinate + * @panel_size: Size of panel in pixels for that axis + * @picture_size: Size of bitmap in pixels for that axis + */ +static void video_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); +} + +static void video_set_cmap(struct udevice *dev, + struct bmp_color_table_entry *cte, unsigned colours) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + int i; + ushort *cmap = priv->cmap; + + debug("%s: colours=%d\n", __func__, colours); + for (i = 0; i < colours; ++i) { + *cmap = ((cte->red << 8) & 0xf800) | + ((cte->green << 3) & 0x07e0) | + ((cte->blue >> 3) & 0x001f); + cmap++; + cte++; + } +} + +int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, + bool align) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + ushort *cmap_base = NULL; + ushort i, j; + uchar *fb; + struct bmp_image *bmp = map_sysmem(bmp_image, 0); + uchar *bmap; + ushort padded_width; + unsigned long width, height, byte_width; + unsigned long pwidth = priv->xsize; + unsigned colours, bpix, bmp_bpix; + struct bmp_color_table_entry *palette; + int hdr_size; + + if (!bmp || !(bmp->header.signature[0] == 'B' && + bmp->header.signature[1] == 'M')) { + printf("Error: no valid bmp image at %lx\n", bmp_image); + + return -EINVAL; + } + + 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); + palette = (void *)bmp + 14 + hdr_size; + + colours = 1 << bmp_bpix; + + bpix = VNBITS(priv->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 -EINVAL; + } + + /* + * 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 -EPERM; + } + + debug("Display-bmp: %d x %d with %d colours, display %d\n", + (int)width, (int)height, (int)colours, 1 << bpix); + + if (bmp_bpix == 8) + video_set_cmap(dev, palette, colours); + + padded_width = (width & 0x3 ? (width & ~0x3) + 4 : width); + + if (align) { + video_splash_align_axis(&x, priv->xsize, width); + video_splash_align_axis(&y, priv->ysize, height); + } + + if ((x + width) > pwidth) + width = pwidth - x; + if ((y + height) > priv->ysize) + height = priv->ysize - y; + + bmap = (uchar *)bmp + get_unaligned_le32(&bmp->header.data_offset); + fb = (uchar *)(priv->fb + + (y + height - 1) * priv->line_length + x * bpix / 8); + + switch (bmp_bpix) { + case 1: + case 8: { + cmap_base = priv->cmap; +#ifdef CONFIG_VIDEO_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 -EPROTONOSUPPORT; + } + video_display_rle8_bitmap(dev, 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 { + *(uint16_t *)fb = cmap_base[*bmap]; + bmap++; + fb += sizeof(uint16_t) / sizeof(*fb); + } + } + bmap += (padded_width - width); + fb -= byte_width + priv->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_24BMP) + 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_24BMP */ +#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; + }; + + video_sync(dev); + + return 0; +} + |