Merge branch '2019-10-28-azure-ci-support'
[oweals/u-boot.git] / common / lcd_console.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2001-2015
4  * DENX Software Engineering -- wd@denx.de
5  * Compulab Ltd - http://compulab.co.il/
6  * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
7  */
8
9 #include <common.h>
10 #include <lcd.h>
11 #include <video_font.h>         /* Get font data, width and height */
12 #if defined(CONFIG_LCD_LOGO)
13 #include <bmp_logo.h>
14 #endif
15
16 static struct console_t cons;
17
18 void lcd_set_col(short col)
19 {
20         cons.curr_col = col;
21 }
22
23 void lcd_set_row(short row)
24 {
25         cons.curr_row = row;
26 }
27
28 void lcd_position_cursor(unsigned col, unsigned row)
29 {
30         cons.curr_col = min_t(short, col, cons.cols - 1);
31         cons.curr_row = min_t(short, row, cons.rows - 1);
32 }
33
34 int lcd_get_screen_rows(void)
35 {
36         return cons.rows;
37 }
38
39 int lcd_get_screen_columns(void)
40 {
41         return cons.cols;
42 }
43
44 static void lcd_putc_xy0(struct console_t *pcons, ushort x, ushort y, char c)
45 {
46         int fg_color = lcd_getfgcolor();
47         int bg_color = lcd_getbgcolor();
48         int i, row;
49         fbptr_t *dst = (fbptr_t *)pcons->fbbase +
50                                   y * pcons->lcdsizex +
51                                   x;
52
53         for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
54                 uchar bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
55                 for (i = 0; i < VIDEO_FONT_WIDTH; ++i) {
56                         *dst++ = (bits & 0x80) ? fg_color : bg_color;
57                         bits <<= 1;
58                 }
59                 dst += (pcons->lcdsizex - VIDEO_FONT_WIDTH);
60         }
61 }
62
63 static inline void console_setrow0(struct console_t *pcons, u32 row, int clr)
64 {
65         int i;
66         fbptr_t *dst = (fbptr_t *)pcons->fbbase +
67                                   row * VIDEO_FONT_HEIGHT *
68                                   pcons->lcdsizex;
69
70         for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
71                 *dst++ = clr;
72 }
73
74 static inline void console_moverow0(struct console_t *pcons,
75                                     u32 rowdst, u32 rowsrc)
76 {
77         int i;
78         fbptr_t *dst = (fbptr_t *)pcons->fbbase +
79                                   rowdst * VIDEO_FONT_HEIGHT *
80                                   pcons->lcdsizex;
81
82         fbptr_t *src = (fbptr_t *)pcons->fbbase +
83                                   rowsrc * VIDEO_FONT_HEIGHT *
84                                   pcons->lcdsizex;
85
86         for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
87                 *dst++ = *src++;
88 }
89
90 static inline void console_back(void)
91 {
92         if (--cons.curr_col < 0) {
93                 cons.curr_col = cons.cols - 1;
94                 if (--cons.curr_row < 0)
95                         cons.curr_row = 0;
96         }
97
98         cons.fp_putc_xy(&cons,
99                         cons.curr_col * VIDEO_FONT_WIDTH,
100                         cons.curr_row * VIDEO_FONT_HEIGHT, ' ');
101 }
102
103 static inline void console_newline(void)
104 {
105         const int rows = CONFIG_CONSOLE_SCROLL_LINES;
106         int bg_color = lcd_getbgcolor();
107         int i;
108
109         cons.curr_col = 0;
110
111         /* Check if we need to scroll the terminal */
112         if (++cons.curr_row >= cons.rows) {
113                 for (i = 0; i < cons.rows-rows; i++)
114                         cons.fp_console_moverow(&cons, i, i+rows);
115                 for (i = 0; i < rows; i++)
116                         cons.fp_console_setrow(&cons, cons.rows-i-1, bg_color);
117                 cons.curr_row -= rows;
118         }
119         lcd_sync();
120 }
121
122 void console_calc_rowcol(struct console_t *pcons, u32 sizex, u32 sizey)
123 {
124         pcons->cols = sizex / VIDEO_FONT_WIDTH;
125 #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
126         pcons->rows = (pcons->lcdsizey - BMP_LOGO_HEIGHT);
127         pcons->rows /= VIDEO_FONT_HEIGHT;
128 #else
129         pcons->rows = sizey / VIDEO_FONT_HEIGHT;
130 #endif
131 }
132
133 void __weak lcd_init_console_rot(struct console_t *pcons)
134 {
135         return;
136 }
137
138 void lcd_init_console(void *address, int vl_cols, int vl_rows, int vl_rot)
139 {
140         memset(&cons, 0, sizeof(cons));
141         cons.fbbase = address;
142
143         cons.lcdsizex = vl_cols;
144         cons.lcdsizey = vl_rows;
145         cons.lcdrot = vl_rot;
146
147         cons.fp_putc_xy = &lcd_putc_xy0;
148         cons.fp_console_moverow = &console_moverow0;
149         cons.fp_console_setrow = &console_setrow0;
150         console_calc_rowcol(&cons, cons.lcdsizex, cons.lcdsizey);
151
152         lcd_init_console_rot(&cons);
153
154         debug("lcd_console: have %d/%d col/rws on scr %dx%d (%d deg rotated)\n",
155               cons.cols, cons.rows, cons.lcdsizex, cons.lcdsizey, vl_rot);
156 }
157
158 void lcd_putc(const char c)
159 {
160         if (!lcd_is_enabled) {
161                 serial_putc(c);
162
163                 return;
164         }
165
166         switch (c) {
167         case '\r':
168                 cons.curr_col = 0;
169                 return;
170         case '\n':
171                 console_newline();
172
173                 return;
174         case '\t':      /* Tab (8 chars alignment) */
175                 cons.curr_col +=  8;
176                 cons.curr_col &= ~7;
177
178                 if (cons.curr_col >= cons.cols)
179                         console_newline();
180
181                 return;
182         case '\b':
183                 console_back();
184
185                 return;
186         default:
187                 cons.fp_putc_xy(&cons,
188                                 cons.curr_col * VIDEO_FONT_WIDTH,
189                                 cons.curr_row * VIDEO_FONT_HEIGHT, c);
190                 if (++cons.curr_col >= cons.cols)
191                         console_newline();
192         }
193 }
194
195 void lcd_puts(const char *s)
196 {
197         if (!lcd_is_enabled) {
198                 serial_puts(s);
199
200                 return;
201         }
202
203         while (*s)
204                 lcd_putc(*s++);
205
206         lcd_sync();
207 }
208
209 void lcd_printf(const char *fmt, ...)
210 {
211         va_list args;
212         char buf[CONFIG_SYS_PBSIZE];
213
214         va_start(args, fmt);
215         vsprintf(buf, fmt, args);
216         va_end(args);
217
218         lcd_puts(buf);
219 }
220
221 static int do_lcd_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
222                             char *const argv[])
223 {
224         unsigned int col, row;
225
226         if (argc != 3)
227                 return CMD_RET_USAGE;
228
229         col = simple_strtoul(argv[1], NULL, 10);
230         row = simple_strtoul(argv[2], NULL, 10);
231         lcd_position_cursor(col, row);
232
233         return 0;
234 }
235
236 static int do_lcd_puts(cmd_tbl_t *cmdtp, int flag, int argc,
237                        char *const argv[])
238 {
239         if (argc != 2)
240                 return CMD_RET_USAGE;
241
242         lcd_puts(argv[1]);
243
244         return 0;
245 }
246
247 U_BOOT_CMD(
248         setcurs, 3,     1,      do_lcd_setcursor,
249         "set cursor position within screen",
250         "    <col> <row> in character"
251 );
252
253 U_BOOT_CMD(
254         lcdputs, 2,     1,      do_lcd_puts,
255         "print string on lcd-framebuffer",
256         "    <string>"
257 );
258