/* * (C) Copyright 2001-2014 * DENX Software Engineering -- wd@denx.de * Compulab Ltd - http://compulab.co.il/ * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> #include <lcd.h> #include <video_font.h> /* Get font data, width and height */ #define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * lcd_line_length) #define CONSOLE_ROW_FIRST lcd_console_address #define CONSOLE_SIZE (CONSOLE_ROW_SIZE * console_rows) static short console_curr_col; static short console_curr_row; static short console_cols; static short console_rows; static void *lcd_console_address; void lcd_init_console(void *address, int rows, int cols) { console_curr_col = 0; console_curr_row = 0; console_cols = cols; console_rows = rows; lcd_console_address = address; } void lcd_set_col(short col) { console_curr_col = col; } void lcd_set_row(short row) { console_curr_row = row; } void lcd_position_cursor(unsigned col, unsigned row) { console_curr_col = min_t(short, col, console_cols - 1); console_curr_row = min_t(short, row, console_rows - 1); } int lcd_get_screen_rows(void) { return console_rows; } int lcd_get_screen_columns(void) { return console_cols; } static void lcd_drawchars(ushort x, ushort y, uchar *str, int count) { uchar *dest; ushort row; int fg_color, bg_color; #if LCD_BPP == LCD_MONOCHROME ushort off = x * (1 << LCD_BPP) % 8; #endif dest = (uchar *)(lcd_console_address + y * lcd_line_length + x * NBITS(LCD_BPP) / 8); for (row = 0; row < VIDEO_FONT_HEIGHT; ++row, dest += lcd_line_length) { uchar *s = str; int i; #if LCD_BPP == LCD_COLOR16 ushort *d = (ushort *)dest; #elif LCD_BPP == LCD_COLOR32 u32 *d = (u32 *)dest; #else uchar *d = dest; #endif fg_color = lcd_getfgcolor(); bg_color = lcd_getbgcolor(); #if LCD_BPP == LCD_MONOCHROME uchar rest = *d & -(1 << (8 - off)); uchar sym; #endif for (i = 0; i < count; ++i) { uchar c, bits; c = *s++; bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row]; #if LCD_BPP == LCD_MONOCHROME sym = (COLOR_MASK(fg_color) & bits) | (COLOR_MASK(bg_color) & ~bits); *d++ = rest | (sym >> off); rest = sym << (8-off); #else /* LCD_BPP == LCD_COLOR8 or LCD_COLOR16 or LCD_COLOR32 */ for (c = 0; c < 8; ++c) { *d++ = (bits & 0x80) ? fg_color : bg_color; bits <<= 1; } #endif } #if LCD_BPP == LCD_MONOCHROME *d = rest | (*d & ((1 << (8 - off)) - 1)); #endif } } static inline void lcd_putc_xy(ushort x, ushort y, uchar c) { lcd_drawchars(x, y, &c, 1); } static void console_scrollup(void) { const int rows = CONFIG_CONSOLE_SCROLL_LINES; int bg_color = lcd_getbgcolor(); /* Copy up rows ignoring those that will be overwritten */ memcpy(CONSOLE_ROW_FIRST, lcd_console_address + CONSOLE_ROW_SIZE * rows, CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows); /* Clear the last rows */ #if (LCD_BPP != LCD_COLOR32) memset(lcd_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows, COLOR_MASK(bg_color), CONSOLE_ROW_SIZE * rows); #else u32 *ppix = lcd_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows; u32 i; for (i = 0; i < (CONSOLE_ROW_SIZE * rows) / NBYTES(panel_info.vl_bpix); i++) { *ppix++ = COLOR_MASK(bg_color); } #endif lcd_sync(); console_curr_row -= rows; } static inline void console_back(void) { if (--console_curr_col < 0) { console_curr_col = console_cols - 1; if (--console_curr_row < 0) console_curr_row = 0; } lcd_putc_xy(console_curr_col * VIDEO_FONT_WIDTH, console_curr_row * VIDEO_FONT_HEIGHT, ' '); } static inline void console_newline(void) { console_curr_col = 0; /* Check if we need to scroll the terminal */ if (++console_curr_row >= console_rows) console_scrollup(); else lcd_sync(); } void lcd_putc(const char c) { if (!lcd_is_enabled) { serial_putc(c); return; } switch (c) { case '\r': console_curr_col = 0; return; case '\n': console_newline(); return; case '\t': /* Tab (8 chars alignment) */ console_curr_col += 8; console_curr_col &= ~7; if (console_curr_col >= console_cols) console_newline(); return; case '\b': console_back(); return; default: lcd_putc_xy(console_curr_col * VIDEO_FONT_WIDTH, console_curr_row * VIDEO_FONT_HEIGHT, c); if (++console_curr_col >= console_cols) console_newline(); } } void lcd_puts(const char *s) { if (!lcd_is_enabled) { serial_puts(s); return; } while (*s) lcd_putc(*s++); lcd_sync(); } void lcd_printf(const char *fmt, ...) { va_list args; char buf[CONFIG_SYS_PBSIZE]; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); lcd_puts(buf); } static int do_lcd_setcursor(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { unsigned int col, row; if (argc != 3) return CMD_RET_USAGE; col = simple_strtoul(argv[1], NULL, 10); row = simple_strtoul(argv[2], NULL, 10); lcd_position_cursor(col, row); return 0; } static int do_lcd_puts(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { if (argc != 2) return CMD_RET_USAGE; lcd_puts(argv[1]); return 0; } U_BOOT_CMD( setcurs, 3, 1, do_lcd_setcursor, "set cursor position within screen", " <col> <row> in character" ); U_BOOT_CMD( lcdputs, 2, 1, do_lcd_puts, "print string on lcd-framebuffer", " <string>" );