Commit 83510766c90a52e58477267704fc5ca8f75c3dab

Authored by Simon Glass
1 parent 6cbf5de708

dm: video: Add a uclass for the text console

The existing LCD/video interface suffers from conflating the bitmap display
with text output on that display. As a result the implementation is more
complex than it needs to me.

We can support multiple text console drivers. Create a separate uclass to
support this, with its own API.

Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Anatolij Gustschin <agust@denx.de>

Showing 5 changed files with 398 additions and 1 deletions Side-by-side Diff

drivers/video/Makefile
... ... @@ -7,7 +7,7 @@
7 7  
8 8 ifdef CONFIG_DM
9 9 obj-$(CONFIG_DISPLAY_PORT) += dp-uclass.o
10   -obj-$(CONFIG_DM_VIDEO) += video-uclass.o
  10 +obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o
11 11 endif
12 12  
13 13 obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
drivers/video/vidconsole-uclass.c
  1 +/*
  2 + * Copyright (c) 2015 Google, Inc
  3 + * (C) Copyright 2001-2015
  4 + * DENX Software Engineering -- wd@denx.de
  5 + * Compulab Ltd - http://compulab.co.il/
  6 + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
  7 + *
  8 + * SPDX-License-Identifier: GPL-2.0+
  9 + */
  10 +
  11 +#include <common.h>
  12 +#include <dm.h>
  13 +#include <video.h>
  14 +#include <video_console.h>
  15 +#include <video_font.h> /* Get font data, width and height */
  16 +
  17 +/* By default we scroll by a single line */
  18 +#ifndef CONFIG_CONSOLE_SCROLL_LINES
  19 +#define CONFIG_CONSOLE_SCROLL_LINES 1
  20 +#endif
  21 +
  22 +int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch)
  23 +{
  24 + struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  25 +
  26 + if (!ops->putc_xy)
  27 + return -ENOSYS;
  28 + return ops->putc_xy(dev, x, y, ch);
  29 +}
  30 +
  31 +int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
  32 + uint count)
  33 +{
  34 + struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  35 +
  36 + if (!ops->move_rows)
  37 + return -ENOSYS;
  38 + return ops->move_rows(dev, rowdst, rowsrc, count);
  39 +}
  40 +
  41 +int vidconsole_set_row(struct udevice *dev, uint row, int clr)
  42 +{
  43 + struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  44 +
  45 + if (!ops->set_row)
  46 + return -ENOSYS;
  47 + return ops->set_row(dev, row, clr);
  48 +}
  49 +
  50 +/* Move backwards one space */
  51 +static void vidconsole_back(struct udevice *dev)
  52 +{
  53 + struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  54 +
  55 + if (--priv->curr_col < 0) {
  56 + priv->curr_col = priv->cols - 1;
  57 + if (--priv->curr_row < 0)
  58 + priv->curr_row = 0;
  59 + }
  60 +
  61 + vidconsole_putc_xy(dev, priv->curr_col * VIDEO_FONT_WIDTH,
  62 + priv->curr_row * VIDEO_FONT_HEIGHT, ' ');
  63 +}
  64 +
  65 +/* Move to a newline, scrolling the display if necessary */
  66 +static void vidconsole_newline(struct udevice *dev)
  67 +{
  68 + struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  69 + struct udevice *vid_dev = dev->parent;
  70 + struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  71 + const int rows = CONFIG_CONSOLE_SCROLL_LINES;
  72 + int i;
  73 +
  74 + priv->curr_col = 0;
  75 +
  76 + /* Check if we need to scroll the terminal */
  77 + if (++priv->curr_row >= priv->rows) {
  78 + vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
  79 + for (i = 0; i < rows; i++)
  80 + vidconsole_set_row(dev, priv->rows - i - 1,
  81 + vid_priv->colour_bg);
  82 + priv->curr_row -= rows;
  83 + }
  84 + video_sync(dev->parent);
  85 +}
  86 +
  87 +int vidconsole_put_char(struct udevice *dev, char ch)
  88 +{
  89 + struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  90 + int ret;
  91 +
  92 + switch (ch) {
  93 + case '\r':
  94 + priv->curr_col = 0;
  95 + break;
  96 + case '\n':
  97 + vidconsole_newline(dev);
  98 + break;
  99 + case '\t': /* Tab (8 chars alignment) */
  100 + priv->curr_col += 8;
  101 + priv->curr_col &= ~7;
  102 +
  103 + if (priv->curr_col >= priv->cols)
  104 + vidconsole_newline(dev);
  105 + break;
  106 + case '\b':
  107 + vidconsole_back(dev);
  108 + break;
  109 + default:
  110 + /*
  111 + * Failure of this function normally indicates an unsupported
  112 + * colour depth. Check this and return an error to help with
  113 + * diagnosis.
  114 + */
  115 + ret = vidconsole_putc_xy(dev,
  116 + priv->curr_col * VIDEO_FONT_WIDTH,
  117 + priv->curr_row * VIDEO_FONT_HEIGHT,
  118 + ch);
  119 + if (ret)
  120 + return ret;
  121 + if (++priv->curr_col >= priv->cols)
  122 + vidconsole_newline(dev);
  123 + break;
  124 + }
  125 +
  126 + return 0;
  127 +}
  128 +
  129 +static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
  130 +{
  131 + struct udevice *dev = sdev->priv;
  132 +
  133 + vidconsole_put_char(dev, ch);
  134 +}
  135 +
  136 +static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
  137 +{
  138 + struct udevice *dev = sdev->priv;
  139 +
  140 + while (*s)
  141 + vidconsole_put_char(dev, *s++);
  142 +}
  143 +
  144 +/* Set up the number of rows and colours (rotated drivers override this) */
  145 +static int vidconsole_pre_probe(struct udevice *dev)
  146 +{
  147 + struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  148 + struct udevice *vid = dev->parent;
  149 + struct video_priv *vid_priv = dev_get_uclass_priv(vid);
  150 +
  151 + priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT;
  152 + priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH;
  153 +
  154 + return 0;
  155 +}
  156 +
  157 +/* Register the device with stdio */
  158 +static int vidconsole_post_probe(struct udevice *dev)
  159 +{
  160 + struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  161 + struct stdio_dev *sdev = &priv->sdev;
  162 + int ret;
  163 +
  164 + strlcpy(sdev->name, dev->name, sizeof(sdev->name));
  165 + sdev->flags = DEV_FLAGS_OUTPUT;
  166 + sdev->putc = vidconsole_putc;
  167 + sdev->puts = vidconsole_puts;
  168 + sdev->priv = dev;
  169 + ret = stdio_register(sdev);
  170 + if (ret)
  171 + return ret;
  172 +
  173 + return 0;
  174 +}
  175 +
  176 +UCLASS_DRIVER(vidconsole) = {
  177 + .id = UCLASS_VIDEO_CONSOLE,
  178 + .name = "vidconsole0",
  179 + .pre_probe = vidconsole_pre_probe,
  180 + .post_probe = vidconsole_post_probe,
  181 + .per_device_auto_alloc_size = sizeof(struct vidconsole_priv),
  182 +};
  183 +
  184 +void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
  185 +{
  186 + struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  187 +
  188 + priv->curr_col = min_t(short, col, priv->cols - 1);
  189 + priv->curr_row = min_t(short, row, priv->rows - 1);
  190 +}
  191 +
  192 +static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
  193 + char *const argv[])
  194 +{
  195 + unsigned int col, row;
  196 + struct udevice *dev;
  197 +
  198 + if (argc != 3)
  199 + return CMD_RET_USAGE;
  200 +
  201 + uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
  202 + if (!dev)
  203 + return CMD_RET_FAILURE;
  204 + col = simple_strtoul(argv[1], NULL, 10);
  205 + row = simple_strtoul(argv[2], NULL, 10);
  206 + vidconsole_position_cursor(dev, col, row);
  207 +
  208 + return 0;
  209 +}
  210 +
  211 +static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
  212 + char *const argv[])
  213 +{
  214 + struct udevice *dev;
  215 + const char *s;
  216 +
  217 + if (argc != 2)
  218 + return CMD_RET_USAGE;
  219 +
  220 + uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
  221 + if (!dev)
  222 + return CMD_RET_FAILURE;
  223 + for (s = argv[1]; *s; s++)
  224 + vidconsole_put_char(dev, *s);
  225 +
  226 + return 0;
  227 +}
  228 +
  229 +U_BOOT_CMD(
  230 + setcurs, 3, 1, do_video_setcursor,
  231 + "set cursor position within screen",
  232 + " <col> <row> in character"
  233 +);
  234 +
  235 +U_BOOT_CMD(
  236 + lcdputs, 2, 1, do_video_puts,
  237 + "print string on video framebuffer",
  238 + " <string>"
  239 +);
