lcd: refactor lcd console stuff into its own file
common/lcd.c is a mix of code portions that do different but related
things. To improve modularity, the various code portions should be split
into their own modules. Separate lcd console code into its own file.
Signed-off-by: Nikita Kiryanov <nikita@compulab.co.il>
Cc: Anatolij Gustschin <agust@denx.de>
Cc: Simon Glass <sjg@chromium.org>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Acked-by: Simon Glass <sjg@chromium.org>
Tested-by: Simon Glass <sjg@chromium.org>
diff --git a/common/lcd_console.c b/common/lcd_console.c
new file mode 100644
index 0000000..f948e5a
--- /dev/null
+++ b/common/lcd_console.c
@@ -0,0 +1,215 @@
+/*
+ * (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_ROW_SECOND (lcd_console_address + CONSOLE_ROW_SIZE)
+#define CONSOLE_ROW_LAST (lcd_console_address + CONSOLE_SIZE \
+ - CONSOLE_ROW_SIZE)
+#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * console_rows)
+#define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
+
+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;
+
+ 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();
+ for (i = 0; i < count; ++i) {
+ uchar c, bits;
+
+ c = *s++;
+ bits = video_fontdata[c * VIDEO_FONT_HEIGHT + row];
+
+ for (c = 0; c < 8; ++c) {
+ *d++ = (bits & 0x80) ? fg_color : bg_color;
+ bits <<= 1;
+ }
+ }
+ }
+}
+
+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,
+ 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++ = 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);
+}