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