diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 946d958f9f..499d00d57e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -44,6 +44,19 @@ config VIDEO_BPP32 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 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index b4eba8e0cc..8f26d1d94e 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -8,6 +8,7 @@ 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_VIDEO_ROTATION) += console_rotate.o endif obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o 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 +#include +#include +#include +#include /* 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, +};