183510766SSimon Glass /* 283510766SSimon Glass * Copyright (c) 2015 Google, Inc 383510766SSimon Glass * (C) Copyright 2001-2015 483510766SSimon Glass * DENX Software Engineering -- wd@denx.de 583510766SSimon Glass * Compulab Ltd - http://compulab.co.il/ 683510766SSimon Glass * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com 783510766SSimon Glass * 883510766SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 983510766SSimon Glass */ 1083510766SSimon Glass 1183510766SSimon Glass #include <common.h> 1283510766SSimon Glass #include <dm.h> 1383510766SSimon Glass #include <video.h> 1483510766SSimon Glass #include <video_console.h> 1583510766SSimon Glass #include <video_font.h> /* Get font data, width and height */ 1683510766SSimon Glass 1783510766SSimon Glass /* By default we scroll by a single line */ 1883510766SSimon Glass #ifndef CONFIG_CONSOLE_SCROLL_LINES 1983510766SSimon Glass #define CONFIG_CONSOLE_SCROLL_LINES 1 2083510766SSimon Glass #endif 2183510766SSimon Glass 2283510766SSimon Glass int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch) 2383510766SSimon Glass { 2483510766SSimon Glass struct vidconsole_ops *ops = vidconsole_get_ops(dev); 2583510766SSimon Glass 2683510766SSimon Glass if (!ops->putc_xy) 2783510766SSimon Glass return -ENOSYS; 2883510766SSimon Glass return ops->putc_xy(dev, x, y, ch); 2983510766SSimon Glass } 3083510766SSimon Glass 3183510766SSimon Glass int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc, 3283510766SSimon Glass uint count) 3383510766SSimon Glass { 3483510766SSimon Glass struct vidconsole_ops *ops = vidconsole_get_ops(dev); 3583510766SSimon Glass 3683510766SSimon Glass if (!ops->move_rows) 3783510766SSimon Glass return -ENOSYS; 3883510766SSimon Glass return ops->move_rows(dev, rowdst, rowsrc, count); 3983510766SSimon Glass } 4083510766SSimon Glass 4183510766SSimon Glass int vidconsole_set_row(struct udevice *dev, uint row, int clr) 4283510766SSimon Glass { 4383510766SSimon Glass struct vidconsole_ops *ops = vidconsole_get_ops(dev); 4483510766SSimon Glass 4583510766SSimon Glass if (!ops->set_row) 4683510766SSimon Glass return -ENOSYS; 4783510766SSimon Glass return ops->set_row(dev, row, clr); 4883510766SSimon Glass } 4983510766SSimon Glass 5083510766SSimon Glass /* Move backwards one space */ 5183510766SSimon Glass static void vidconsole_back(struct udevice *dev) 5283510766SSimon Glass { 5383510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 5483510766SSimon Glass 55f2661786SSimon Glass priv->xcur_frac -= VID_TO_POS(priv->x_charsize); 56*c5b77d01SSimon Glass if (priv->xcur_frac < priv->xstart_frac) { 57f2661786SSimon Glass priv->xcur_frac = (priv->cols - 1) * 58f2661786SSimon Glass VID_TO_POS(priv->x_charsize); 59f2661786SSimon Glass priv->ycur -= priv->y_charsize; 60f2661786SSimon Glass if (priv->ycur < 0) 61f2661786SSimon Glass priv->ycur = 0; 6283510766SSimon Glass } 6383510766SSimon Glass } 6483510766SSimon Glass 6583510766SSimon Glass /* Move to a newline, scrolling the display if necessary */ 6683510766SSimon Glass static void vidconsole_newline(struct udevice *dev) 6783510766SSimon Glass { 6883510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 6983510766SSimon Glass struct udevice *vid_dev = dev->parent; 7083510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 7183510766SSimon Glass const int rows = CONFIG_CONSOLE_SCROLL_LINES; 7283510766SSimon Glass int i; 7383510766SSimon Glass 74*c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 75f2661786SSimon Glass priv->ycur += priv->y_charsize; 7683510766SSimon Glass 7783510766SSimon Glass /* Check if we need to scroll the terminal */ 78f2661786SSimon Glass if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) { 7983510766SSimon Glass vidconsole_move_rows(dev, 0, rows, priv->rows - rows); 8083510766SSimon Glass for (i = 0; i < rows; i++) 8183510766SSimon Glass vidconsole_set_row(dev, priv->rows - i - 1, 8283510766SSimon Glass vid_priv->colour_bg); 83f2661786SSimon Glass priv->ycur -= rows * priv->y_charsize; 8483510766SSimon Glass } 8583510766SSimon Glass video_sync(dev->parent); 8683510766SSimon Glass } 8783510766SSimon Glass 8883510766SSimon Glass int vidconsole_put_char(struct udevice *dev, char ch) 8983510766SSimon Glass { 9083510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 9183510766SSimon Glass int ret; 9283510766SSimon Glass 9383510766SSimon Glass switch (ch) { 945508f10aSSimon Glass case '\a': 955508f10aSSimon Glass /* beep */ 965508f10aSSimon Glass break; 9783510766SSimon Glass case '\r': 98*c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 9983510766SSimon Glass break; 10083510766SSimon Glass case '\n': 10183510766SSimon Glass vidconsole_newline(dev); 10283510766SSimon Glass break; 10383510766SSimon Glass case '\t': /* Tab (8 chars alignment) */ 104f2661786SSimon Glass priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac) 105f2661786SSimon Glass + 1) * priv->tab_width_frac; 10683510766SSimon Glass 107f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 10883510766SSimon Glass vidconsole_newline(dev); 10983510766SSimon Glass break; 11083510766SSimon Glass case '\b': 11183510766SSimon Glass vidconsole_back(dev); 11283510766SSimon Glass break; 11383510766SSimon Glass default: 11483510766SSimon Glass /* 11583510766SSimon Glass * Failure of this function normally indicates an unsupported 11683510766SSimon Glass * colour depth. Check this and return an error to help with 11783510766SSimon Glass * diagnosis. 11883510766SSimon Glass */ 119f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); 120f2661786SSimon Glass if (ret == -EAGAIN) { 121f2661786SSimon Glass vidconsole_newline(dev); 122f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, 123f2661786SSimon Glass priv->ycur, ch); 124f2661786SSimon Glass } 125f2661786SSimon Glass if (ret < 0) 12683510766SSimon Glass return ret; 127f2661786SSimon Glass priv->xcur_frac += ret; 128f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 12983510766SSimon Glass vidconsole_newline(dev); 13083510766SSimon Glass break; 13183510766SSimon Glass } 13283510766SSimon Glass 13383510766SSimon Glass return 0; 13483510766SSimon Glass } 13583510766SSimon Glass 13683510766SSimon Glass static void vidconsole_putc(struct stdio_dev *sdev, const char ch) 13783510766SSimon Glass { 13883510766SSimon Glass struct udevice *dev = sdev->priv; 13983510766SSimon Glass 14083510766SSimon Glass vidconsole_put_char(dev, ch); 14183510766SSimon Glass } 14283510766SSimon Glass 14383510766SSimon Glass static void vidconsole_puts(struct stdio_dev *sdev, const char *s) 14483510766SSimon Glass { 14583510766SSimon Glass struct udevice *dev = sdev->priv; 14683510766SSimon Glass 14783510766SSimon Glass while (*s) 14883510766SSimon Glass vidconsole_put_char(dev, *s++); 14983510766SSimon Glass } 15083510766SSimon Glass 15183510766SSimon Glass /* Set up the number of rows and colours (rotated drivers override this) */ 15283510766SSimon Glass static int vidconsole_pre_probe(struct udevice *dev) 15383510766SSimon Glass { 15483510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 15583510766SSimon Glass struct udevice *vid = dev->parent; 15683510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid); 15783510766SSimon Glass 158f2661786SSimon Glass priv->xsize_frac = VID_TO_POS(vid_priv->xsize); 15983510766SSimon Glass 16083510766SSimon Glass return 0; 16183510766SSimon Glass } 16283510766SSimon Glass 16383510766SSimon Glass /* Register the device with stdio */ 16483510766SSimon Glass static int vidconsole_post_probe(struct udevice *dev) 16583510766SSimon Glass { 16683510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 16783510766SSimon Glass struct stdio_dev *sdev = &priv->sdev; 16883510766SSimon Glass int ret; 16983510766SSimon Glass 170f2661786SSimon Glass if (!priv->tab_width_frac) 171f2661786SSimon Glass priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8; 172f2661786SSimon Glass 173f1a1247dSSimon Glass if (dev->seq) { 174f1a1247dSSimon Glass snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d", 175f1a1247dSSimon Glass dev->seq); 176f1a1247dSSimon Glass } else { 177f1a1247dSSimon Glass strcpy(sdev->name, "vidconsole"); 178f1a1247dSSimon Glass } 179f2661786SSimon Glass 18083510766SSimon Glass sdev->flags = DEV_FLAGS_OUTPUT; 18183510766SSimon Glass sdev->putc = vidconsole_putc; 18283510766SSimon Glass sdev->puts = vidconsole_puts; 18383510766SSimon Glass sdev->priv = dev; 18483510766SSimon Glass ret = stdio_register(sdev); 18583510766SSimon Glass if (ret) 18683510766SSimon Glass return ret; 18783510766SSimon Glass 18883510766SSimon Glass return 0; 18983510766SSimon Glass } 19083510766SSimon Glass 19183510766SSimon Glass UCLASS_DRIVER(vidconsole) = { 19283510766SSimon Glass .id = UCLASS_VIDEO_CONSOLE, 19383510766SSimon Glass .name = "vidconsole0", 19483510766SSimon Glass .pre_probe = vidconsole_pre_probe, 19583510766SSimon Glass .post_probe = vidconsole_post_probe, 19683510766SSimon Glass .per_device_auto_alloc_size = sizeof(struct vidconsole_priv), 19783510766SSimon Glass }; 19883510766SSimon Glass 19983510766SSimon Glass void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) 20083510766SSimon Glass { 20183510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 202f2661786SSimon Glass struct udevice *vid_dev = dev->parent; 203f2661786SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 20483510766SSimon Glass 205f2661786SSimon Glass priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1)); 206f2661786SSimon Glass priv->ycur = min_t(short, row, vid_priv->ysize - 1); 20783510766SSimon Glass } 20883510766SSimon Glass 20983510766SSimon Glass static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, 21083510766SSimon Glass char *const argv[]) 21183510766SSimon Glass { 21283510766SSimon Glass unsigned int col, row; 21383510766SSimon Glass struct udevice *dev; 21483510766SSimon Glass 21583510766SSimon Glass if (argc != 3) 21683510766SSimon Glass return CMD_RET_USAGE; 21783510766SSimon Glass 21883510766SSimon Glass uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); 21983510766SSimon Glass if (!dev) 22083510766SSimon Glass return CMD_RET_FAILURE; 22183510766SSimon Glass col = simple_strtoul(argv[1], NULL, 10); 22283510766SSimon Glass row = simple_strtoul(argv[2], NULL, 10); 22383510766SSimon Glass vidconsole_position_cursor(dev, col, row); 22483510766SSimon Glass 22583510766SSimon Glass return 0; 22683510766SSimon Glass } 22783510766SSimon Glass 22883510766SSimon Glass static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, 22983510766SSimon Glass char *const argv[]) 23083510766SSimon Glass { 23183510766SSimon Glass struct udevice *dev; 23283510766SSimon Glass const char *s; 23383510766SSimon Glass 23483510766SSimon Glass if (argc != 2) 23583510766SSimon Glass return CMD_RET_USAGE; 23683510766SSimon Glass 23783510766SSimon Glass uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); 23883510766SSimon Glass if (!dev) 23983510766SSimon Glass return CMD_RET_FAILURE; 24083510766SSimon Glass for (s = argv[1]; *s; s++) 24183510766SSimon Glass vidconsole_put_char(dev, *s); 24283510766SSimon Glass 24383510766SSimon Glass return 0; 24483510766SSimon Glass } 24583510766SSimon Glass 24683510766SSimon Glass U_BOOT_CMD( 24783510766SSimon Glass setcurs, 3, 1, do_video_setcursor, 24883510766SSimon Glass "set cursor position within screen", 24983510766SSimon Glass " <col> <row> in character" 25083510766SSimon Glass ); 25183510766SSimon Glass 25283510766SSimon Glass U_BOOT_CMD( 25383510766SSimon Glass lcdputs, 2, 1, do_video_puts, 25483510766SSimon Glass "print string on video framebuffer", 25583510766SSimon Glass " <string>" 25683510766SSimon Glass ); 257