1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2904672eeSNikita Kiryanov /*
3604c7d4aSHannes Petermaier * (C) Copyright 2001-2015
4904672eeSNikita Kiryanov * DENX Software Engineering -- wd@denx.de
5904672eeSNikita Kiryanov * Compulab Ltd - http://compulab.co.il/
6604c7d4aSHannes Petermaier * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
7904672eeSNikita Kiryanov */
8904672eeSNikita Kiryanov
9904672eeSNikita Kiryanov #include <common.h>
10904672eeSNikita Kiryanov #include <lcd.h>
11904672eeSNikita Kiryanov #include <video_font.h> /* Get font data, width and height */
12604c7d4aSHannes Petermaier #if defined(CONFIG_LCD_LOGO)
13604c7d4aSHannes Petermaier #include <bmp_logo.h>
14604c7d4aSHannes Petermaier #endif
15904672eeSNikita Kiryanov
167471142cSHannes Petermaier static struct console_t cons;
17904672eeSNikita Kiryanov
lcd_set_col(short col)18904672eeSNikita Kiryanov void lcd_set_col(short col)
19904672eeSNikita Kiryanov {
207471142cSHannes Petermaier cons.curr_col = col;
21904672eeSNikita Kiryanov }
22904672eeSNikita Kiryanov
lcd_set_row(short row)23904672eeSNikita Kiryanov void lcd_set_row(short row)
24904672eeSNikita Kiryanov {
257471142cSHannes Petermaier cons.curr_row = row;
26904672eeSNikita Kiryanov }
27904672eeSNikita Kiryanov
lcd_position_cursor(unsigned col,unsigned row)28904672eeSNikita Kiryanov void lcd_position_cursor(unsigned col, unsigned row)
29904672eeSNikita Kiryanov {
307471142cSHannes Petermaier cons.curr_col = min_t(short, col, cons.cols - 1);
317471142cSHannes Petermaier cons.curr_row = min_t(short, row, cons.rows - 1);
32904672eeSNikita Kiryanov }
33904672eeSNikita Kiryanov
lcd_get_screen_rows(void)34904672eeSNikita Kiryanov int lcd_get_screen_rows(void)
35904672eeSNikita Kiryanov {
367471142cSHannes Petermaier return cons.rows;
37904672eeSNikita Kiryanov }
38904672eeSNikita Kiryanov
lcd_get_screen_columns(void)39904672eeSNikita Kiryanov int lcd_get_screen_columns(void)
40904672eeSNikita Kiryanov {
417471142cSHannes Petermaier return cons.cols;
42904672eeSNikita Kiryanov }
43904672eeSNikita Kiryanov
lcd_putc_xy0(struct console_t * pcons,ushort x,ushort y,char c)44604c7d4aSHannes Petermaier static void lcd_putc_xy0(struct console_t *pcons, ushort x, ushort y, char c)
45904672eeSNikita Kiryanov {
46a202c5bdSHannes Petermaier int fg_color = lcd_getfgcolor();
47a202c5bdSHannes Petermaier int bg_color = lcd_getbgcolor();
48604c7d4aSHannes Petermaier int i, row;
49604c7d4aSHannes Petermaier fbptr_t *dst = (fbptr_t *)pcons->fbbase +
50604c7d4aSHannes Petermaier y * pcons->lcdsizex +
51604c7d4aSHannes Petermaier x;
52904672eeSNikita Kiryanov
53604c7d4aSHannes Petermaier for (row = 0; row < VIDEO_FONT_HEIGHT; row++) {
54604c7d4aSHannes Petermaier uchar bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
55604c7d4aSHannes Petermaier for (i = 0; i < VIDEO_FONT_WIDTH; ++i) {
56604c7d4aSHannes Petermaier *dst++ = (bits & 0x80) ? fg_color : bg_color;
57904672eeSNikita Kiryanov bits <<= 1;
58904672eeSNikita Kiryanov }
59604c7d4aSHannes Petermaier dst += (pcons->lcdsizex - VIDEO_FONT_WIDTH);
60904672eeSNikita Kiryanov }
61904672eeSNikita Kiryanov }
62904672eeSNikita Kiryanov
console_setrow0(struct console_t * pcons,u32 row,int clr)63604c7d4aSHannes Petermaier static inline void console_setrow0(struct console_t *pcons, u32 row, int clr)
64904672eeSNikita Kiryanov {
65604c7d4aSHannes Petermaier int i;
66604c7d4aSHannes Petermaier fbptr_t *dst = (fbptr_t *)pcons->fbbase +
67604c7d4aSHannes Petermaier row * VIDEO_FONT_HEIGHT *
68604c7d4aSHannes Petermaier pcons->lcdsizex;
69904672eeSNikita Kiryanov
70604c7d4aSHannes Petermaier for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
71604c7d4aSHannes Petermaier *dst++ = clr;
72904672eeSNikita Kiryanov }
73604c7d4aSHannes Petermaier
console_moverow0(struct console_t * pcons,u32 rowdst,u32 rowsrc)74604c7d4aSHannes Petermaier static inline void console_moverow0(struct console_t *pcons,
75604c7d4aSHannes Petermaier u32 rowdst, u32 rowsrc)
76604c7d4aSHannes Petermaier {
77604c7d4aSHannes Petermaier int i;
78604c7d4aSHannes Petermaier fbptr_t *dst = (fbptr_t *)pcons->fbbase +
79604c7d4aSHannes Petermaier rowdst * VIDEO_FONT_HEIGHT *
80604c7d4aSHannes Petermaier pcons->lcdsizex;
81604c7d4aSHannes Petermaier
82604c7d4aSHannes Petermaier fbptr_t *src = (fbptr_t *)pcons->fbbase +
83604c7d4aSHannes Petermaier rowsrc * VIDEO_FONT_HEIGHT *
84604c7d4aSHannes Petermaier pcons->lcdsizex;
85604c7d4aSHannes Petermaier
86604c7d4aSHannes Petermaier for (i = 0; i < (VIDEO_FONT_HEIGHT * pcons->lcdsizex); i++)
87604c7d4aSHannes Petermaier *dst++ = *src++;
88904672eeSNikita Kiryanov }
89904672eeSNikita Kiryanov
console_back(void)90904672eeSNikita Kiryanov static inline void console_back(void)
91904672eeSNikita Kiryanov {
927471142cSHannes Petermaier if (--cons.curr_col < 0) {
937471142cSHannes Petermaier cons.curr_col = cons.cols - 1;
947471142cSHannes Petermaier if (--cons.curr_row < 0)
957471142cSHannes Petermaier cons.curr_row = 0;
96904672eeSNikita Kiryanov }
97904672eeSNikita Kiryanov
98604c7d4aSHannes Petermaier cons.fp_putc_xy(&cons,
99604c7d4aSHannes Petermaier cons.curr_col * VIDEO_FONT_WIDTH,
1007471142cSHannes Petermaier cons.curr_row * VIDEO_FONT_HEIGHT, ' ');
101904672eeSNikita Kiryanov }
102904672eeSNikita Kiryanov
console_newline(void)103904672eeSNikita Kiryanov static inline void console_newline(void)
104904672eeSNikita Kiryanov {
105604c7d4aSHannes Petermaier const int rows = CONFIG_CONSOLE_SCROLL_LINES;
106604c7d4aSHannes Petermaier int bg_color = lcd_getbgcolor();
107604c7d4aSHannes Petermaier int i;
108604c7d4aSHannes Petermaier
1097471142cSHannes Petermaier cons.curr_col = 0;
110904672eeSNikita Kiryanov
111904672eeSNikita Kiryanov /* Check if we need to scroll the terminal */
112604c7d4aSHannes Petermaier if (++cons.curr_row >= cons.rows) {
113604c7d4aSHannes Petermaier for (i = 0; i < cons.rows-rows; i++)
114604c7d4aSHannes Petermaier cons.fp_console_moverow(&cons, i, i+rows);
115604c7d4aSHannes Petermaier for (i = 0; i < rows; i++)
116604c7d4aSHannes Petermaier cons.fp_console_setrow(&cons, cons.rows-i-1, bg_color);
117604c7d4aSHannes Petermaier cons.curr_row -= rows;
118604c7d4aSHannes Petermaier }
119904672eeSNikita Kiryanov lcd_sync();
120904672eeSNikita Kiryanov }
121904672eeSNikita Kiryanov
console_calc_rowcol(struct console_t * pcons,u32 sizex,u32 sizey)122604c7d4aSHannes Petermaier void console_calc_rowcol(struct console_t *pcons, u32 sizex, u32 sizey)
123604c7d4aSHannes Petermaier {
124604c7d4aSHannes Petermaier pcons->cols = sizex / VIDEO_FONT_WIDTH;
125604c7d4aSHannes Petermaier #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO)
126604c7d4aSHannes Petermaier pcons->rows = (pcons->lcdsizey - BMP_LOGO_HEIGHT);
127604c7d4aSHannes Petermaier pcons->rows /= VIDEO_FONT_HEIGHT;
128604c7d4aSHannes Petermaier #else
129604c7d4aSHannes Petermaier pcons->rows = sizey / VIDEO_FONT_HEIGHT;
130604c7d4aSHannes Petermaier #endif
131604c7d4aSHannes Petermaier }
132604c7d4aSHannes Petermaier
lcd_init_console_rot(struct console_t * pcons)133604c7d4aSHannes Petermaier void __weak lcd_init_console_rot(struct console_t *pcons)
134604c7d4aSHannes Petermaier {
135604c7d4aSHannes Petermaier return;
136604c7d4aSHannes Petermaier }
137604c7d4aSHannes Petermaier
lcd_init_console(void * address,int vl_cols,int vl_rows,int vl_rot)138604c7d4aSHannes Petermaier void lcd_init_console(void *address, int vl_cols, int vl_rows, int vl_rot)
139604c7d4aSHannes Petermaier {
140604c7d4aSHannes Petermaier memset(&cons, 0, sizeof(cons));
141604c7d4aSHannes Petermaier cons.fbbase = address;
142604c7d4aSHannes Petermaier
143604c7d4aSHannes Petermaier cons.lcdsizex = vl_cols;
144604c7d4aSHannes Petermaier cons.lcdsizey = vl_rows;
145604c7d4aSHannes Petermaier cons.lcdrot = vl_rot;
146604c7d4aSHannes Petermaier
147604c7d4aSHannes Petermaier cons.fp_putc_xy = &lcd_putc_xy0;
148604c7d4aSHannes Petermaier cons.fp_console_moverow = &console_moverow0;
149604c7d4aSHannes Petermaier cons.fp_console_setrow = &console_setrow0;
150604c7d4aSHannes Petermaier console_calc_rowcol(&cons, cons.lcdsizex, cons.lcdsizey);
151604c7d4aSHannes Petermaier
152604c7d4aSHannes Petermaier lcd_init_console_rot(&cons);
153604c7d4aSHannes Petermaier
154604c7d4aSHannes Petermaier debug("lcd_console: have %d/%d col/rws on scr %dx%d (%d deg rotated)\n",
155604c7d4aSHannes Petermaier cons.cols, cons.rows, cons.lcdsizex, cons.lcdsizey, vl_rot);
156604c7d4aSHannes Petermaier }
157604c7d4aSHannes Petermaier
lcd_putc(const char c)158904672eeSNikita Kiryanov void lcd_putc(const char c)
159904672eeSNikita Kiryanov {
160904672eeSNikita Kiryanov if (!lcd_is_enabled) {
161904672eeSNikita Kiryanov serial_putc(c);
162904672eeSNikita Kiryanov
163904672eeSNikita Kiryanov return;
164904672eeSNikita Kiryanov }
165904672eeSNikita Kiryanov
166904672eeSNikita Kiryanov switch (c) {
167904672eeSNikita Kiryanov case '\r':
1687471142cSHannes Petermaier cons.curr_col = 0;
169904672eeSNikita Kiryanov return;
170904672eeSNikita Kiryanov case '\n':
171904672eeSNikita Kiryanov console_newline();
172904672eeSNikita Kiryanov
173904672eeSNikita Kiryanov return;
174904672eeSNikita Kiryanov case '\t': /* Tab (8 chars alignment) */
1757471142cSHannes Petermaier cons.curr_col += 8;
1767471142cSHannes Petermaier cons.curr_col &= ~7;
177904672eeSNikita Kiryanov
1787471142cSHannes Petermaier if (cons.curr_col >= cons.cols)
179904672eeSNikita Kiryanov console_newline();
180904672eeSNikita Kiryanov
181904672eeSNikita Kiryanov return;
182904672eeSNikita Kiryanov case '\b':
183904672eeSNikita Kiryanov console_back();
184904672eeSNikita Kiryanov
185904672eeSNikita Kiryanov return;
186904672eeSNikita Kiryanov default:
187604c7d4aSHannes Petermaier cons.fp_putc_xy(&cons,
188604c7d4aSHannes Petermaier cons.curr_col * VIDEO_FONT_WIDTH,
1897471142cSHannes Petermaier cons.curr_row * VIDEO_FONT_HEIGHT, c);
1907471142cSHannes Petermaier if (++cons.curr_col >= cons.cols)
191904672eeSNikita Kiryanov console_newline();
192904672eeSNikita Kiryanov }
193904672eeSNikita Kiryanov }
194904672eeSNikita Kiryanov
lcd_puts(const char * s)195904672eeSNikita Kiryanov void lcd_puts(const char *s)
196904672eeSNikita Kiryanov {
197904672eeSNikita Kiryanov if (!lcd_is_enabled) {
198904672eeSNikita Kiryanov serial_puts(s);
199904672eeSNikita Kiryanov
200904672eeSNikita Kiryanov return;
201904672eeSNikita Kiryanov }
202904672eeSNikita Kiryanov
203904672eeSNikita Kiryanov while (*s)
204904672eeSNikita Kiryanov lcd_putc(*s++);
205904672eeSNikita Kiryanov
206904672eeSNikita Kiryanov lcd_sync();
207904672eeSNikita Kiryanov }
208904672eeSNikita Kiryanov
lcd_printf(const char * fmt,...)209904672eeSNikita Kiryanov void lcd_printf(const char *fmt, ...)
210904672eeSNikita Kiryanov {
211904672eeSNikita Kiryanov va_list args;
212904672eeSNikita Kiryanov char buf[CONFIG_SYS_PBSIZE];
213904672eeSNikita Kiryanov
214904672eeSNikita Kiryanov va_start(args, fmt);
215904672eeSNikita Kiryanov vsprintf(buf, fmt, args);
216904672eeSNikita Kiryanov va_end(args);
217904672eeSNikita Kiryanov
218904672eeSNikita Kiryanov lcd_puts(buf);
219904672eeSNikita Kiryanov }
220d38d0c6aSHannes Petermaier
do_lcd_setcursor(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])221d38d0c6aSHannes Petermaier static int do_lcd_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
222d38d0c6aSHannes Petermaier char *const argv[])
223d38d0c6aSHannes Petermaier {
224d38d0c6aSHannes Petermaier unsigned int col, row;
225d38d0c6aSHannes Petermaier
226d38d0c6aSHannes Petermaier if (argc != 3)
227d38d0c6aSHannes Petermaier return CMD_RET_USAGE;
228d38d0c6aSHannes Petermaier
229d38d0c6aSHannes Petermaier col = simple_strtoul(argv[1], NULL, 10);
230d38d0c6aSHannes Petermaier row = simple_strtoul(argv[2], NULL, 10);
231d38d0c6aSHannes Petermaier lcd_position_cursor(col, row);
232d38d0c6aSHannes Petermaier
233d38d0c6aSHannes Petermaier return 0;
234d38d0c6aSHannes Petermaier }
235d38d0c6aSHannes Petermaier
do_lcd_puts(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2361b7caf11SHannes Petermaier static int do_lcd_puts(cmd_tbl_t *cmdtp, int flag, int argc,
2371b7caf11SHannes Petermaier char *const argv[])
2381b7caf11SHannes Petermaier {
2391b7caf11SHannes Petermaier if (argc != 2)
2401b7caf11SHannes Petermaier return CMD_RET_USAGE;
2411b7caf11SHannes Petermaier
2421b7caf11SHannes Petermaier lcd_puts(argv[1]);
2431b7caf11SHannes Petermaier
2441b7caf11SHannes Petermaier return 0;
2451b7caf11SHannes Petermaier }
2461b7caf11SHannes Petermaier
247d38d0c6aSHannes Petermaier U_BOOT_CMD(
248d38d0c6aSHannes Petermaier setcurs, 3, 1, do_lcd_setcursor,
249d38d0c6aSHannes Petermaier "set cursor position within screen",
250d38d0c6aSHannes Petermaier " <col> <row> in character"
251d38d0c6aSHannes Petermaier );
2521b7caf11SHannes Petermaier
2531b7caf11SHannes Petermaier U_BOOT_CMD(
2541b7caf11SHannes Petermaier lcdputs, 2, 1, do_lcd_puts,
2551b7caf11SHannes Petermaier "print string on lcd-framebuffer",
2561b7caf11SHannes Petermaier " <string>"
2571b7caf11SHannes Petermaier );
2581b7caf11SHannes Petermaier
259