drivers/video/video-uclass.c
... ... @@ -189,6 +189,27 @@
189 189 #endif
190 190 video_clear(dev);
191 191  
  192 + /*
  193 + * Create a text console devices. For now we always do this, although
  194 + * it might be useful to support only bitmap drawing on the device
  195 + * for boards that don't need to display text.
  196 + */
  197 + snprintf(name, sizeof(name), "%s.vidconsole", dev->name);
  198 + str = strdup(name);
  199 + if (!str)
  200 + return -ENOMEM;
  201 + snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot);
  202 + ret = device_bind_driver(dev, drv, str, &cons);
  203 + if (ret) {
  204 + debug("%s: Cannot bind console driver\n", __func__);
  205 + return ret;
  206 + }
  207 + ret = device_probe(cons);
  208 + if (ret) {
  209 + debug("%s: Cannot probe console driver\n", __func__);
  210 + return ret;
  211 + }
  212 +
192 213 return 0;
193 214 };
194 215  
include/dm/uclass-id.h
... ... @@ -68,6 +68,7 @@
68 68 UCLASS_USB_HUB, /* USB hub */
69 69 UCLASS_VIDEO, /* Video or LCD device */
70 70 UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
  71 + UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */
71 72  
72 73 UCLASS_COUNT,
73 74 UCLASS_INVALID = -1,
include/video_console.h
  1 +/*
  2 + * Copyright (c) 2015 Google, Inc
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#ifndef __video_console_h
  8 +#define __video_console_h
  9 +
  10 +/**
  11 + * struct vidconsole_priv - uclass-private data about a console device
  12 + *
  13 + * @sdev: stdio device, acting as an output sink
  14 + * @curr_col: Current text column (0=left)
  15 + * @curr_row: Current row (0=top)
  16 + * @rows: Number of text rows
  17 + * @cols: Number of text columns
  18 + */
  19 +struct vidconsole_priv {
  20 + struct stdio_dev sdev;
  21 + int curr_col;
  22 + int curr_row;
  23 + int rows;
  24 + int cols;
  25 +};
  26 +
  27 +/**
  28 + * struct vidconsole_ops - Video console operations
  29 + *
  30 + * These operations work on either an absolute console position (measured
  31 + * in pixels) or a text row number (measured in rows, where each row consists
  32 + * of an entire line of text - typically 16 pixels).
  33 + */
  34 +struct vidconsole_ops {
  35 + /**
  36 + * putc_xy() - write a single character to a position
  37 + *
  38 + * @dev: Device to write to
  39 + * @x: Pixel X position (0=left-most pixel)
  40 + * @y: Pixel Y position (0=top-most pixel)
  41 + * @ch: Character to write
  42 + * @return 0 if OK, -ve on error
  43 + */
  44 + int (*putc_xy)(struct udevice *dev, uint x, uint y, char ch);
  45 +
  46 + /**
  47 + * move_rows() - Move text rows from one place to another
  48 + *
  49 + * @dev: Device to adjust
  50 + * @rowdst: Destination text row (0=top)
  51 + * @rowsrc: Source start text row
  52 + * @count: Number of text rows to move
  53 + * @return 0 if OK, -ve on error
  54 + */
  55 + int (*move_rows)(struct udevice *dev, uint rowdst, uint rowsrc,
  56 + uint count);
  57 +
  58 + /**
  59 + * set_row() - Set the colour of a text row
  60 + *
  61 + * Every pixel contained within the text row is adjusted
  62 + *
  63 + * @dev: Device to adjust
  64 + * @row: Text row to adjust (0=top)
  65 + * @clr: Raw colour (pixel value) to write to each pixel
  66 + * @return 0 if OK, -ve on error
  67 + */
  68 + int (*set_row)(struct udevice *dev, uint row, int clr);
  69 +};
  70 +
  71 +/* Get a pointer to the driver operations for a video console device */
  72 +#define vidconsole_get_ops(dev) ((struct vidconsole_ops *)(dev)->driver->ops)
  73 +
  74 +/**
  75 + * vidconsole_putc_xy() - write a single character to a position
  76 + *
  77 + * @dev: Device to write to
  78 + * @x: Pixel X position (0=left-most pixel)
  79 + * @y: Pixel Y position (0=top-most pixel)
  80 + * @ch: Character to write
  81 + * @return 0 if OK, -ve on error
  82 + */
  83 +int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch);
  84 +
  85 +/**
  86 + * vidconsole_move_rows() - Move text rows from one place to another
  87 + *
  88 + * @dev: Device to adjust
  89 + * @rowdst: Destination text row (0=top)
  90 + * @rowsrc: Source start text row
  91 + * @count: Number of text rows to move
  92 + * @return 0 if OK, -ve on error
  93 + */
  94 +int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
  95 + uint count);
  96 +
  97 +/**
  98 + * vidconsole_set_row() - Set the colour of a text row
  99 + *
  100 + * Every pixel contained within the text row is adjusted
  101 + *
  102 + * @dev: Device to adjust
  103 + * @row: Text row to adjust (0=top)
  104 + * @clr: Raw colour (pixel value) to write to each pixel
  105 + * @return 0 if OK, -ve on error
  106 + */
  107 +int vidconsole_set_row(struct udevice *dev, uint row, int clr);
  108 +
  109 +/**
  110 + * vidconsole_put_char() - Output a character to the current console position
  111 + *
  112 + * Outputs a character to the console and advances the cursor. This function
  113 + * handles wrapping to new lines and scrolling the console. Special
  114 + * characters are handled also: \n, \r, \b and \t.
  115 + *
  116 + * The device always starts with the cursor at position 0,0 (top left). It
  117 + * can be adjusted manually using vidconsole_position_cursor().
  118 + *
  119 + * @dev: Device to adjust
  120 + * @ch: Character to write
  121 + * @return 0 if OK, -ve on error
  122 + */
  123 +int vidconsole_put_char(struct udevice *dev, char ch);
  124 +
  125 +/**
  126 + * vidconsole_position_cursor() - Move the text cursor
  127 + *
  128 + * @dev: Device to adjust
  129 + * @col: New cursor text column
  130 + * @row: New cursor text row
  131 + * @return 0 if OK, -ve on error
  132 + */
  133 +void vidconsole_position_cursor(struct udevice *dev, unsigned col,
  134 + unsigned row);
  135 +
  136 +#endif