xref: /openbmc/u-boot/common/lcd_console.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2904672eeSNikita Kiryanov /*
3604c7d4aSHannes Petermaier  * (C) Copyright 2001-2015
4904672eeSNikita Kiryanov  * DENX Software Engineering -- wd@denx.de
5904672eeSNikita Kiryanov  * Compulab Ltd - http://compulab.co.il/
6604c7d4aSHannes Petermaier  * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
7904672eeSNikita Kiryanov  */
8904672eeSNikita Kiryanov 
9904672eeSNikita Kiryanov #include <common.h>
10904672eeSNikita Kiryanov #include <lcd.h>
11904672eeSNikita Kiryanov #include <video_font.h>		/* Get font data, width and height */
12604c7d4aSHannes Petermaier #if defined(CONFIG_LCD_LOGO)
13604c7d4aSHannes Petermaier #include <bmp_logo.h>
14604c7d4aSHannes Petermaier #endif
15904672eeSNikita Kiryanov 
167471142cSHannes Petermaier static struct console_t cons;
17904672eeSNikita Kiryanov 
lcd_set_col(short col)18904672eeSNikita Kiryanov void lcd_set_col(short col)
19904672eeSNikita Kiryanov {
207471142cSHannes Petermaier 	cons.curr_col = col;
21904672eeSNikita Kiryanov }
22904672eeSNikita Kiryanov 
lcd_set_row(short row)23904672eeSNikita Kiryanov void lcd_set_row(short row)
24904672eeSNikita Kiryanov {
257471142cSHannes Petermaier 	cons.curr_row = row;
26904672eeSNikita Kiryanov }
27904672eeSNikita Kiryanov 
lcd_position_cursor(unsigned col,unsigned row)28904672eeSNikita Kiryanov void lcd_position_cursor(unsigned col, unsigned row)
29904672eeSNikita Kiryanov {
307471142cSHannes Petermaier 	cons.curr_col = min_t(short, col, cons.cols - 1);
317471142cSHannes Petermaier 	cons.curr_row = min_t(short, row, cons.rows - 1);
32904672eeSNikita Kiryanov }
33904672eeSNikita Kiryanov 
lcd_get_screen_rows(void)34904672eeSNikita Kiryanov int lcd_get_screen_rows(void)
35904672eeSNikita Kiryanov {
367471142cSHannes Petermaier 	return cons.rows;
37904672eeSNikita Kiryanov }
38904672eeSNikita Kiryanov 
lcd_get_screen_columns(void)39904672eeSNikita Kiryanov int lcd_get_screen_columns(void)
40904672eeSNikita Kiryanov {
417471142cSHannes Petermaier 	return cons.cols;
42904672eeSNikita Kiryanov }
43904672eeSNikita Kiryanov 
lcd_putc_xy0(struct console_t * pcons,ushort x,ushort y,char c)44604c7d4aSHannes Petermaier static void lcd_putc_xy0(struct console_t *pcons, ushort x, ushort y, char c)
45904672eeSNikita Kiryanov {
46a202c5bdSHannes Petermaier 	int fg_color = lcd_getfgcolor();
47a202c5bdSHannes Petermaier 	int bg_color = lcd_getbgcolor();
48604c7d4aSHannes Petermaier 	int i, row;
49604c7d4aSHannes Petermaier 	fbptr_t *dst = (fbptr_t *)pcons->fbbase +
50604c7d4aSHannes Petermaier 				  y * pcons->lcdsizex +
51604c7d4aSHannes Petermaier 				  x;
52904672eeSNikita Kiryanov 
53604c7d4aSHannes Petermaier 	for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
54604c7d4aSHannes Petermaier 		uchar bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
55604c7d4aSHannes Petermaier 		for (i = 0; i < VIDEO_FONT_WIDTH; ++i) {
56604c7d4aSHannes Petermaier 			*dst++ = (bits & 0x80) ? fg_color : bg_color;
57904672eeSNikita Kiryanov 			bits <<= 1;
58904672eeSNikita Kiryanov 		}
59604c7d4aSHannes Petermaier 		dst += (pcons->lcdsizex - VIDEO_FONT_WIDTH);
60904672eeSNikita Kiryanov 	}
61904672eeSNikita Kiryanov }
62904672eeSNikita Kiryanov 
console_setrow0(struct console_t * pcons,u32 row,int clr)63604c7d4aSHannes Petermaier static inline void console_setrow0(struct console_t *pcons, u32 row, int clr)
64904672eeSNikita Kiryanov {
65604c7d4aSHannes Petermaier 	int i;
66604c7d4aSHannes Petermaier 	fbptr_t *dst = (fbptr_t *)pcons->fbbase +
67604c7d4aSHannes Petermaier 				  row * VIDEO_FONT_HEIGHT *
68604c7d4aSHannes Petermaier 				  pcons->lcdsizex;
69904672eeSNikita Kiryanov 
70604c7d4aSHannes Petermaier 	for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
71604c7d4aSHannes Petermaier 		*dst++ = clr;
72904672eeSNikita Kiryanov }
73604c7d4aSHannes Petermaier 
console_moverow0(struct console_t * pcons,u32 rowdst,u32 rowsrc)74604c7d4aSHannes Petermaier static inline void console_moverow0(struct console_t *pcons,
75604c7d4aSHannes Petermaier 				    u32 rowdst, u32 rowsrc)
76604c7d4aSHannes Petermaier {
77604c7d4aSHannes Petermaier 	int i;
78604c7d4aSHannes Petermaier 	fbptr_t *dst = (fbptr_t *)pcons->fbbase +
79604c7d4aSHannes Petermaier 				  rowdst * VIDEO_FONT_HEIGHT *
80604c7d4aSHannes Petermaier 				  pcons->lcdsizex;
81604c7d4aSHannes Petermaier 
82604c7d4aSHannes Petermaier 	fbptr_t *src = (fbptr_t *)pcons->fbbase +
83604c7d4aSHannes Petermaier 				  rowsrc * VIDEO_FONT_HEIGHT *
84604c7d4aSHannes Petermaier 				  pcons->lcdsizex;
85604c7d4aSHannes Petermaier 
86604c7d4aSHannes Petermaier 	for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
87604c7d4aSHannes Petermaier 		*dst++ = *src++;
88904672eeSNikita Kiryanov }
89904672eeSNikita Kiryanov 
console_back(void)90904672eeSNikita Kiryanov static inline void console_back(void)
91904672eeSNikita Kiryanov {
927471142cSHannes Petermaier 	if (--cons.curr_col < 0) {
937471142cSHannes Petermaier 		cons.curr_col = cons.cols - 1;
947471142cSHannes Petermaier 		if (--cons.curr_row < 0)
957471142cSHannes Petermaier 			cons.curr_row = 0;
96904672eeSNikita Kiryanov 	}
97904672eeSNikita Kiryanov 
98604c7d4aSHannes Petermaier 	cons.fp_putc_xy(&cons,
99604c7d4aSHannes Petermaier 			cons.curr_col * VIDEO_FONT_WIDTH,
1007471142cSHannes Petermaier 			cons.curr_row * VIDEO_FONT_HEIGHT, ' ');
101904672eeSNikita Kiryanov }
102904672eeSNikita Kiryanov 
console_newline(void)103904672eeSNikita Kiryanov static inline void console_newline(void)
104904672eeSNikita Kiryanov {
105604c7d4aSHannes Petermaier 	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
106604c7d4aSHannes Petermaier 	int bg_color = lcd_getbgcolor();
107604c7d4aSHannes Petermaier 	int i;
108604c7d4aSHannes Petermaier 
1097471142cSHannes Petermaier 	cons.curr_col = 0;
110904672eeSNikita Kiryanov 
111904672eeSNikita Kiryanov 	/* Check if we need to scroll the terminal */
112604c7d4aSHannes Petermaier 	if (++cons.curr_row >= cons.rows) {
113604c7d4aSHannes Petermaier 		for (i = 0; i < cons.rows-rows; i++)
114604c7d4aSHannes Petermaier 			cons.fp_console_moverow(&cons, i, i+rows);
115604c7d4aSHannes Petermaier 		for (i = 0; i < rows; i++)
116604c7d4aSHannes Petermaier 			cons.fp_console_setrow(&cons, cons.rows-i-1, bg_color);
117604c7d4aSHannes Petermaier 		cons.curr_row -= rows;
118604c7d4aSHannes Petermaier 	}
119904672eeSNikita Kiryanov 	lcd_sync();
120904672eeSNikita Kiryanov }
121904672eeSNikita Kiryanov 
console_calc_rowcol(struct console_t * pcons,u32 sizex,u32 sizey)122604c7d4aSHannes Petermaier void console_calc_rowcol(struct console_t *pcons, u32 sizex, u32 sizey)
123604c7d4aSHannes Petermaier {
124604c7d4aSHannes Petermaier 	pcons->cols = sizex / VIDEO_FONT_WIDTH;
125604c7d4aSHannes Petermaier #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
126604c7d4aSHannes Petermaier 	pcons->rows = (pcons->lcdsizey - BMP_LOGO_HEIGHT);
127604c7d4aSHannes Petermaier 	pcons->rows /= VIDEO_FONT_HEIGHT;
128604c7d4aSHannes Petermaier #else
129604c7d4aSHannes Petermaier 	pcons->rows = sizey / VIDEO_FONT_HEIGHT;
130604c7d4aSHannes Petermaier #endif
131604c7d4aSHannes Petermaier }
132604c7d4aSHannes Petermaier 
lcd_init_console_rot(struct console_t * pcons)133604c7d4aSHannes Petermaier void __weak lcd_init_console_rot(struct console_t *pcons)
134604c7d4aSHannes Petermaier {
135604c7d4aSHannes Petermaier 	return;
136604c7d4aSHannes Petermaier }
137604c7d4aSHannes Petermaier 
lcd_init_console(void * address,int vl_cols,int vl_rows,int vl_rot)138604c7d4aSHannes Petermaier void lcd_init_console(void *address, int vl_cols, int vl_rows, int vl_rot)
139604c7d4aSHannes Petermaier {
140604c7d4aSHannes Petermaier 	memset(&cons, 0, sizeof(cons));
141604c7d4aSHannes Petermaier 	cons.fbbase = address;
142604c7d4aSHannes Petermaier 
143604c7d4aSHannes Petermaier 	cons.lcdsizex = vl_cols;
144604c7d4aSHannes Petermaier 	cons.lcdsizey = vl_rows;
145604c7d4aSHannes Petermaier 	cons.lcdrot = vl_rot;
146604c7d4aSHannes Petermaier 
147604c7d4aSHannes Petermaier 	cons.fp_putc_xy = &lcd_putc_xy0;
148604c7d4aSHannes Petermaier 	cons.fp_console_moverow = &console_moverow0;
149604c7d4aSHannes Petermaier 	cons.fp_console_setrow = &console_setrow0;
150604c7d4aSHannes Petermaier 	console_calc_rowcol(&cons, cons.lcdsizex, cons.lcdsizey);
151604c7d4aSHannes Petermaier 
152604c7d4aSHannes Petermaier 	lcd_init_console_rot(&cons);
153604c7d4aSHannes Petermaier 
154604c7d4aSHannes Petermaier 	debug("lcd_console: have %d/%d col/rws on scr %dx%d (%d deg rotated)\n",
155604c7d4aSHannes Petermaier 	      cons.cols, cons.rows, cons.lcdsizex, cons.lcdsizey, vl_rot);
156604c7d4aSHannes Petermaier }
157604c7d4aSHannes Petermaier 
lcd_putc(const char c)158904672eeSNikita Kiryanov void lcd_putc(const char c)
159904672eeSNikita Kiryanov {
160904672eeSNikita Kiryanov 	if (!lcd_is_enabled) {
161904672eeSNikita Kiryanov 		serial_putc(c);
162904672eeSNikita Kiryanov 
163904672eeSNikita Kiryanov 		return;
164904672eeSNikita Kiryanov 	}
165904672eeSNikita Kiryanov 
166904672eeSNikita Kiryanov 	switch (c) {
167904672eeSNikita Kiryanov 	case '\r':
1687471142cSHannes Petermaier 		cons.curr_col = 0;
169904672eeSNikita Kiryanov 		return;
170904672eeSNikita Kiryanov 	case '\n':
171904672eeSNikita Kiryanov 		console_newline();
172904672eeSNikita Kiryanov 
173904672eeSNikita Kiryanov 		return;
174904672eeSNikita Kiryanov 	case '\t':	/* Tab (8 chars alignment) */
1757471142cSHannes Petermaier 		cons.curr_col +=  8;
1767471142cSHannes Petermaier 		cons.curr_col &= ~7;
177904672eeSNikita Kiryanov 
1787471142cSHannes Petermaier 		if (cons.curr_col >= cons.cols)
179904672eeSNikita Kiryanov 			console_newline();
180904672eeSNikita Kiryanov 
181904672eeSNikita Kiryanov 		return;
182904672eeSNikita Kiryanov 	case '\b':
183904672eeSNikita Kiryanov 		console_back();
184904672eeSNikita Kiryanov 
185904672eeSNikita Kiryanov 		return;
186904672eeSNikita Kiryanov 	default:
187604c7d4aSHannes Petermaier 		cons.fp_putc_xy(&cons,
188604c7d4aSHannes Petermaier 				cons.curr_col * VIDEO_FONT_WIDTH,
1897471142cSHannes Petermaier 				cons.curr_row * VIDEO_FONT_HEIGHT, c);
1907471142cSHannes Petermaier 		if (++cons.curr_col >= cons.cols)
191904672eeSNikita Kiryanov 			console_newline();
192904672eeSNikita Kiryanov 	}
193904672eeSNikita Kiryanov }
194904672eeSNikita Kiryanov 
lcd_puts(const char * s)195904672eeSNikita Kiryanov void lcd_puts(const char *s)
196904672eeSNikita Kiryanov {
197904672eeSNikita Kiryanov 	if (!lcd_is_enabled) {
198904672eeSNikita Kiryanov 		serial_puts(s);
199904672eeSNikita Kiryanov 
200904672eeSNikita Kiryanov 		return;
201904672eeSNikita Kiryanov 	}
202904672eeSNikita Kiryanov 
203904672eeSNikita Kiryanov 	while (*s)
204904672eeSNikita Kiryanov 		lcd_putc(*s++);
205904672eeSNikita Kiryanov 
206904672eeSNikita Kiryanov 	lcd_sync();
207904672eeSNikita Kiryanov }
208904672eeSNikita Kiryanov 
lcd_printf(const char * fmt,...)209904672eeSNikita Kiryanov void lcd_printf(const char *fmt, ...)
210904672eeSNikita Kiryanov {
211904672eeSNikita Kiryanov 	va_list args;
212904672eeSNikita Kiryanov 	char buf[CONFIG_SYS_PBSIZE];
213904672eeSNikita Kiryanov 
214904672eeSNikita Kiryanov 	va_start(args, fmt);
215904672eeSNikita Kiryanov 	vsprintf(buf, fmt, args);
216904672eeSNikita Kiryanov 	va_end(args);
217904672eeSNikita Kiryanov 
218904672eeSNikita Kiryanov 	lcd_puts(buf);
219904672eeSNikita Kiryanov }
220d38d0c6aSHannes Petermaier 
do_lcd_setcursor(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])221d38d0c6aSHannes Petermaier static int do_lcd_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
222d38d0c6aSHannes Petermaier 			    char *const argv[])
223d38d0c6aSHannes Petermaier {
224d38d0c6aSHannes Petermaier 	unsigned int col, row;
225d38d0c6aSHannes Petermaier 
226d38d0c6aSHannes Petermaier 	if (argc != 3)
227d38d0c6aSHannes Petermaier 		return CMD_RET_USAGE;
228d38d0c6aSHannes Petermaier 
229d38d0c6aSHannes Petermaier 	col = simple_strtoul(argv[1], NULL, 10);
230d38d0c6aSHannes Petermaier 	row = simple_strtoul(argv[2], NULL, 10);
231d38d0c6aSHannes Petermaier 	lcd_position_cursor(col, row);
232d38d0c6aSHannes Petermaier 
233d38d0c6aSHannes Petermaier 	return 0;
234d38d0c6aSHannes Petermaier }
235d38d0c6aSHannes Petermaier 
do_lcd_puts(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2361b7caf11SHannes Petermaier static int do_lcd_puts(cmd_tbl_t *cmdtp, int flag, int argc,
2371b7caf11SHannes Petermaier 		       char *const argv[])
2381b7caf11SHannes Petermaier {
2391b7caf11SHannes Petermaier 	if (argc != 2)
2401b7caf11SHannes Petermaier 		return CMD_RET_USAGE;
2411b7caf11SHannes Petermaier 
2421b7caf11SHannes Petermaier 	lcd_puts(argv[1]);
2431b7caf11SHannes Petermaier 
2441b7caf11SHannes Petermaier 	return 0;
2451b7caf11SHannes Petermaier }
2461b7caf11SHannes Petermaier 
247d38d0c6aSHannes Petermaier U_BOOT_CMD(
248d38d0c6aSHannes Petermaier 	setcurs, 3,	1,	do_lcd_setcursor,
249d38d0c6aSHannes Petermaier 	"set cursor position within screen",
250d38d0c6aSHannes Petermaier 	"    <col> <row> in character"
251d38d0c6aSHannes Petermaier );
2521b7caf11SHannes Petermaier 
2531b7caf11SHannes Petermaier U_BOOT_CMD(
2541b7caf11SHannes Petermaier 	lcdputs, 2,	1,	do_lcd_puts,
2551b7caf11SHannes Petermaier 	"print string on lcd-framebuffer",
2561b7caf11SHannes Petermaier 	"    <string>"
2571b7caf11SHannes Petermaier );
2581b7caf11SHannes Petermaier 
259