xref: /openbmc/u-boot/common/lcd_console.c (revision 7471142cdf75c562f2ac8f07c021e0ba80bde6bd)
1 /*
2  * (C) Copyright 2001-2014
3  * DENX Software Engineering -- wd@denx.de
4  * Compulab Ltd - http://compulab.co.il/
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <lcd.h>
11 #include <video_font.h>		/* Get font data, width and height */
12 
13 #define CONSOLE_ROW_SIZE	(VIDEO_FONT_HEIGHT * lcd_line_length)
14 #define CONSOLE_ROW_FIRST	cons.lcd_address
15 #define CONSOLE_SIZE		(CONSOLE_ROW_SIZE * cons.rows)
16 
17 struct console_t {
18 	short curr_col, curr_row;
19 	short cols, rows;
20 	void *lcd_address;
21 };
22 static struct console_t cons;
23 
24 void lcd_init_console(void *address, int rows, int cols)
25 {
26 	memset(&cons, 0, sizeof(cons));
27 	cons.cols = cols;
28 	cons.rows = rows;
29 	cons.lcd_address = address;
30 
31 }
32 
33 void lcd_set_col(short col)
34 {
35 	cons.curr_col = col;
36 }
37 
38 void lcd_set_row(short row)
39 {
40 	cons.curr_row = row;
41 }
42 
43 void lcd_position_cursor(unsigned col, unsigned row)
44 {
45 	cons.curr_col = min_t(short, col, cons.cols - 1);
46 	cons.curr_row = min_t(short, row, cons.rows - 1);
47 }
48 
49 int lcd_get_screen_rows(void)
50 {
51 	return cons.rows;
52 }
53 
54 int lcd_get_screen_columns(void)
55 {
56 	return cons.cols;
57 }
58 
59 static void lcd_putc_xy(ushort x, ushort y, char c)
60 {
61 	uchar *dest;
62 	ushort row;
63 	int fg_color = lcd_getfgcolor();
64 	int bg_color = lcd_getbgcolor();
65 	int i;
66 
67 	dest = (uchar *)(cons.lcd_address +
68 			 y * lcd_line_length + x * NBITS(LCD_BPP) / 8);
69 
70 	for (row = 0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) {
71 #if LCD_BPP == LCD_COLOR16
72 		ushort *d = (ushort *)dest;
73 #elif LCD_BPP == LCD_COLOR32
74 		u32 *d = (u32 *)dest;
75 #else
76 		uchar *d = dest;
77 #endif
78 		uchar bits;
79 		bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
80 
81 		for (i = 0; i < 8; ++i) {
82 			*d++ = (bits & 0x80) ? fg_color : bg_color;
83 			bits <<= 1;
84 		}
85 	}
86 }
87 
88 static void console_scrollup(void)
89 {
90 	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
91 	int bg_color = lcd_getbgcolor();
92 
93 	/* Copy up rows ignoring those that will be overwritten */
94 	memcpy(CONSOLE_ROW_FIRST,
95 	       cons.lcd_address + CONSOLE_ROW_SIZE * rows,
96 	       CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows);
97 
98 	/* Clear the last rows */
99 #if (LCD_BPP != LCD_COLOR32)
100 	memset(lcd_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows,
101 	       bg_color, CONSOLE_ROW_SIZE * rows);
102 #else
103 	u32 *ppix = cons.lcd_address +
104 		    CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows;
105 	u32 i;
106 	for (i = 0;
107 	    i < (CONSOLE_ROW_SIZE * rows) / NBYTES(panel_info.vl_bpix);
108 	    i++) {
109 		*ppix++ = bg_color;
110 	}
111 #endif
112 	lcd_sync();
113 	cons.curr_row -= rows;
114 }
115 
116 static inline void console_back(void)
117 {
118 	if (--cons.curr_col < 0) {
119 		cons.curr_col = cons.cols - 1;
120 		if (--cons.curr_row < 0)
121 			cons.curr_row = 0;
122 	}
123 
124 	lcd_putc_xy(cons.curr_col * VIDEO_FONT_WIDTH,
125 		    cons.curr_row * VIDEO_FONT_HEIGHT, ' ');
126 }
127 
128 static inline void console_newline(void)
129 {
130 	cons.curr_col = 0;
131 
132 	/* Check if we need to scroll the terminal */
133 	if (++cons.curr_row >= cons.rows)
134 		console_scrollup();
135 	else
136 		lcd_sync();
137 }
138 
139 void lcd_putc(const char c)
140 {
141 	if (!lcd_is_enabled) {
142 		serial_putc(c);
143 
144 		return;
145 	}
146 
147 	switch (c) {
148 	case '\r':
149 		cons.curr_col = 0;
150 		return;
151 	case '\n':
152 		console_newline();
153 
154 		return;
155 	case '\t':	/* Tab (8 chars alignment) */
156 		cons.curr_col +=  8;
157 		cons.curr_col &= ~7;
158 
159 		if (cons.curr_col >= cons.cols)
160 			console_newline();
161 
162 		return;
163 	case '\b':
164 		console_back();
165 
166 		return;
167 	default:
168 		lcd_putc_xy(cons.curr_col * VIDEO_FONT_WIDTH,
169 			    cons.curr_row * VIDEO_FONT_HEIGHT, c);
170 		if (++cons.curr_col >= cons.cols)
171 			console_newline();
172 	}
173 }
174 
175 void lcd_puts(const char *s)
176 {
177 	if (!lcd_is_enabled) {
178 		serial_puts(s);
179 
180 		return;
181 	}
182 
183 	while (*s)
184 		lcd_putc(*s++);
185 
186 	lcd_sync();
187 }
188 
189 void lcd_printf(const char *fmt, ...)
190 {
191 	va_list args;
192 	char buf[CONFIG_SYS_PBSIZE];
193 
194 	va_start(args, fmt);
195 	vsprintf(buf, fmt, args);
196 	va_end(args);
197 
198 	lcd_puts(buf);
199 }
200 
201 static int do_lcd_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
202 			    char *const argv[])
203 {
204 	unsigned int col, row;
205 
206 	if (argc != 3)
207 		return CMD_RET_USAGE;
208 
209 	col = simple_strtoul(argv[1], NULL, 10);
210 	row = simple_strtoul(argv[2], NULL, 10);
211 	lcd_position_cursor(col, row);
212 
213 	return 0;
214 }
215 
216 static int do_lcd_puts(cmd_tbl_t *cmdtp, int flag, int argc,
217 		       char *const argv[])
218 {
219 	if (argc != 2)
220 		return CMD_RET_USAGE;
221 
222 	lcd_puts(argv[1]);
223 
224 	return 0;
225 }
226 
227 U_BOOT_CMD(
228 	setcurs, 3,	1,	do_lcd_setcursor,
229 	"set cursor position within screen",
230 	"    <col> <row> in character"
231 );
232 
233 U_BOOT_CMD(
234 	lcdputs, 2,	1,	do_lcd_puts,
235 	"print string on lcd-framebuffer",
236 	"    <string>"
237 );
238 
239