blob: 7aab81ffbe4913e99764b53e664a72c31c86c9ff [file] [log] [blame]
/*
* (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>"
);