| /* |
| * (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>" |
| ); |
| |