xref: /openbmc/u-boot/drivers/video/vidconsole-uclass.c (revision 430c166bcedd22e0ce93ce298747275f814b172f)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
283510766SSimon Glass /*
383510766SSimon Glass  * Copyright (c) 2015 Google, Inc
483510766SSimon Glass  * (C) Copyright 2001-2015
583510766SSimon Glass  * DENX Software Engineering -- wd@denx.de
683510766SSimon Glass  * Compulab Ltd - http://compulab.co.il/
783510766SSimon Glass  * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
883510766SSimon Glass  */
983510766SSimon Glass 
1083510766SSimon Glass #include <common.h>
11a085aa1fSRob Clark #include <linux/ctype.h>
1283510766SSimon Glass #include <dm.h>
1383510766SSimon Glass #include <video.h>
1483510766SSimon Glass #include <video_console.h>
155fba5329SHeinrich Schuchardt #include <video_font.h>		/* Bitmap font for code page 437 */
1683510766SSimon Glass 
175c30fbb8SHeinrich Schuchardt /*
185c30fbb8SHeinrich Schuchardt  * Structure to describe a console color
195c30fbb8SHeinrich Schuchardt  */
205c30fbb8SHeinrich Schuchardt struct vid_rgb {
215c30fbb8SHeinrich Schuchardt 	u32 r;
225c30fbb8SHeinrich Schuchardt 	u32 g;
235c30fbb8SHeinrich Schuchardt 	u32 b;
245c30fbb8SHeinrich Schuchardt };
255c30fbb8SHeinrich Schuchardt 
2683510766SSimon Glass /* By default we scroll by a single line */
2783510766SSimon Glass #ifndef CONFIG_CONSOLE_SCROLL_LINES
2883510766SSimon Glass #define CONFIG_CONSOLE_SCROLL_LINES 1
2983510766SSimon Glass #endif
3083510766SSimon Glass 
vidconsole_putc_xy(struct udevice * dev,uint x,uint y,char ch)3183510766SSimon Glass int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch)
3283510766SSimon Glass {
3383510766SSimon Glass 	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
3483510766SSimon Glass 
3583510766SSimon Glass 	if (!ops->putc_xy)
3683510766SSimon Glass 		return -ENOSYS;
3783510766SSimon Glass 	return ops->putc_xy(dev, x, y, ch);
3883510766SSimon Glass }
3983510766SSimon Glass 
vidconsole_move_rows(struct udevice * dev,uint rowdst,uint rowsrc,uint count)4083510766SSimon Glass int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
4183510766SSimon Glass 			 uint count)
4283510766SSimon Glass {
4383510766SSimon Glass 	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
4483510766SSimon Glass 
4583510766SSimon Glass 	if (!ops->move_rows)
4683510766SSimon Glass 		return -ENOSYS;
4783510766SSimon Glass 	return ops->move_rows(dev, rowdst, rowsrc, count);
4883510766SSimon Glass }
4983510766SSimon Glass 
vidconsole_set_row(struct udevice * dev,uint row,int clr)5083510766SSimon Glass int vidconsole_set_row(struct udevice *dev, uint row, int clr)
5183510766SSimon Glass {
5283510766SSimon Glass 	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
5383510766SSimon Glass 
5483510766SSimon Glass 	if (!ops->set_row)
5583510766SSimon Glass 		return -ENOSYS;
5683510766SSimon Glass 	return ops->set_row(dev, row, clr);
5783510766SSimon Glass }
5883510766SSimon Glass 
vidconsole_entry_start(struct udevice * dev)5958c733a7SSimon Glass static int vidconsole_entry_start(struct udevice *dev)
6058c733a7SSimon Glass {
6158c733a7SSimon Glass 	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
6258c733a7SSimon Glass 
6358c733a7SSimon Glass 	if (!ops->entry_start)
6458c733a7SSimon Glass 		return -ENOSYS;
6558c733a7SSimon Glass 	return ops->entry_start(dev);
6658c733a7SSimon Glass }
6758c733a7SSimon Glass 
6883510766SSimon Glass /* Move backwards one space */
vidconsole_back(struct udevice * dev)697b9f7e44SSimon Glass static int vidconsole_back(struct udevice *dev)
7083510766SSimon Glass {
7183510766SSimon Glass 	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
727b9f7e44SSimon Glass 	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
737b9f7e44SSimon Glass 	int ret;
747b9f7e44SSimon Glass 
757b9f7e44SSimon Glass 	if (ops->backspace) {
767b9f7e44SSimon Glass 		ret = ops->backspace(dev);
777b9f7e44SSimon Glass 		if (ret != -ENOSYS)
787b9f7e44SSimon Glass 			return ret;
797b9f7e44SSimon Glass 	}
8083510766SSimon Glass 
81f2661786SSimon Glass 	priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
82c5b77d01SSimon Glass 	if (priv->xcur_frac < priv->xstart_frac) {
83f2661786SSimon Glass 		priv->xcur_frac = (priv->cols - 1) *
84f2661786SSimon Glass 			VID_TO_POS(priv->x_charsize);
85f2661786SSimon Glass 		priv->ycur -= priv->y_charsize;
86f2661786SSimon Glass 		if (priv->ycur < 0)
87f2661786SSimon Glass 			priv->ycur = 0;
8883510766SSimon Glass 	}
8955d39911SSimon Glass 	video_sync(dev->parent, false);
907b9f7e44SSimon Glass 
917b9f7e44SSimon Glass 	return 0;
9283510766SSimon Glass }
9383510766SSimon Glass 
9483510766SSimon Glass /* Move to a newline, scrolling the display if necessary */
vidconsole_newline(struct udevice * dev)9583510766SSimon Glass static void vidconsole_newline(struct udevice *dev)
9683510766SSimon Glass {
9783510766SSimon Glass 	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
9883510766SSimon Glass 	struct udevice *vid_dev = dev->parent;
9983510766SSimon Glass 	struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
10083510766SSimon Glass 	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
10183510766SSimon Glass 	int i;
10283510766SSimon Glass 
103c5b77d01SSimon Glass 	priv->xcur_frac = priv->xstart_frac;
104f2661786SSimon Glass 	priv->ycur += priv->y_charsize;
10583510766SSimon Glass 
10683510766SSimon Glass 	/* Check if we need to scroll the terminal */
107f2661786SSimon Glass 	if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) {
10883510766SSimon Glass 		vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
10983510766SSimon Glass 		for (i = 0; i < rows; i++)
11083510766SSimon Glass 			vidconsole_set_row(dev, priv->rows - i - 1,
11183510766SSimon Glass 					   vid_priv->colour_bg);
112f2661786SSimon Glass 		priv->ycur -= rows * priv->y_charsize;
11383510766SSimon Glass 	}
11458c733a7SSimon Glass 	priv->last_ch = 0;
11558c733a7SSimon Glass 
11655d39911SSimon Glass 	video_sync(dev->parent, false);
11783510766SSimon Glass }
11883510766SSimon Glass 
1195c30fbb8SHeinrich Schuchardt static const struct vid_rgb colors[VID_COLOR_COUNT] = {
120703d885cSRob Clark 	{ 0x00, 0x00, 0x00 },  /* black */
1219ffa4d12SHeinrich Schuchardt 	{ 0xc0, 0x00, 0x00 },  /* red */
1229ffa4d12SHeinrich Schuchardt 	{ 0x00, 0xc0, 0x00 },  /* green */
1239ffa4d12SHeinrich Schuchardt 	{ 0xc0, 0x60, 0x00 },  /* brown */
1249ffa4d12SHeinrich Schuchardt 	{ 0x00, 0x00, 0xc0 },  /* blue */
1259ffa4d12SHeinrich Schuchardt 	{ 0xc0, 0x00, 0xc0 },  /* magenta */
1269ffa4d12SHeinrich Schuchardt 	{ 0x00, 0xc0, 0xc0 },  /* cyan */
1279ffa4d12SHeinrich Schuchardt 	{ 0xc0, 0xc0, 0xc0 },  /* light gray */
1289ffa4d12SHeinrich Schuchardt 	{ 0x80, 0x80, 0x80 },  /* gray */
1299ffa4d12SHeinrich Schuchardt 	{ 0xff, 0x00, 0x00 },  /* bright red */
1309ffa4d12SHeinrich Schuchardt 	{ 0x00, 0xff, 0x00 },  /* bright green */
131703d885cSRob Clark 	{ 0xff, 0xff, 0x00 },  /* yellow */
1329ffa4d12SHeinrich Schuchardt 	{ 0x00, 0x00, 0xff },  /* bright blue */
1339ffa4d12SHeinrich Schuchardt 	{ 0xff, 0x00, 0xff },  /* bright magenta */
1349ffa4d12SHeinrich Schuchardt 	{ 0x00, 0xff, 0xff },  /* bright cyan */
135703d885cSRob Clark 	{ 0xff, 0xff, 0xff },  /* white */
136703d885cSRob Clark };
137703d885cSRob Clark 
vid_console_color(struct video_priv * priv,unsigned int idx)1385c30fbb8SHeinrich Schuchardt u32 vid_console_color(struct video_priv *priv, unsigned int idx)
139703d885cSRob Clark {
140703d885cSRob Clark 	switch (priv->bpix) {
141703d885cSRob Clark 	case VIDEO_BPP16:
1425c30fbb8SHeinrich Schuchardt 		return ((colors[idx].r >> 3) << 11) |
143703d885cSRob Clark 		       ((colors[idx].g >> 2) <<  5) |
1443aeb0cbeSHeinrich Schuchardt 		       ((colors[idx].b >> 3) <<  0);
145703d885cSRob Clark 	case VIDEO_BPP32:
1465c30fbb8SHeinrich Schuchardt 		return (colors[idx].r << 16) |
147703d885cSRob Clark 		       (colors[idx].g <<  8) |
1483aeb0cbeSHeinrich Schuchardt 		       (colors[idx].b <<  0);
149703d885cSRob Clark 	default:
1505c30fbb8SHeinrich Schuchardt 		/*
1515c30fbb8SHeinrich Schuchardt 		 * For unknown bit arrangements just support
1525c30fbb8SHeinrich Schuchardt 		 * black and white.
1535c30fbb8SHeinrich Schuchardt 		 */
1545c30fbb8SHeinrich Schuchardt 		if (idx)
1555c30fbb8SHeinrich Schuchardt 			return 0xffffff; /* white */
1565c30fbb8SHeinrich Schuchardt 		else
1575c30fbb8SHeinrich Schuchardt 			return 0x000000; /* black */
158703d885cSRob Clark 	}
159703d885cSRob Clark }
160703d885cSRob Clark 
parsenum(char * s,int * num)161a085aa1fSRob Clark static char *parsenum(char *s, int *num)
162a085aa1fSRob Clark {
163a085aa1fSRob Clark 	char *end;
164a085aa1fSRob Clark 	*num = simple_strtol(s, &end, 10);
165a085aa1fSRob Clark 	return end;
166a085aa1fSRob Clark }
167a085aa1fSRob Clark 
168662f381aSHeinrich Schuchardt /**
169662f381aSHeinrich Schuchardt  * set_cursor_position() - set cursor position
170662f381aSHeinrich Schuchardt  *
171662f381aSHeinrich Schuchardt  * @priv:	private data of the video console
172662f381aSHeinrich Schuchardt  * @row:	new row
173662f381aSHeinrich Schuchardt  * @col:	new column
174662f381aSHeinrich Schuchardt  */
set_cursor_position(struct vidconsole_priv * priv,int row,int col)175662f381aSHeinrich Schuchardt static void set_cursor_position(struct vidconsole_priv *priv, int row, int col)
176662f381aSHeinrich Schuchardt {
177662f381aSHeinrich Schuchardt 	/*
178662f381aSHeinrich Schuchardt 	 * Ensure we stay in the bounds of the screen.
179662f381aSHeinrich Schuchardt 	 */
180662f381aSHeinrich Schuchardt 	if (row >= priv->rows)
181662f381aSHeinrich Schuchardt 		row = priv->rows - 1;
182662f381aSHeinrich Schuchardt 	if (col >= priv->cols)
183662f381aSHeinrich Schuchardt 		col = priv->cols - 1;
184662f381aSHeinrich Schuchardt 
185662f381aSHeinrich Schuchardt 	priv->ycur = row * priv->y_charsize;
186662f381aSHeinrich Schuchardt 	priv->xcur_frac = priv->xstart_frac +
187662f381aSHeinrich Schuchardt 			  VID_TO_POS(col * priv->x_charsize);
188662f381aSHeinrich Schuchardt }
189662f381aSHeinrich Schuchardt 
190662f381aSHeinrich Schuchardt /**
191662f381aSHeinrich Schuchardt  * get_cursor_position() - get cursor position
192662f381aSHeinrich Schuchardt  *
193662f381aSHeinrich Schuchardt  * @priv:	private data of the video console
194662f381aSHeinrich Schuchardt  * @row:	row
195662f381aSHeinrich Schuchardt  * @col:	column
196662f381aSHeinrich Schuchardt  */
get_cursor_position(struct vidconsole_priv * priv,int * row,int * col)197662f381aSHeinrich Schuchardt static void get_cursor_position(struct vidconsole_priv *priv,
198662f381aSHeinrich Schuchardt 				int *row, int *col)
199662f381aSHeinrich Schuchardt {
200662f381aSHeinrich Schuchardt 	*row = priv->ycur / priv->y_charsize;
201662f381aSHeinrich Schuchardt 	*col = VID_TO_PIXEL(priv->xcur_frac - priv->xstart_frac) /
202662f381aSHeinrich Schuchardt 	       priv->x_charsize;
203662f381aSHeinrich Schuchardt }
204662f381aSHeinrich Schuchardt 
205a085aa1fSRob Clark /*
206a085aa1fSRob Clark  * Process a character while accumulating an escape string.  Chars are
207a085aa1fSRob Clark  * accumulated into escape_buf until the end of escape sequence is
208a085aa1fSRob Clark  * found, at which point the sequence is parsed and processed.
209a085aa1fSRob Clark  */
vidconsole_escape_char(struct udevice * dev,char ch)210a085aa1fSRob Clark static void vidconsole_escape_char(struct udevice *dev, char ch)
211a085aa1fSRob Clark {
212a085aa1fSRob Clark 	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
213a085aa1fSRob Clark 
214a085aa1fSRob Clark 	if (!IS_ENABLED(CONFIG_VIDEO_ANSI))
215a085aa1fSRob Clark 		goto error;
216a085aa1fSRob Clark 
217a085aa1fSRob Clark 	/* Sanity checking for bogus ESC sequences: */
218a085aa1fSRob Clark 	if (priv->escape_len >= sizeof(priv->escape_buf))
219a085aa1fSRob Clark 		goto error;
220662f381aSHeinrich Schuchardt 	if (priv->escape_len == 0) {
221662f381aSHeinrich Schuchardt 		switch (ch) {
222662f381aSHeinrich Schuchardt 		case '7':
223662f381aSHeinrich Schuchardt 			/* Save cursor position */
224662f381aSHeinrich Schuchardt 			get_cursor_position(priv, &priv->row_saved,
225662f381aSHeinrich Schuchardt 					    &priv->col_saved);
226662f381aSHeinrich Schuchardt 			priv->escape = 0;
227662f381aSHeinrich Schuchardt 
228662f381aSHeinrich Schuchardt 			return;
229662f381aSHeinrich Schuchardt 		case '8': {
230662f381aSHeinrich Schuchardt 			/* Restore cursor position */
231662f381aSHeinrich Schuchardt 			int row = priv->row_saved;
232662f381aSHeinrich Schuchardt 			int col = priv->col_saved;
233662f381aSHeinrich Schuchardt 
234662f381aSHeinrich Schuchardt 			set_cursor_position(priv, row, col);
235662f381aSHeinrich Schuchardt 			priv->escape = 0;
236662f381aSHeinrich Schuchardt 			return;
237662f381aSHeinrich Schuchardt 		}
238662f381aSHeinrich Schuchardt 		case '[':
239662f381aSHeinrich Schuchardt 			break;
240662f381aSHeinrich Schuchardt 		default:
241a085aa1fSRob Clark 			goto error;
242662f381aSHeinrich Schuchardt 		}
243662f381aSHeinrich Schuchardt 	}
244a085aa1fSRob Clark 
245a085aa1fSRob Clark 	priv->escape_buf[priv->escape_len++] = ch;
246a085aa1fSRob Clark 
247a085aa1fSRob Clark 	/*
248a085aa1fSRob Clark 	 * Escape sequences are terminated by a letter, so keep
249a085aa1fSRob Clark 	 * accumulating until we get one:
250a085aa1fSRob Clark 	 */
251a085aa1fSRob Clark 	if (!isalpha(ch))
252a085aa1fSRob Clark 		return;
253a085aa1fSRob Clark 
254a085aa1fSRob Clark 	/*
255a085aa1fSRob Clark 	 * clear escape mode first, otherwise things will get highly
256a085aa1fSRob Clark 	 * surprising if you hit any debug prints that come back to
257a085aa1fSRob Clark 	 * this console.
258a085aa1fSRob Clark 	 */
259a085aa1fSRob Clark 	priv->escape = 0;
260a085aa1fSRob Clark 
261a085aa1fSRob Clark 	switch (ch) {
262a085aa1fSRob Clark 	case 'H':
263a085aa1fSRob Clark 	case 'f': {
264a085aa1fSRob Clark 		int row, col;
265a085aa1fSRob Clark 		char *s = priv->escape_buf;
266a085aa1fSRob Clark 
267a085aa1fSRob Clark 		/*
268a085aa1fSRob Clark 		 * Set cursor position: [%d;%df or [%d;%dH
269a085aa1fSRob Clark 		 */
270a085aa1fSRob Clark 		s++;    /* [ */
271a085aa1fSRob Clark 		s = parsenum(s, &row);
272a085aa1fSRob Clark 		s++;    /* ; */
273a085aa1fSRob Clark 		s = parsenum(s, &col);
274a085aa1fSRob Clark 
275118f020dSHeinrich Schuchardt 		/*
276118f020dSHeinrich Schuchardt 		 * Video origin is [0, 0], terminal origin is [1, 1].
277118f020dSHeinrich Schuchardt 		 */
278118f020dSHeinrich Schuchardt 		if (row)
279118f020dSHeinrich Schuchardt 			--row;
280118f020dSHeinrich Schuchardt 		if (col)
281118f020dSHeinrich Schuchardt 			--col;
282118f020dSHeinrich Schuchardt 
283662f381aSHeinrich Schuchardt 		set_cursor_position(priv, row, col);
284a085aa1fSRob Clark 
285a085aa1fSRob Clark 		break;
286a085aa1fSRob Clark 	}
287a085aa1fSRob Clark 	case 'J': {
288a085aa1fSRob Clark 		int mode;
289a085aa1fSRob Clark 
290a085aa1fSRob Clark 		/*
291a085aa1fSRob Clark 		 * Clear part/all screen:
292a085aa1fSRob Clark 		 *   [J or [0J - clear screen from cursor down
293a085aa1fSRob Clark 		 *   [1J       - clear screen from cursor up
294a085aa1fSRob Clark 		 *   [2J       - clear entire screen
295a085aa1fSRob Clark 		 *
296a085aa1fSRob Clark 		 * TODO we really only handle entire-screen case, others
297a085aa1fSRob Clark 		 * probably require some additions to video-uclass (and
298a085aa1fSRob Clark 		 * are not really needed yet by efi_console)
299a085aa1fSRob Clark 		 */
300a085aa1fSRob Clark 		parsenum(priv->escape_buf + 1, &mode);
301a085aa1fSRob Clark 
302a085aa1fSRob Clark 		if (mode == 2) {
303a085aa1fSRob Clark 			video_clear(dev->parent);
30455d39911SSimon Glass 			video_sync(dev->parent, false);
305a085aa1fSRob Clark 			priv->ycur = 0;
306a085aa1fSRob Clark 			priv->xcur_frac = priv->xstart_frac;
307a085aa1fSRob Clark 		} else {
308a085aa1fSRob Clark 			debug("unsupported clear mode: %d\n", mode);
309a085aa1fSRob Clark 		}
310a085aa1fSRob Clark 		break;
311a085aa1fSRob Clark 	}
312703d885cSRob Clark 	case 'm': {
313703d885cSRob Clark 		struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
314703d885cSRob Clark 		char *s = priv->escape_buf;
315703d885cSRob Clark 		char *end = &priv->escape_buf[priv->escape_len];
316703d885cSRob Clark 
317703d885cSRob Clark 		/*
318703d885cSRob Clark 		 * Set graphics mode: [%d;...;%dm
319703d885cSRob Clark 		 *
320703d885cSRob Clark 		 * Currently only supports the color attributes:
321703d885cSRob Clark 		 *
322703d885cSRob Clark 		 * Foreground Colors:
323703d885cSRob Clark 		 *
324703d885cSRob Clark 		 *   30	Black
325703d885cSRob Clark 		 *   31	Red
326703d885cSRob Clark 		 *   32	Green
327703d885cSRob Clark 		 *   33	Yellow
328703d885cSRob Clark 		 *   34	Blue
329703d885cSRob Clark 		 *   35	Magenta
330703d885cSRob Clark 		 *   36	Cyan
331703d885cSRob Clark 		 *   37	White
332703d885cSRob Clark 		 *
333703d885cSRob Clark 		 * Background Colors:
334703d885cSRob Clark 		 *
335703d885cSRob Clark 		 *   40	Black
336703d885cSRob Clark 		 *   41	Red
337703d885cSRob Clark 		 *   42	Green
338703d885cSRob Clark 		 *   43	Yellow
339703d885cSRob Clark 		 *   44	Blue
340703d885cSRob Clark 		 *   45	Magenta
341703d885cSRob Clark 		 *   46	Cyan
342703d885cSRob Clark 		 *   47	White
343703d885cSRob Clark 		 */
344703d885cSRob Clark 
345703d885cSRob Clark 		s++;    /* [ */
346703d885cSRob Clark 		while (s < end) {
347703d885cSRob Clark 			int val;
348703d885cSRob Clark 
349703d885cSRob Clark 			s = parsenum(s, &val);
350703d885cSRob Clark 			s++;
351703d885cSRob Clark 
352703d885cSRob Clark 			switch (val) {
3539ffa4d12SHeinrich Schuchardt 			case 0:
3549ffa4d12SHeinrich Schuchardt 				/* all attributes off */
355*b9f210a3SSimon Glass 				video_set_default_colors(dev->parent, false);
3569ffa4d12SHeinrich Schuchardt 				break;
3579ffa4d12SHeinrich Schuchardt 			case 1:
3589ffa4d12SHeinrich Schuchardt 				/* bold */
3599ffa4d12SHeinrich Schuchardt 				vid_priv->fg_col_idx |= 8;
3609ffa4d12SHeinrich Schuchardt 				vid_priv->colour_fg = vid_console_color(
3619ffa4d12SHeinrich Schuchardt 						vid_priv, vid_priv->fg_col_idx);
3629ffa4d12SHeinrich Schuchardt 				break;
363703d885cSRob Clark 			case 30 ... 37:
3645c30fbb8SHeinrich Schuchardt 				/* foreground color */
3659ffa4d12SHeinrich Schuchardt 				vid_priv->fg_col_idx &= ~7;
3669ffa4d12SHeinrich Schuchardt 				vid_priv->fg_col_idx |= val - 30;
3675c30fbb8SHeinrich Schuchardt 				vid_priv->colour_fg = vid_console_color(
3689ffa4d12SHeinrich Schuchardt 						vid_priv, vid_priv->fg_col_idx);
369703d885cSRob Clark 				break;
370703d885cSRob Clark 			case 40 ... 47:
3715c30fbb8SHeinrich Schuchardt 				/* background color */
3725c30fbb8SHeinrich Schuchardt 				vid_priv->colour_bg = vid_console_color(
3735c30fbb8SHeinrich Schuchardt 							vid_priv, val - 40);
374703d885cSRob Clark 				break;
375703d885cSRob Clark 			default:
3765c30fbb8SHeinrich Schuchardt 				/* ignore unsupported SGR parameter */
377703d885cSRob Clark 				break;
378703d885cSRob Clark 			}
379703d885cSRob Clark 		}
380703d885cSRob Clark 
381703d885cSRob Clark 		break;
382703d885cSRob Clark 	}
383a085aa1fSRob Clark 	default:
384a085aa1fSRob Clark 		debug("unrecognized escape sequence: %*s\n",
385a085aa1fSRob Clark 		      priv->escape_len, priv->escape_buf);
386a085aa1fSRob Clark 	}
387a085aa1fSRob Clark 
388a085aa1fSRob Clark 	return;
389a085aa1fSRob Clark 
390a085aa1fSRob Clark error:
391a085aa1fSRob Clark 	/* something went wrong, just revert to normal mode: */
392a085aa1fSRob Clark 	priv->escape = 0;
393a085aa1fSRob Clark }
394a085aa1fSRob Clark 
vidconsole_put_char(struct udevice * dev,char ch)39583510766SSimon Glass int vidconsole_put_char(struct udevice *dev, char ch)
39683510766SSimon Glass {
39783510766SSimon Glass 	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
39883510766SSimon Glass 	int ret;
39983510766SSimon Glass 
400a085aa1fSRob Clark 	if (priv->escape) {
401a085aa1fSRob Clark 		vidconsole_escape_char(dev, ch);
402a085aa1fSRob Clark 		return 0;
403a085aa1fSRob Clark 	}
404a085aa1fSRob Clark 
40583510766SSimon Glass 	switch (ch) {
406a085aa1fSRob Clark 	case '\x1b':
407a085aa1fSRob Clark 		priv->escape_len = 0;
408a085aa1fSRob Clark 		priv->escape = 1;
409a085aa1fSRob Clark 		break;
4105508f10aSSimon Glass 	case '\a':
4115508f10aSSimon Glass 		/* beep */
4125508f10aSSimon Glass 		break;
41383510766SSimon Glass 	case '\r':
414c5b77d01SSimon Glass 		priv->xcur_frac = priv->xstart_frac;
41583510766SSimon Glass 		break;
41683510766SSimon Glass 	case '\n':
41783510766SSimon Glass 		vidconsole_newline(dev);
41858c733a7SSimon Glass 		vidconsole_entry_start(dev);
41983510766SSimon Glass 		break;
42083510766SSimon Glass 	case '\t':	/* Tab (8 chars alignment) */
421f2661786SSimon Glass 		priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
422f2661786SSimon Glass 				+ 1) * priv->tab_width_frac;
42383510766SSimon Glass 
424f2661786SSimon Glass 		if (priv->xcur_frac >= priv->xsize_frac)
42583510766SSimon Glass 			vidconsole_newline(dev);
42683510766SSimon Glass 		break;
42783510766SSimon Glass 	case '\b':
42883510766SSimon Glass 		vidconsole_back(dev);
42958c733a7SSimon Glass 		priv->last_ch = 0;
43083510766SSimon Glass 		break;
43183510766SSimon Glass 	default:
43283510766SSimon Glass 		/*
43383510766SSimon Glass 		 * Failure of this function normally indicates an unsupported
43483510766SSimon Glass 		 * colour depth. Check this and return an error to help with
43583510766SSimon Glass 		 * diagnosis.
43683510766SSimon Glass 		 */
437f2661786SSimon Glass 		ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
438f2661786SSimon Glass 		if (ret == -EAGAIN) {
439f2661786SSimon Glass 			vidconsole_newline(dev);
440f2661786SSimon Glass 			ret = vidconsole_putc_xy(dev, priv->xcur_frac,
441f2661786SSimon Glass 						 priv->ycur, ch);
442f2661786SSimon Glass 		}
443f2661786SSimon Glass 		if (ret < 0)
44483510766SSimon Glass 			return ret;
445f2661786SSimon Glass 		priv->xcur_frac += ret;
44658c733a7SSimon Glass 		priv->last_ch = ch;
447f2661786SSimon Glass 		if (priv->xcur_frac >= priv->xsize_frac)
44883510766SSimon Glass 			vidconsole_newline(dev);
44983510766SSimon Glass 		break;
45083510766SSimon Glass 	}
45183510766SSimon Glass 
45283510766SSimon Glass 	return 0;
45383510766SSimon Glass }
45483510766SSimon Glass 
vidconsole_putc(struct stdio_dev * sdev,const char ch)45583510766SSimon Glass static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
45683510766SSimon Glass {
45783510766SSimon Glass 	struct udevice *dev = sdev->priv;
45883510766SSimon Glass 
45983510766SSimon Glass 	vidconsole_put_char(dev, ch);
46055d39911SSimon Glass 	video_sync(dev->parent, false);
46183510766SSimon Glass }
46283510766SSimon Glass 
vidconsole_puts(struct stdio_dev * sdev,const char * s)46383510766SSimon Glass static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
46483510766SSimon Glass {
46583510766SSimon Glass 	struct udevice *dev = sdev->priv;
46683510766SSimon Glass 
46783510766SSimon Glass 	while (*s)
46883510766SSimon Glass 		vidconsole_put_char(dev, *s++);
46955d39911SSimon Glass 	video_sync(dev->parent, false);
47083510766SSimon Glass }
47183510766SSimon Glass 
47283510766SSimon Glass /* Set up the number of rows and colours (rotated drivers override this) */
vidconsole_pre_probe(struct udevice * dev)47383510766SSimon Glass static int vidconsole_pre_probe(struct udevice *dev)
47483510766SSimon Glass {
47583510766SSimon Glass 	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
47683510766SSimon Glass 	struct udevice *vid = dev->parent;
47783510766SSimon Glass 	struct video_priv *vid_priv = dev_get_uclass_priv(vid);
47883510766SSimon Glass 
479f2661786SSimon Glass 	priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
48083510766SSimon Glass 
48183510766SSimon Glass 	return 0;
48283510766SSimon Glass }
48383510766SSimon Glass 
48483510766SSimon Glass /* Register the device with stdio */
vidconsole_post_probe(struct udevice * dev)48583510766SSimon Glass static int vidconsole_post_probe(struct udevice *dev)
48683510766SSimon Glass {
48783510766SSimon Glass 	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
48883510766SSimon Glass 	struct stdio_dev *sdev = &priv->sdev;
48983510766SSimon Glass 
490f2661786SSimon Glass 	if (!priv->tab_width_frac)
491f2661786SSimon Glass 		priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
492f2661786SSimon Glass 
493f1a1247dSSimon Glass 	if (dev->seq) {
494f1a1247dSSimon Glass 		snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
495f1a1247dSSimon Glass 			 dev->seq);
496f1a1247dSSimon Glass 	} else {
497f1a1247dSSimon Glass 		strcpy(sdev->name, "vidconsole");
498f1a1247dSSimon Glass 	}
499f2661786SSimon Glass 
50083510766SSimon Glass 	sdev->flags = DEV_FLAGS_OUTPUT;
50183510766SSimon Glass 	sdev->putc = vidconsole_putc;
50283510766SSimon Glass 	sdev->puts = vidconsole_puts;
50383510766SSimon Glass 	sdev->priv = dev;
50483510766SSimon Glass 
505720873bfSMasahiro Yamada 	return stdio_register(sdev);
50683510766SSimon Glass }
50783510766SSimon Glass 
50883510766SSimon Glass UCLASS_DRIVER(vidconsole) = {
50983510766SSimon Glass 	.id		= UCLASS_VIDEO_CONSOLE,
51083510766SSimon Glass 	.name		= "vidconsole0",
51183510766SSimon Glass 	.pre_probe	= vidconsole_pre_probe,
51283510766SSimon Glass 	.post_probe	= vidconsole_post_probe,
51383510766SSimon Glass 	.per_device_auto_alloc_size	= sizeof(struct vidconsole_priv),
51483510766SSimon Glass };
51583510766SSimon Glass 
vidconsole_position_cursor(struct udevice * dev,unsigned col,unsigned row)51683510766SSimon Glass void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
51783510766SSimon Glass {
51883510766SSimon Glass 	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
519f2661786SSimon Glass 	struct udevice *vid_dev = dev->parent;
520f2661786SSimon Glass 	struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
52183510766SSimon Glass 
5229949ee87SSimon Glass 	col *= priv->x_charsize;
5239949ee87SSimon Glass 	row *= priv->y_charsize;
524f2661786SSimon Glass 	priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1));
525f2661786SSimon Glass 	priv->ycur = min_t(short, row, vid_priv->ysize - 1);
52683510766SSimon Glass }
52783510766SSimon Glass 
do_video_setcursor(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])52883510766SSimon Glass static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
52983510766SSimon Glass 			      char *const argv[])
53083510766SSimon Glass {
53183510766SSimon Glass 	unsigned int col, row;
53283510766SSimon Glass 	struct udevice *dev;
53383510766SSimon Glass 
53483510766SSimon Glass 	if (argc != 3)
53583510766SSimon Glass 		return CMD_RET_USAGE;
53683510766SSimon Glass 
5373f603cbbSSimon Glass 	if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
53883510766SSimon Glass 		return CMD_RET_FAILURE;
53983510766SSimon Glass 	col = simple_strtoul(argv[1], NULL, 10);
54083510766SSimon Glass 	row = simple_strtoul(argv[2], NULL, 10);
54183510766SSimon Glass 	vidconsole_position_cursor(dev, col, row);
54283510766SSimon Glass 
54383510766SSimon Glass 	return 0;
54483510766SSimon Glass }
54583510766SSimon Glass 
do_video_puts(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])54683510766SSimon Glass static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
54783510766SSimon Glass 			 char *const argv[])
54883510766SSimon Glass {
54983510766SSimon Glass 	struct udevice *dev;
55083510766SSimon Glass 	const char *s;
55183510766SSimon Glass 
55283510766SSimon Glass 	if (argc != 2)
55383510766SSimon Glass 		return CMD_RET_USAGE;
55483510766SSimon Glass 
5553f603cbbSSimon Glass 	if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
55683510766SSimon Glass 		return CMD_RET_FAILURE;
55783510766SSimon Glass 	for (s = argv[1]; *s; s++)
55883510766SSimon Glass 		vidconsole_put_char(dev, *s);
55983510766SSimon Glass 
56055d39911SSimon Glass 	video_sync(dev->parent, false);
561889808daSRob Clark 
56283510766SSimon Glass 	return 0;
56383510766SSimon Glass }
56483510766SSimon Glass 
56583510766SSimon Glass U_BOOT_CMD(
56683510766SSimon Glass 	setcurs, 3,	1,	do_video_setcursor,
56783510766SSimon Glass 	"set cursor position within screen",
56883510766SSimon Glass 	"    <col> <row> in character"
56983510766SSimon Glass );
57083510766SSimon Glass 
57183510766SSimon Glass U_BOOT_CMD(
57283510766SSimon Glass 	lcdputs, 2,	1,	do_video_puts,
57383510766SSimon Glass 	"print string on video framebuffer",
57483510766SSimon Glass 	"    <string>"
57583510766SSimon Glass );
576