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