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 5058c733a7SSimon Glass static int vidconsole_entry_start(struct udevice *dev) 5158c733a7SSimon Glass { 5258c733a7SSimon Glass struct vidconsole_ops *ops = vidconsole_get_ops(dev); 5358c733a7SSimon Glass 5458c733a7SSimon Glass if (!ops->entry_start) 5558c733a7SSimon Glass return -ENOSYS; 5658c733a7SSimon Glass return ops->entry_start(dev); 5758c733a7SSimon Glass } 5858c733a7SSimon Glass 5983510766SSimon Glass /* Move backwards one space */ 607b9f7e44SSimon Glass static int vidconsole_back(struct udevice *dev) 6183510766SSimon Glass { 6283510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 637b9f7e44SSimon Glass struct vidconsole_ops *ops = vidconsole_get_ops(dev); 647b9f7e44SSimon Glass int ret; 657b9f7e44SSimon Glass 667b9f7e44SSimon Glass if (ops->backspace) { 677b9f7e44SSimon Glass ret = ops->backspace(dev); 687b9f7e44SSimon Glass if (ret != -ENOSYS) 697b9f7e44SSimon Glass return ret; 707b9f7e44SSimon Glass } 7183510766SSimon Glass 72f2661786SSimon Glass priv->xcur_frac -= VID_TO_POS(priv->x_charsize); 73c5b77d01SSimon Glass if (priv->xcur_frac < priv->xstart_frac) { 74f2661786SSimon Glass priv->xcur_frac = (priv->cols - 1) * 75f2661786SSimon Glass VID_TO_POS(priv->x_charsize); 76f2661786SSimon Glass priv->ycur -= priv->y_charsize; 77f2661786SSimon Glass if (priv->ycur < 0) 78f2661786SSimon Glass priv->ycur = 0; 7983510766SSimon Glass } 807b9f7e44SSimon Glass 817b9f7e44SSimon Glass return 0; 8283510766SSimon Glass } 8383510766SSimon Glass 8483510766SSimon Glass /* Move to a newline, scrolling the display if necessary */ 8583510766SSimon Glass static void vidconsole_newline(struct udevice *dev) 8683510766SSimon Glass { 8783510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 8883510766SSimon Glass struct udevice *vid_dev = dev->parent; 8983510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 9083510766SSimon Glass const int rows = CONFIG_CONSOLE_SCROLL_LINES; 9183510766SSimon Glass int i; 9283510766SSimon Glass 93c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 94f2661786SSimon Glass priv->ycur += priv->y_charsize; 9583510766SSimon Glass 9683510766SSimon Glass /* Check if we need to scroll the terminal */ 97f2661786SSimon Glass if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) { 9883510766SSimon Glass vidconsole_move_rows(dev, 0, rows, priv->rows - rows); 9983510766SSimon Glass for (i = 0; i < rows; i++) 10083510766SSimon Glass vidconsole_set_row(dev, priv->rows - i - 1, 10183510766SSimon Glass vid_priv->colour_bg); 102f2661786SSimon Glass priv->ycur -= rows * priv->y_charsize; 10383510766SSimon Glass } 10458c733a7SSimon Glass priv->last_ch = 0; 10558c733a7SSimon Glass 10683510766SSimon Glass video_sync(dev->parent); 10783510766SSimon Glass } 10883510766SSimon Glass 10983510766SSimon Glass int vidconsole_put_char(struct udevice *dev, char ch) 11083510766SSimon Glass { 11183510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 11283510766SSimon Glass int ret; 11383510766SSimon Glass 11483510766SSimon Glass switch (ch) { 1155508f10aSSimon Glass case '\a': 1165508f10aSSimon Glass /* beep */ 1175508f10aSSimon Glass break; 11883510766SSimon Glass case '\r': 119c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 12083510766SSimon Glass break; 12183510766SSimon Glass case '\n': 12283510766SSimon Glass vidconsole_newline(dev); 12358c733a7SSimon Glass vidconsole_entry_start(dev); 12483510766SSimon Glass break; 12583510766SSimon Glass case '\t': /* Tab (8 chars alignment) */ 126f2661786SSimon Glass priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac) 127f2661786SSimon Glass + 1) * priv->tab_width_frac; 12883510766SSimon Glass 129f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 13083510766SSimon Glass vidconsole_newline(dev); 13183510766SSimon Glass break; 13283510766SSimon Glass case '\b': 13383510766SSimon Glass vidconsole_back(dev); 13458c733a7SSimon Glass priv->last_ch = 0; 13583510766SSimon Glass break; 13683510766SSimon Glass default: 13783510766SSimon Glass /* 13883510766SSimon Glass * Failure of this function normally indicates an unsupported 13983510766SSimon Glass * colour depth. Check this and return an error to help with 14083510766SSimon Glass * diagnosis. 14183510766SSimon Glass */ 142f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); 143f2661786SSimon Glass if (ret == -EAGAIN) { 144f2661786SSimon Glass vidconsole_newline(dev); 145f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, 146f2661786SSimon Glass priv->ycur, ch); 147f2661786SSimon Glass } 148f2661786SSimon Glass if (ret < 0) 14983510766SSimon Glass return ret; 150f2661786SSimon Glass priv->xcur_frac += ret; 15158c733a7SSimon Glass priv->last_ch = ch; 152f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 15383510766SSimon Glass vidconsole_newline(dev); 15483510766SSimon Glass break; 15583510766SSimon Glass } 15683510766SSimon Glass 15783510766SSimon Glass return 0; 15883510766SSimon Glass } 15983510766SSimon Glass 16083510766SSimon Glass static void vidconsole_putc(struct stdio_dev *sdev, const char ch) 16183510766SSimon Glass { 16283510766SSimon Glass struct udevice *dev = sdev->priv; 16383510766SSimon Glass 16483510766SSimon Glass vidconsole_put_char(dev, ch); 16583510766SSimon Glass } 16683510766SSimon Glass 16783510766SSimon Glass static void vidconsole_puts(struct stdio_dev *sdev, const char *s) 16883510766SSimon Glass { 16983510766SSimon Glass struct udevice *dev = sdev->priv; 17083510766SSimon Glass 17183510766SSimon Glass while (*s) 17283510766SSimon Glass vidconsole_put_char(dev, *s++); 173*bbc8a8b4SSimon Glass video_sync(dev->parent); 17483510766SSimon Glass } 17583510766SSimon Glass 17683510766SSimon Glass /* Set up the number of rows and colours (rotated drivers override this) */ 17783510766SSimon Glass static int vidconsole_pre_probe(struct udevice *dev) 17883510766SSimon Glass { 17983510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 18083510766SSimon Glass struct udevice *vid = dev->parent; 18183510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid); 18283510766SSimon Glass 183f2661786SSimon Glass priv->xsize_frac = VID_TO_POS(vid_priv->xsize); 18483510766SSimon Glass 18583510766SSimon Glass return 0; 18683510766SSimon Glass } 18783510766SSimon Glass 18883510766SSimon Glass /* Register the device with stdio */ 18983510766SSimon Glass static int vidconsole_post_probe(struct udevice *dev) 19083510766SSimon Glass { 19183510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 19283510766SSimon Glass struct stdio_dev *sdev = &priv->sdev; 19383510766SSimon Glass int ret; 19483510766SSimon Glass 195f2661786SSimon Glass if (!priv->tab_width_frac) 196f2661786SSimon Glass priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8; 197f2661786SSimon Glass 198f1a1247dSSimon Glass if (dev->seq) { 199f1a1247dSSimon Glass snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d", 200f1a1247dSSimon Glass dev->seq); 201f1a1247dSSimon Glass } else { 202f1a1247dSSimon Glass strcpy(sdev->name, "vidconsole"); 203f1a1247dSSimon Glass } 204f2661786SSimon Glass 20583510766SSimon Glass sdev->flags = DEV_FLAGS_OUTPUT; 20683510766SSimon Glass sdev->putc = vidconsole_putc; 20783510766SSimon Glass sdev->puts = vidconsole_puts; 20883510766SSimon Glass sdev->priv = dev; 20983510766SSimon Glass ret = stdio_register(sdev); 21083510766SSimon Glass if (ret) 21183510766SSimon Glass return ret; 21283510766SSimon Glass 21383510766SSimon Glass return 0; 21483510766SSimon Glass } 21583510766SSimon Glass 21683510766SSimon Glass UCLASS_DRIVER(vidconsole) = { 21783510766SSimon Glass .id = UCLASS_VIDEO_CONSOLE, 21883510766SSimon Glass .name = "vidconsole0", 21983510766SSimon Glass .pre_probe = vidconsole_pre_probe, 22083510766SSimon Glass .post_probe = vidconsole_post_probe, 22183510766SSimon Glass .per_device_auto_alloc_size = sizeof(struct vidconsole_priv), 22283510766SSimon Glass }; 22383510766SSimon Glass 22483510766SSimon Glass void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) 22583510766SSimon Glass { 22683510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 227f2661786SSimon Glass struct udevice *vid_dev = dev->parent; 228f2661786SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 22983510766SSimon Glass 230f2661786SSimon Glass priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1)); 231f2661786SSimon Glass priv->ycur = min_t(short, row, vid_priv->ysize - 1); 23283510766SSimon Glass } 23383510766SSimon Glass 23483510766SSimon Glass static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, 23583510766SSimon Glass char *const argv[]) 23683510766SSimon Glass { 23783510766SSimon Glass unsigned int col, row; 23883510766SSimon Glass struct udevice *dev; 23983510766SSimon Glass 24083510766SSimon Glass if (argc != 3) 24183510766SSimon Glass return CMD_RET_USAGE; 24283510766SSimon Glass 24383510766SSimon Glass uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); 24483510766SSimon Glass if (!dev) 24583510766SSimon Glass return CMD_RET_FAILURE; 24683510766SSimon Glass col = simple_strtoul(argv[1], NULL, 10); 24783510766SSimon Glass row = simple_strtoul(argv[2], NULL, 10); 24883510766SSimon Glass vidconsole_position_cursor(dev, col, row); 24983510766SSimon Glass 25083510766SSimon Glass return 0; 25183510766SSimon Glass } 25283510766SSimon Glass 25383510766SSimon Glass static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, 25483510766SSimon Glass char *const argv[]) 25583510766SSimon Glass { 25683510766SSimon Glass struct udevice *dev; 25783510766SSimon Glass const char *s; 25883510766SSimon Glass 25983510766SSimon Glass if (argc != 2) 26083510766SSimon Glass return CMD_RET_USAGE; 26183510766SSimon Glass 26283510766SSimon Glass uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); 26383510766SSimon Glass if (!dev) 26483510766SSimon Glass return CMD_RET_FAILURE; 26583510766SSimon Glass for (s = argv[1]; *s; s++) 26683510766SSimon Glass vidconsole_put_char(dev, *s); 26783510766SSimon Glass 26883510766SSimon Glass return 0; 26983510766SSimon Glass } 27083510766SSimon Glass 27183510766SSimon Glass U_BOOT_CMD( 27283510766SSimon Glass setcurs, 3, 1, do_video_setcursor, 27383510766SSimon Glass "set cursor position within screen", 27483510766SSimon Glass " <col> <row> in character" 27583510766SSimon Glass ); 27683510766SSimon Glass 27783510766SSimon Glass U_BOOT_CMD( 27883510766SSimon Glass lcdputs, 2, 1, do_video_puts, 27983510766SSimon Glass "print string on video framebuffer", 28083510766SSimon Glass " <string>" 28183510766SSimon Glass ); 282