Skip to content
Snippets Groups Projects
Commit b5146b28 authored by Simon Glass's avatar Simon Glass
Browse files

dm: video: Add a driver for a rotated text console


Sometimes the console must be rotated. Add a driver which supports rotating
the text clockwise to 90, 180 and 270 degrees. This can support devices
where the display is rotated for mechanical reasons.

Signed-off-by: default avatarSimon Glass <sjg@chromium.org>
Acked-by: default avatarAnatolij Gustschin <agust@denx.de>
parent 72cded9e
No related branches found
No related tags found
No related merge requests found
...@@ -44,6 +44,19 @@ config VIDEO_BPP32 ...@@ -44,6 +44,19 @@ config VIDEO_BPP32
this option, such displays will not be supported and console output this option, such displays will not be supported and console output
will be empty. 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 config VIDEO_VESA
bool "Enable VESA video driver support" bool "Enable VESA video driver support"
default n default n
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
ifdef CONFIG_DM ifdef CONFIG_DM
obj-$(CONFIG_DISPLAY_PORT) += dp-uclass.o 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-uclass.o vidconsole-uclass.o console_normal.o
obj-$(CONFIG_VIDEO_ROTATION) += console_rotate.o
endif endif
obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
......
/*
* 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,
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment