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 50*58c733a7SSimon Glass static int vidconsole_entry_start(struct udevice *dev) 51*58c733a7SSimon Glass { 52*58c733a7SSimon Glass struct vidconsole_ops *ops = vidconsole_get_ops(dev); 53*58c733a7SSimon Glass 54*58c733a7SSimon Glass if (!ops->entry_start) 55*58c733a7SSimon Glass return -ENOSYS; 56*58c733a7SSimon Glass return ops->entry_start(dev); 57*58c733a7SSimon Glass } 58*58c733a7SSimon Glass 5983510766SSimon Glass /* Move backwards one space */ 6083510766SSimon Glass static void vidconsole_back(struct udevice *dev) 6183510766SSimon Glass { 6283510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 6383510766SSimon Glass 64f2661786SSimon Glass priv->xcur_frac -= VID_TO_POS(priv->x_charsize); 65c5b77d01SSimon Glass if (priv->xcur_frac < priv->xstart_frac) { 66f2661786SSimon Glass priv->xcur_frac = (priv->cols - 1) * 67f2661786SSimon Glass VID_TO_POS(priv->x_charsize); 68f2661786SSimon Glass priv->ycur -= priv->y_charsize; 69f2661786SSimon Glass if (priv->ycur < 0) 70f2661786SSimon Glass priv->ycur = 0; 7183510766SSimon Glass } 7283510766SSimon Glass } 7383510766SSimon Glass 7483510766SSimon Glass /* Move to a newline, scrolling the display if necessary */ 7583510766SSimon Glass static void vidconsole_newline(struct udevice *dev) 7683510766SSimon Glass { 7783510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 7883510766SSimon Glass struct udevice *vid_dev = dev->parent; 7983510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 8083510766SSimon Glass const int rows = CONFIG_CONSOLE_SCROLL_LINES; 8183510766SSimon Glass int i; 8283510766SSimon Glass 83c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 84f2661786SSimon Glass priv->ycur += priv->y_charsize; 8583510766SSimon Glass 8683510766SSimon Glass /* Check if we need to scroll the terminal */ 87f2661786SSimon Glass if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) { 8883510766SSimon Glass vidconsole_move_rows(dev, 0, rows, priv->rows - rows); 8983510766SSimon Glass for (i = 0; i < rows; i++) 9083510766SSimon Glass vidconsole_set_row(dev, priv->rows - i - 1, 9183510766SSimon Glass vid_priv->colour_bg); 92f2661786SSimon Glass priv->ycur -= rows * priv->y_charsize; 9383510766SSimon Glass } 94*58c733a7SSimon Glass priv->last_ch = 0; 95*58c733a7SSimon Glass 9683510766SSimon Glass video_sync(dev->parent); 9783510766SSimon Glass } 9883510766SSimon Glass 9983510766SSimon Glass int vidconsole_put_char(struct udevice *dev, char ch) 10083510766SSimon Glass { 10183510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 10283510766SSimon Glass int ret; 10383510766SSimon Glass 10483510766SSimon Glass switch (ch) { 1055508f10aSSimon Glass case '\a': 1065508f10aSSimon Glass /* beep */ 1075508f10aSSimon Glass break; 10883510766SSimon Glass case '\r': 109c5b77d01SSimon Glass priv->xcur_frac = priv->xstart_frac; 11083510766SSimon Glass break; 11183510766SSimon Glass case '\n': 11283510766SSimon Glass vidconsole_newline(dev); 113*58c733a7SSimon Glass vidconsole_entry_start(dev); 11483510766SSimon Glass break; 11583510766SSimon Glass case '\t': /* Tab (8 chars alignment) */ 116f2661786SSimon Glass priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac) 117f2661786SSimon Glass + 1) * priv->tab_width_frac; 11883510766SSimon Glass 119f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 12083510766SSimon Glass vidconsole_newline(dev); 12183510766SSimon Glass break; 12283510766SSimon Glass case '\b': 12383510766SSimon Glass vidconsole_back(dev); 124*58c733a7SSimon Glass priv->last_ch = 0; 12583510766SSimon Glass break; 12683510766SSimon Glass default: 12783510766SSimon Glass /* 12883510766SSimon Glass * Failure of this function normally indicates an unsupported 12983510766SSimon Glass * colour depth. Check this and return an error to help with 13083510766SSimon Glass * diagnosis. 13183510766SSimon Glass */ 132f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); 133f2661786SSimon Glass if (ret == -EAGAIN) { 134f2661786SSimon Glass vidconsole_newline(dev); 135f2661786SSimon Glass ret = vidconsole_putc_xy(dev, priv->xcur_frac, 136f2661786SSimon Glass priv->ycur, ch); 137f2661786SSimon Glass } 138f2661786SSimon Glass if (ret < 0) 13983510766SSimon Glass return ret; 140f2661786SSimon Glass priv->xcur_frac += ret; 141*58c733a7SSimon Glass priv->last_ch = ch; 142f2661786SSimon Glass if (priv->xcur_frac >= priv->xsize_frac) 14383510766SSimon Glass vidconsole_newline(dev); 14483510766SSimon Glass break; 14583510766SSimon Glass } 14683510766SSimon Glass 14783510766SSimon Glass return 0; 14883510766SSimon Glass } 14983510766SSimon Glass 15083510766SSimon Glass static void vidconsole_putc(struct stdio_dev *sdev, const char ch) 15183510766SSimon Glass { 15283510766SSimon Glass struct udevice *dev = sdev->priv; 15383510766SSimon Glass 15483510766SSimon Glass vidconsole_put_char(dev, ch); 15583510766SSimon Glass } 15683510766SSimon Glass 15783510766SSimon Glass static void vidconsole_puts(struct stdio_dev *sdev, const char *s) 15883510766SSimon Glass { 15983510766SSimon Glass struct udevice *dev = sdev->priv; 16083510766SSimon Glass 16183510766SSimon Glass while (*s) 16283510766SSimon Glass vidconsole_put_char(dev, *s++); 16383510766SSimon Glass } 16483510766SSimon Glass 16583510766SSimon Glass /* Set up the number of rows and colours (rotated drivers override this) */ 16683510766SSimon Glass static int vidconsole_pre_probe(struct udevice *dev) 16783510766SSimon Glass { 16883510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 16983510766SSimon Glass struct udevice *vid = dev->parent; 17083510766SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid); 17183510766SSimon Glass 172f2661786SSimon Glass priv->xsize_frac = VID_TO_POS(vid_priv->xsize); 17383510766SSimon Glass 17483510766SSimon Glass return 0; 17583510766SSimon Glass } 17683510766SSimon Glass 17783510766SSimon Glass /* Register the device with stdio */ 17883510766SSimon Glass static int vidconsole_post_probe(struct udevice *dev) 17983510766SSimon Glass { 18083510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 18183510766SSimon Glass struct stdio_dev *sdev = &priv->sdev; 18283510766SSimon Glass int ret; 18383510766SSimon Glass 184f2661786SSimon Glass if (!priv->tab_width_frac) 185f2661786SSimon Glass priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8; 186f2661786SSimon Glass 187f1a1247dSSimon Glass if (dev->seq) { 188f1a1247dSSimon Glass snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d", 189f1a1247dSSimon Glass dev->seq); 190f1a1247dSSimon Glass } else { 191f1a1247dSSimon Glass strcpy(sdev->name, "vidconsole"); 192f1a1247dSSimon Glass } 193f2661786SSimon Glass 19483510766SSimon Glass sdev->flags = DEV_FLAGS_OUTPUT; 19583510766SSimon Glass sdev->putc = vidconsole_putc; 19683510766SSimon Glass sdev->puts = vidconsole_puts; 19783510766SSimon Glass sdev->priv = dev; 19883510766SSimon Glass ret = stdio_register(sdev); 19983510766SSimon Glass if (ret) 20083510766SSimon Glass return ret; 20183510766SSimon Glass 20283510766SSimon Glass return 0; 20383510766SSimon Glass } 20483510766SSimon Glass 20583510766SSimon Glass UCLASS_DRIVER(vidconsole) = { 20683510766SSimon Glass .id = UCLASS_VIDEO_CONSOLE, 20783510766SSimon Glass .name = "vidconsole0", 20883510766SSimon Glass .pre_probe = vidconsole_pre_probe, 20983510766SSimon Glass .post_probe = vidconsole_post_probe, 21083510766SSimon Glass .per_device_auto_alloc_size = sizeof(struct vidconsole_priv), 21183510766SSimon Glass }; 21283510766SSimon Glass 21383510766SSimon Glass void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) 21483510766SSimon Glass { 21583510766SSimon Glass struct vidconsole_priv *priv = dev_get_uclass_priv(dev); 216f2661786SSimon Glass struct udevice *vid_dev = dev->parent; 217f2661786SSimon Glass struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); 21883510766SSimon Glass 219f2661786SSimon Glass priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1)); 220f2661786SSimon Glass priv->ycur = min_t(short, row, vid_priv->ysize - 1); 22183510766SSimon Glass } 22283510766SSimon Glass 22383510766SSimon Glass static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, 22483510766SSimon Glass char *const argv[]) 22583510766SSimon Glass { 22683510766SSimon Glass unsigned int col, row; 22783510766SSimon Glass struct udevice *dev; 22883510766SSimon Glass 22983510766SSimon Glass if (argc != 3) 23083510766SSimon Glass return CMD_RET_USAGE; 23183510766SSimon Glass 23283510766SSimon Glass uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); 23383510766SSimon Glass if (!dev) 23483510766SSimon Glass return CMD_RET_FAILURE; 23583510766SSimon Glass col = simple_strtoul(argv[1], NULL, 10); 23683510766SSimon Glass row = simple_strtoul(argv[2], NULL, 10); 23783510766SSimon Glass vidconsole_position_cursor(dev, col, row); 23883510766SSimon Glass 23983510766SSimon Glass return 0; 24083510766SSimon Glass } 24183510766SSimon Glass 24283510766SSimon Glass static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc, 24383510766SSimon Glass char *const argv[]) 24483510766SSimon Glass { 24583510766SSimon Glass struct udevice *dev; 24683510766SSimon Glass const char *s; 24783510766SSimon Glass 24883510766SSimon Glass if (argc != 2) 24983510766SSimon Glass return CMD_RET_USAGE; 25083510766SSimon Glass 25183510766SSimon Glass uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev); 25283510766SSimon Glass if (!dev) 25383510766SSimon Glass return CMD_RET_FAILURE; 25483510766SSimon Glass for (s = argv[1]; *s; s++) 25583510766SSimon Glass vidconsole_put_char(dev, *s); 25683510766SSimon Glass 25783510766SSimon Glass return 0; 25883510766SSimon Glass } 25983510766SSimon Glass 26083510766SSimon Glass U_BOOT_CMD( 26183510766SSimon Glass setcurs, 3, 1, do_video_setcursor, 26283510766SSimon Glass "set cursor position within screen", 26383510766SSimon Glass " <col> <row> in character" 26483510766SSimon Glass ); 26583510766SSimon Glass 26683510766SSimon Glass U_BOOT_CMD( 26783510766SSimon Glass lcdputs, 2, 1, do_video_puts, 26883510766SSimon Glass "print string on video framebuffer", 26983510766SSimon Glass " <string>" 27083510766SSimon Glass ); 271