lcd: refactor lcd console stuff into its own file
[oweals/u-boot.git] / common / lcd_console.c
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 }