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