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 } 80*fb0b709eSSimon Glass video_sync(dev->parent); 817b9f7e44SSimon Glass 827b9f7e44SSimon Glass return 0; 8383510766SSimon Glass } 8483510766SSimon Glass 8583510766SSimon Glass /* Move to a newline, scrolling the display if necessary */ 8683510766SSimon Glass static void vidconsole_newline(struct udevice *dev) 8783510766SSimon Glass { 8883510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 8983510766SSimon Glass struct udevice *vid_dev = dev->parent; 9083510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 9183510766SSimon Glass const int rows = CONFIG_CONSOLE_SCROLL_LINES; 9283510766SSimon Glass int i; 9383510766SSimon Glass 94c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 95f2661786SSimon Glass priv->ycur += priv->y_charsize; 9683510766SSimon Glass 9783510766SSimon Glass /* Check if we need to scroll the terminal */ 98f2661786SSimon Glass if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) { 9983510766SSimon Glass vidconsole_move_rows(dev, 0, rows, priv->rows - rows); 10083510766SSimon Glass for (i = 0; i < rows; i++) 10183510766SSimon Glass vidconsole_set_row(dev, priv->rows - i - 1, 10283510766SSimon Glass vid_priv->colour_bg); 103f2661786SSimon Glass priv->ycur -= rows * priv->y_charsize; 10483510766SSimon Glass } 10558c733a7SSimon Glass priv->last_ch = 0; 10658c733a7SSimon Glass 10783510766SSimon Glass video_sync(dev->parent); 10883510766SSimon Glass } 10983510766SSimon Glass 11083510766SSimon Glass int vidconsole_put_char(struct udevice *dev, char ch) 11183510766SSimon Glass { 11283510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 11383510766SSimon Glass int ret; 11483510766SSimon Glass 11583510766SSimon Glass switch (ch) { 1165508f10aSSimon Glass case '\a': 1175508f10aSSimon Glass /* beep */ 1185508f10aSSimon Glass break; 11983510766SSimon Glass case '\r': 120c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 12183510766SSimon Glass break; 12283510766SSimon Glass case '\n': 12383510766SSimon Glass vidconsole_newline(dev); 12458c733a7SSimon Glass vidconsole_entry_start(dev); 12583510766SSimon Glass break; 12683510766SSimon Glass case '\t': /* Tab (8 chars alignment) */ 127f2661786SSimon Glass priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac) 128f2661786SSimon Glass + 1) * priv->tab_width_frac; 12983510766SSimon Glass 130f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 13183510766SSimon Glass vidconsole_newline(dev); 13283510766SSimon Glass break; 13383510766SSimon Glass case '\b': 13483510766SSimon Glass vidconsole_back(dev); 13558c733a7SSimon Glass priv->last_ch = 0; 13683510766SSimon Glass break; 13783510766SSimon Glass default: 13883510766SSimon Glass /* 13983510766SSimon Glass * Failure of this function normally indicates an unsupported 14083510766SSimon Glass * colour depth. Check this and return an error to help with 14183510766SSimon Glass * diagnosis. 14283510766SSimon Glass */ 143f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); 144f2661786SSimon Glass if (ret == -EAGAIN) { 145f2661786SSimon Glass vidconsole_newline(dev); 146f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, 147f2661786SSimon Glass priv->ycur, ch); 148f2661786SSimon Glass } 149f2661786SSimon Glass if (ret < 0) 15083510766SSimon Glass return ret; 151f2661786SSimon Glass priv->xcur_frac += ret; 15258c733a7SSimon Glass priv->last_ch = ch; 153f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 15483510766SSimon Glass vidconsole_newline(dev); 15583510766SSimon Glass break; 15683510766SSimon Glass } 15783510766SSimon Glass 15883510766SSimon Glass return 0; 15983510766SSimon Glass } 16083510766SSimon Glass 16183510766SSimon Glass static void vidconsole_putc(struct stdio_dev *sdev, const char ch) 16283510766SSimon Glass { 16383510766SSimon Glass struct udevice *dev = sdev->priv; 16483510766SSimon Glass 16583510766SSimon Glass vidconsole_put_char(dev, ch); 16683510766SSimon Glass } 16783510766SSimon Glass 16883510766SSimon Glass static void vidconsole_puts(struct stdio_dev *sdev, const char *s) 16983510766SSimon Glass { 17083510766SSimon Glass struct udevice *dev = sdev->priv; 17183510766SSimon Glass 17283510766SSimon Glass while (*s) 17383510766SSimon Glass vidconsole_put_char(dev, *s++); 174bbc8a8b4SSimon Glass video_sync(dev->parent); 17583510766SSimon Glass } 17683510766SSimon Glass 17783510766SSimon Glass /* Set up the number of rows and colours (rotated drivers override this) */ 17883510766SSimon Glass static int vidconsole_pre_probe(struct udevice *dev) 17983510766SSimon Glass { 18083510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 18183510766SSimon Glass struct udevice *vid = dev->parent; 18283510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid); 18383510766SSimon Glass 184f2661786SSimon Glass priv->xsize_frac = VID_TO_POS(vid_priv->xsize); 18583510766SSimon Glass 18683510766SSimon Glass return 0; 18783510766SSimon Glass } 18883510766SSimon Glass 18983510766SSimon Glass /* Register the device with stdio */ 19083510766SSimon Glass static int vidconsole_post_probe(struct udevice *dev) 19183510766SSimon Glass { 19283510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 19383510766SSimon Glass struct stdio_dev *sdev = &priv->sdev; 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 210720873bfSMasahiro Yamada return stdio_register(sdev); 21183510766SSimon Glass } 21283510766SSimon Glass 21383510766SSimon Glass UCLASS_DRIVER(vidconsole) = { 21483510766SSimon Glass .id = UCLASS_VIDEO_CONSOLE, 21583510766SSimon Glass .name = "vidconsole0", 21683510766SSimon Glass .pre_probe = vidconsole_pre_probe, 21783510766SSimon Glass .post_probe = vidconsole_post_probe, 21883510766SSimon Glass .per_device_auto_alloc_size = sizeof(struct vidconsole_priv), 21983510766SSimon Glass }; 22083510766SSimon Glass 22183510766SSimon Glass void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) 22283510766SSimon Glass { 22383510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 224f2661786SSimon Glass struct udevice *vid_dev = dev->parent; 225f2661786SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 22683510766SSimon Glass 227f2661786SSimon Glass priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1)); 228f2661786SSimon Glass priv->ycur = min_t(short, row, vid_priv->ysize - 1); 22983510766SSimon Glass } 23083510766SSimon Glass 23183510766SSimon Glass static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, 23283510766SSimon Glass char *const argv[]) 23383510766SSimon Glass { 23483510766SSimon Glass unsigned int col, row; 23583510766SSimon Glass struct udevice *dev; 23683510766SSimon Glass 23783510766SSimon Glass if (argc != 3) 23883510766SSimon Glass return CMD_RET_USAGE; 23983510766SSimon Glass 2403f603cbbSSimon Glass if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev)) 24183510766SSimon Glass return CMD_RET_FAILURE; 24283510766SSimon Glass col = simple_strtoul(argv[1], NULL, 10); 24383510766SSimon Glass row = simple_strtoul(argv[2], NULL, 10); 24483510766SSimon Glass vidconsole_position_cursor(dev, col, row); 24583510766SSimon Glass 24683510766SSimon Glass return 0; 24783510766SSimon Glass } 24883510766SSimon Glass 24983510766SSimon Glass static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, 25083510766SSimon Glass char *const argv[]) 25183510766SSimon Glass { 25283510766SSimon Glass struct udevice *dev; 25383510766SSimon Glass const char *s; 25483510766SSimon Glass 25583510766SSimon Glass if (argc != 2) 25683510766SSimon Glass return CMD_RET_USAGE; 25783510766SSimon Glass 2583f603cbbSSimon Glass if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev)) 25983510766SSimon Glass return CMD_RET_FAILURE; 26083510766SSimon Glass for (s = argv[1]; *s; s++) 26183510766SSimon Glass vidconsole_put_char(dev, *s); 26283510766SSimon Glass 26383510766SSimon Glass return 0; 26483510766SSimon Glass } 26583510766SSimon Glass 26683510766SSimon Glass U_BOOT_CMD( 26783510766SSimon Glass setcurs, 3, 1, do_video_setcursor, 26883510766SSimon Glass "set cursor position within screen", 26983510766SSimon Glass " <col> <row> in character" 27083510766SSimon Glass ); 27183510766SSimon Glass 27283510766SSimon Glass U_BOOT_CMD( 27383510766SSimon Glass lcdputs, 2, 1, do_video_puts, 27483510766SSimon Glass "print string on video framebuffer", 27583510766SSimon Glass " <string>" 27683510766SSimon Glass ); 277