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