blob: 3a8e20bcca99599dfeca76ed2aed328f328410a4 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2002 ELTEC Elektronik AG
3 * Frank Gottschling <fgottschling@eltec.de>
4 *
Wolfgang Denk3765b3e2013-10-07 13:07:26 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +00006 */
7
8/*
9 * cfb_console.c
10 *
11 * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel.
12 *
13 * At the moment only the 8x16 font is tested and the font fore- and
14 * background color is limited to black/white/gray colors. The Linux
15 * logo can be placed in the upper left corner and additional board
Wolfgang Denk64e40d72011-07-29 09:55:27 +000016 * information strings (that normally goes to serial port) can be drawn.
wdenkc6097192002-11-03 00:24:07 +000017 *
Simon Glass39f615e2015-11-11 10:05:47 -070018 * The console driver can use a keyboard interface for character input
19 * but this is deprecated. Only rk51 uses it.
20 *
21 * Character output goes to a memory-mapped video
wdenkc6097192002-11-03 00:24:07 +000022 * framebuffer with little or big-endian organisation.
23 * With environment setting 'console=serial' the console i/o can be
24 * forced to serial port.
Wolfgang Denk64e40d72011-07-29 09:55:27 +000025 *
26 * The driver uses graphic specific defines/parameters/functions:
27 *
28 * (for SMI LynxE graphic chip)
29 *
Wolfgang Denk64e40d72011-07-29 09:55:27 +000030 * VIDEO_FB_LITTLE_ENDIAN - framebuffer organisation default: big endian
31 * VIDEO_HW_RECTFILL - graphic driver supports hardware rectangle fill
32 * VIDEO_HW_BITBLT - graphic driver supports hardware bit blt
33 *
34 * Console Parameters are set by graphic drivers global struct:
35 *
36 * VIDEO_VISIBLE_COLS - x resolution
37 * VIDEO_VISIBLE_ROWS - y resolution
38 * VIDEO_PIXEL_SIZE - storage size in byte per pixel
39 * VIDEO_DATA_FORMAT - graphical data format GDF
40 * VIDEO_FB_ADRS - start of video memory
41 *
Wolfgang Denk64e40d72011-07-29 09:55:27 +000042 * VIDEO_KBD_INIT_FCT - init function for keyboard
43 * VIDEO_TSTC_FCT - keyboard_tstc function
44 * VIDEO_GETC_FCT - keyboard_getc function
45 *
Bastian Ruppert1e681f92012-09-13 22:29:01 +000046 * CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner.
47 * Use CONFIG_SPLASH_SCREEN_ALIGN with
48 * environment variable "splashpos" to place
49 * the logo on other position. In this case
50 * no CONSOLE_EXTRA_INFO is possible.
Wolfgang Denk64e40d72011-07-29 09:55:27 +000051 * CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo
52 * CONFIG_CONSOLE_EXTRA_INFO - display additional board information
53 * strings that normaly goes to serial
54 * port. This define requires a board
55 * specific function:
56 * video_drawstring (VIDEO_INFO_X,
57 * VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT,
58 * info);
59 * that fills a info buffer at i=row.
60 * s.a: board/eltec/bab7xx.
Wolfgang Denk64e40d72011-07-29 09:55:27 +000061 *
62 * CONFIG_VIDEO_SW_CURSOR: - Draws a cursor after the last
63 * character. No blinking is provided.
64 * Uses the macros CURSOR_SET and
65 * CURSOR_OFF.
66 *
67 * CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability
68 * of the graphic chip. Uses the macro
69 * CURSOR_SET. ATTENTION: If booting an
70 * OS, the display driver must disable
71 * the hardware register of the graphic
72 * chip. Otherwise a blinking field is
73 * displayed.
74 */
wdenkc6097192002-11-03 00:24:07 +000075
76#include <common.h>
Simon Glass5692ccf2015-03-02 12:40:50 -070077#include <fdtdec.h>
Andreas Bießmann09c2e902011-07-18 20:24:04 +020078#include <version.h>
wdenka6c7ad22002-12-03 21:28:10 +000079#include <malloc.h>
Wolfgang Denka9a62af2011-11-04 15:55:20 +000080#include <linux/compiler.h>
wdenka6c7ad22002-12-03 21:28:10 +000081
Wolfgang Denk64e40d72011-07-29 09:55:27 +000082/*
Wolfgang Denk64e40d72011-07-29 09:55:27 +000083 * Defines for the CT69000 driver
84 */
wdenk4b248f32004-03-14 16:51:43 +000085#ifdef CONFIG_VIDEO_CT69000
wdenkc6097192002-11-03 00:24:07 +000086
87#define VIDEO_FB_LITTLE_ENDIAN
88#define VIDEO_HW_RECTFILL
89#define VIDEO_HW_BITBLT
90#endif
91
Simon Glassc370d382016-10-17 20:12:47 -060092#if defined(CONFIG_VIDEO_MXS)
Marek Vasutfb8ddc22013-04-28 09:20:03 +000093#define VIDEO_FB_16BPP_WORD_SWAP
94#endif
95
Wolfgang Denk64e40d72011-07-29 09:55:27 +000096/*
97 * Defines for the MB862xx driver
98 */
Anatolij Gustschinbed53752008-01-11 14:30:01 +010099#ifdef CONFIG_VIDEO_MB862xx
100
101#ifdef CONFIG_VIDEO_CORALP
102#define VIDEO_FB_LITTLE_ENDIAN
103#endif
Anatolij Gustschin5d16ca82009-10-23 12:03:14 +0200104#ifdef CONFIG_VIDEO_MB862xx_ACCEL
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100105#define VIDEO_HW_RECTFILL
106#define VIDEO_HW_BITBLT
107#endif
Anatolij Gustschin5d16ca82009-10-23 12:03:14 +0200108#endif
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100109
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000110/*
Helmut Raiger62a22dc2011-10-12 23:16:29 +0000111 * Defines for the i.MX31 driver (mx3fb.c)
112 */
Fabio Estevam695af9a2012-05-31 07:23:56 +0000113#if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3)
Helmut Raiger62a22dc2011-10-12 23:16:29 +0000114#define VIDEO_FB_16BPP_WORD_SWAP
115#endif
116
117/*
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000118 * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
119 */
wdenkc6097192002-11-03 00:24:07 +0000120#include <video_fb.h>
121
Robert Winklerdd4425e2013-06-17 11:31:29 -0700122#include <splash.h>
123
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000124/*
125 * some Macros
126 */
wdenk4b248f32004-03-14 16:51:43 +0000127#define VIDEO_VISIBLE_COLS (pGD->winSizeX)
128#define VIDEO_VISIBLE_ROWS (pGD->winSizeY)
129#define VIDEO_PIXEL_SIZE (pGD->gdfBytesPP)
130#define VIDEO_DATA_FORMAT (pGD->gdfIndex)
131#define VIDEO_FB_ADRS (pGD->frameAdrs)
wdenkc6097192002-11-03 00:24:07 +0000132
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000133/*
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000134 * Console device
135 */
wdenkc6097192002-11-03 00:24:07 +0000136
137#include <version.h>
138#include <linux/types.h>
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200139#include <stdio_dev.h>
wdenkc6097192002-11-03 00:24:07 +0000140#include <video_font.h>
wdenkc6097192002-11-03 00:24:07 +0000141
Jon Loeligerddb5d86f2007-07-10 11:13:21 -0500142#if defined(CONFIG_CMD_DATE)
143#include <rtc.h>
wdenkc6097192002-11-03 00:24:07 +0000144#endif
145
Jon Loeliger07d38a12007-07-09 17:30:01 -0500146#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenk4b248f32004-03-14 16:51:43 +0000147#include <watchdog.h>
148#include <bmp_layout.h>
Anatolij Gustschinff8fb562013-07-02 00:04:05 +0200149#include <splash.h>
Jon Loeliger07d38a12007-07-09 17:30:01 -0500150#endif
wdenk4b248f32004-03-14 16:51:43 +0000151
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000152/*
153 * Cursor definition:
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000154 * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No
155 * blinking is provided. Uses the macros CURSOR_SET
156 * and CURSOR_OFF.
157 * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the
158 * graphic chip. Uses the macro CURSOR_SET.
159 * ATTENTION: If booting an OS, the display driver
160 * must disable the hardware register of the graphic
161 * chip. Otherwise a blinking field is displayed
162 */
Simon Glass7fe09332015-10-18 21:17:18 -0600163#if !defined(CONFIG_VIDEO_SW_CURSOR) && !defined(CONFIG_VIDEO_HW_CURSOR)
wdenkc6097192002-11-03 00:24:07 +0000164/* no Cursor defined */
165#define CURSOR_ON
166#define CURSOR_OFF
167#define CURSOR_SET
168#endif
169
Simon Glass7fe09332015-10-18 21:17:18 -0600170#if defined(CONFIG_VIDEO_SW_CURSOR)
171#if defined(CONFIG_VIDEO_HW_CURSOR)
172#error only one of CONFIG_VIDEO_SW_CURSOR or CONFIG_VIDEO_HW_CURSOR can be \
173 defined
wdenkc6097192002-11-03 00:24:07 +0000174#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000175void console_cursor(int state);
176
Timur Tabi65618632010-08-27 15:45:47 -0500177#define CURSOR_ON console_cursor(1)
178#define CURSOR_OFF console_cursor(0)
Gabe Black03d31fc2011-11-30 13:50:50 +0000179#define CURSOR_SET video_set_cursor()
Simon Glass7fe09332015-10-18 21:17:18 -0600180#endif /* CONFIG_VIDEO_SW_CURSOR */
wdenkc6097192002-11-03 00:24:07 +0000181
182#ifdef CONFIG_VIDEO_HW_CURSOR
wdenk4b248f32004-03-14 16:51:43 +0000183#ifdef CURSOR_ON
Simon Glass7fe09332015-10-18 21:17:18 -0600184#error only one of CONFIG_VIDEO_SW_CURSOR or CONFIG_VIDEO_HW_CURSOR can be \
185 defined
wdenkc6097192002-11-03 00:24:07 +0000186#endif
187#define CURSOR_ON
188#define CURSOR_OFF
189#define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \
Timur Tabi65618632010-08-27 15:45:47 -0500190 (console_row * VIDEO_FONT_HEIGHT) + video_logo_height)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000191#endif /* CONFIG_VIDEO_HW_CURSOR */
wdenkc6097192002-11-03 00:24:07 +0000192
wdenk4b248f32004-03-14 16:51:43 +0000193#ifdef CONFIG_VIDEO_LOGO
194#ifdef CONFIG_VIDEO_BMP_LOGO
wdenka6c7ad22002-12-03 21:28:10 +0000195#include <bmp_logo.h>
Che-Liang Chiouc2707302011-10-20 23:04:20 +0000196#include <bmp_logo_data.h>
wdenk4b248f32004-03-14 16:51:43 +0000197#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH
198#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT
199#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET
200#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS
wdenka6c7ad22002-12-03 21:28:10 +0000201
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000202#else /* CONFIG_VIDEO_BMP_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000203#define LINUX_LOGO_WIDTH 80
204#define LINUX_LOGO_HEIGHT 80
205#define LINUX_LOGO_COLORS 214
206#define LINUX_LOGO_LUT_OFFSET 0x20
wdenkc6097192002-11-03 00:24:07 +0000207#define __initdata
208#include <linux_logo.h>
wdenk4b248f32004-03-14 16:51:43 +0000209#define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH
210#define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT
211#define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET
212#define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000213#endif /* CONFIG_VIDEO_BMP_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000214#define VIDEO_INFO_X (VIDEO_LOGO_WIDTH)
215#define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000216#else /* CONFIG_VIDEO_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000217#define VIDEO_LOGO_WIDTH 0
218#define VIDEO_LOGO_HEIGHT 0
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000219#endif /* CONFIG_VIDEO_LOGO */
wdenkc6097192002-11-03 00:24:07 +0000220
wdenk4b248f32004-03-14 16:51:43 +0000221#define VIDEO_COLS VIDEO_VISIBLE_COLS
222#define VIDEO_ROWS VIDEO_VISIBLE_ROWS
Hans de Goedec67a8762015-08-04 12:15:39 +0200223#ifndef VIDEO_LINE_LEN
224#define VIDEO_LINE_LEN (VIDEO_COLS * VIDEO_PIXEL_SIZE)
225#endif
226#define VIDEO_SIZE (VIDEO_ROWS * VIDEO_LINE_LEN)
wdenk4b248f32004-03-14 16:51:43 +0000227#define VIDEO_BURST_LEN (VIDEO_COLS/8)
wdenkc6097192002-11-03 00:24:07 +0000228
wdenk4b248f32004-03-14 16:51:43 +0000229#ifdef CONFIG_VIDEO_LOGO
Matthias Weisserbe129aa2010-01-12 12:06:31 +0100230#define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000231#else
wdenk4b248f32004-03-14 16:51:43 +0000232#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000233#endif
234
wdenk4b248f32004-03-14 16:51:43 +0000235#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH)
236#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
237#define CONSOLE_ROW_FIRST (video_console_address)
238#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE)
239#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
240#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
Simon Glass3c0b6682015-01-01 16:17:57 -0700241
242/* By default we scroll by a single line */
243#ifndef CONFIG_CONSOLE_SCROLL_LINES
244#define CONFIG_CONSOLE_SCROLL_LINES 1
245#endif
wdenkc6097192002-11-03 00:24:07 +0000246
247/* Macros */
wdenk4b248f32004-03-14 16:51:43 +0000248#ifdef VIDEO_FB_LITTLE_ENDIAN
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000249#define SWAP16(x) ((((x) & 0x00ff) << 8) | \
250 ((x) >> 8) \
251 )
252#define SWAP32(x) ((((x) & 0x000000ff) << 24) | \
253 (((x) & 0x0000ff00) << 8) | \
254 (((x) & 0x00ff0000) >> 8) | \
255 (((x) & 0xff000000) >> 24) \
256 )
257#define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | \
258 (((x) & 0x0000ff00) >> 8) | \
259 (((x) & 0x00ff0000) << 8) | \
260 (((x) & 0xff000000) >> 8) \
261 )
wdenkc6097192002-11-03 00:24:07 +0000262#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000263#define SWAP16(x) (x)
264#define SWAP32(x) (x)
Wolfgang Grandegger229b6dc2009-10-23 12:03:15 +0200265#if defined(VIDEO_FB_16BPP_WORD_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000266#define SHORTSWAP32(x) (((x) >> 16) | ((x) << 16))
Andrew Dyercc347802008-08-29 12:30:39 -0500267#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000268#define SHORTSWAP32(x) (x)
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100269#endif
wdenkc6097192002-11-03 00:24:07 +0000270#endif
271
wdenkc6097192002-11-03 00:24:07 +0000272#ifdef CONFIG_CONSOLE_EXTRA_INFO
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000273/*
274 * setup a board string: type, speed, etc.
275 *
276 * line_number: location to place info string beside logo
277 * info: buffer for info string
278 */
279extern void video_get_info_str(int line_number, char *info);
wdenkc6097192002-11-03 00:24:07 +0000280#endif
281
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +0200282DECLARE_GLOBAL_DATA_PTR;
283
wdenkc6097192002-11-03 00:24:07 +0000284/* Locals */
285static GraphicDevice *pGD; /* Pointer to Graphic array */
286
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000287static void *video_fb_address; /* frame buffer address */
wdenk4b248f32004-03-14 16:51:43 +0000288static void *video_console_address; /* console buffer start address */
wdenkc6097192002-11-03 00:24:07 +0000289
Matthias Weisserbe129aa2010-01-12 12:06:31 +0100290static int video_logo_height = VIDEO_LOGO_HEIGHT;
291
Anatolij Gustschina45adde2011-12-07 03:58:10 +0000292static int __maybe_unused cursor_state;
293static int __maybe_unused old_col;
294static int __maybe_unused old_row;
Gabe Black03d31fc2011-11-30 13:50:50 +0000295
Wolfgang Denk57912932011-07-30 12:48:09 +0000296static int console_col; /* cursor col */
297static int console_row; /* cursor row */
wdenkc6097192002-11-03 00:24:07 +0000298
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000299static u32 eorx, fgx, bgx; /* color pats */
wdenkc6097192002-11-03 00:24:07 +0000300
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +0200301static int cfb_do_flush_cache;
302
Pali Rohár33a35bb2012-10-19 13:30:09 +0000303#ifdef CONFIG_CFB_CONSOLE_ANSI
304static char ansi_buf[10];
305static int ansi_buf_size;
306static int ansi_colors_need_revert;
307static int ansi_cursor_hidden;
308#endif
309
wdenkc6097192002-11-03 00:24:07 +0000310static const int video_font_draw_table8[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000311 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
312 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
313 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
314 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
315};
wdenkc6097192002-11-03 00:24:07 +0000316
317static const int video_font_draw_table15[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000318 0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff
319};
wdenkc6097192002-11-03 00:24:07 +0000320
321static const int video_font_draw_table16[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000322 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
323};
wdenkc6097192002-11-03 00:24:07 +0000324
325static const int video_font_draw_table24[16][3] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000326 {0x00000000, 0x00000000, 0x00000000},
327 {0x00000000, 0x00000000, 0x00ffffff},
328 {0x00000000, 0x0000ffff, 0xff000000},
329 {0x00000000, 0x0000ffff, 0xffffffff},
330 {0x000000ff, 0xffff0000, 0x00000000},
331 {0x000000ff, 0xffff0000, 0x00ffffff},
332 {0x000000ff, 0xffffffff, 0xff000000},
333 {0x000000ff, 0xffffffff, 0xffffffff},
334 {0xffffff00, 0x00000000, 0x00000000},
335 {0xffffff00, 0x00000000, 0x00ffffff},
336 {0xffffff00, 0x0000ffff, 0xff000000},
337 {0xffffff00, 0x0000ffff, 0xffffffff},
338 {0xffffffff, 0xffff0000, 0x00000000},
339 {0xffffffff, 0xffff0000, 0x00ffffff},
340 {0xffffffff, 0xffffffff, 0xff000000},
341 {0xffffffff, 0xffffffff, 0xffffffff}
342};
wdenkc6097192002-11-03 00:24:07 +0000343
344static const int video_font_draw_table32[16][4] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000345 {0x00000000, 0x00000000, 0x00000000, 0x00000000},
346 {0x00000000, 0x00000000, 0x00000000, 0x00ffffff},
347 {0x00000000, 0x00000000, 0x00ffffff, 0x00000000},
348 {0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff},
349 {0x00000000, 0x00ffffff, 0x00000000, 0x00000000},
350 {0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff},
351 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000},
352 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff},
353 {0x00ffffff, 0x00000000, 0x00000000, 0x00000000},
354 {0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff},
355 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000},
356 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff},
357 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000},
358 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff},
359 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000},
360 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff}
361};
wdenkc6097192002-11-03 00:24:07 +0000362
Heiko Schocher2bc4aa52013-08-03 07:22:53 +0200363/*
364 * Implement a weak default function for boards that optionally
365 * need to skip the cfb initialization.
366 */
367__weak int board_cfb_skip(void)
368{
369 /* As default, don't skip cfb init */
370 return 0;
371}
372
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000373static void video_drawchars(int xx, int yy, unsigned char *s, int count)
wdenkc6097192002-11-03 00:24:07 +0000374{
wdenk4b248f32004-03-14 16:51:43 +0000375 u8 *cdat, *dest, *dest0;
376 int rows, offset, c;
wdenkc6097192002-11-03 00:24:07 +0000377
wdenk4b248f32004-03-14 16:51:43 +0000378 offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
379 dest0 = video_fb_address + offset;
wdenkc6097192002-11-03 00:24:07 +0000380
wdenk4b248f32004-03-14 16:51:43 +0000381 switch (VIDEO_DATA_FORMAT) {
382 case GDF__8BIT_INDEX:
383 case GDF__8BIT_332RGB:
384 while (count--) {
385 c = *s;
386 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
387 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000388 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000389 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000390
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000391 ((u32 *) dest)[0] =
392 (video_font_draw_table8[bits >> 4] &
393 eorx) ^ bgx;
Marek Vasutfd8cf992013-07-30 23:37:59 +0200394
395 if (VIDEO_FONT_WIDTH == 4)
396 continue;
397
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000398 ((u32 *) dest)[1] =
399 (video_font_draw_table8[bits & 15] &
400 eorx) ^ bgx;
wdenk4b248f32004-03-14 16:51:43 +0000401 }
402 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
403 s++;
404 }
405 break;
wdenkc6097192002-11-03 00:24:07 +0000406
wdenk4b248f32004-03-14 16:51:43 +0000407 case GDF_15BIT_555RGB:
408 while (count--) {
409 c = *s;
410 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
411 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000412 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000413 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000414
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000415 ((u32 *) dest)[0] =
416 SHORTSWAP32((video_font_draw_table15
417 [bits >> 6] & eorx) ^
418 bgx);
419 ((u32 *) dest)[1] =
420 SHORTSWAP32((video_font_draw_table15
421 [bits >> 4 & 3] & eorx) ^
422 bgx);
Marek Vasutfd8cf992013-07-30 23:37:59 +0200423
424 if (VIDEO_FONT_WIDTH == 4)
425 continue;
426
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000427 ((u32 *) dest)[2] =
428 SHORTSWAP32((video_font_draw_table15
429 [bits >> 2 & 3] & eorx) ^
430 bgx);
431 ((u32 *) dest)[3] =
432 SHORTSWAP32((video_font_draw_table15
433 [bits & 3] & eorx) ^
434 bgx);
wdenk4b248f32004-03-14 16:51:43 +0000435 }
436 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
437 s++;
438 }
439 break;
wdenkc6097192002-11-03 00:24:07 +0000440
wdenk4b248f32004-03-14 16:51:43 +0000441 case GDF_16BIT_565RGB:
442 while (count--) {
443 c = *s;
444 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
445 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000446 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000447 u8 bits = *cdat++;
448
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000449 ((u32 *) dest)[0] =
450 SHORTSWAP32((video_font_draw_table16
451 [bits >> 6] & eorx) ^
452 bgx);
453 ((u32 *) dest)[1] =
454 SHORTSWAP32((video_font_draw_table16
455 [bits >> 4 & 3] & eorx) ^
456 bgx);
Marek Vasutfd8cf992013-07-30 23:37:59 +0200457
458 if (VIDEO_FONT_WIDTH == 4)
459 continue;
460
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000461 ((u32 *) dest)[2] =
462 SHORTSWAP32((video_font_draw_table16
463 [bits >> 2 & 3] & eorx) ^
464 bgx);
465 ((u32 *) dest)[3] =
466 SHORTSWAP32((video_font_draw_table16
467 [bits & 3] & eorx) ^
468 bgx);
wdenk4b248f32004-03-14 16:51:43 +0000469 }
470 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
471 s++;
472 }
473 break;
474
475 case GDF_32BIT_X888RGB:
476 while (count--) {
477 c = *s;
478 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
479 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000480 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000481 u8 bits = *cdat++;
482
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000483 ((u32 *) dest)[0] =
484 SWAP32((video_font_draw_table32
485 [bits >> 4][0] & eorx) ^ bgx);
486 ((u32 *) dest)[1] =
487 SWAP32((video_font_draw_table32
488 [bits >> 4][1] & eorx) ^ bgx);
489 ((u32 *) dest)[2] =
490 SWAP32((video_font_draw_table32
491 [bits >> 4][2] & eorx) ^ bgx);
492 ((u32 *) dest)[3] =
493 SWAP32((video_font_draw_table32
494 [bits >> 4][3] & eorx) ^ bgx);
Marek Vasutfd8cf992013-07-30 23:37:59 +0200495
496
497 if (VIDEO_FONT_WIDTH == 4)
498 continue;
499
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000500 ((u32 *) dest)[4] =
501 SWAP32((video_font_draw_table32
502 [bits & 15][0] & eorx) ^ bgx);
503 ((u32 *) dest)[5] =
504 SWAP32((video_font_draw_table32
505 [bits & 15][1] & eorx) ^ bgx);
506 ((u32 *) dest)[6] =
507 SWAP32((video_font_draw_table32
508 [bits & 15][2] & eorx) ^ bgx);
509 ((u32 *) dest)[7] =
510 SWAP32((video_font_draw_table32
511 [bits & 15][3] & eorx) ^ bgx);
wdenk4b248f32004-03-14 16:51:43 +0000512 }
513 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
514 s++;
515 }
516 break;
517
518 case GDF_24BIT_888RGB:
519 while (count--) {
520 c = *s;
521 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
522 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000523 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000524 u8 bits = *cdat++;
525
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000526 ((u32 *) dest)[0] =
527 (video_font_draw_table24[bits >> 4][0]
528 & eorx) ^ bgx;
529 ((u32 *) dest)[1] =
530 (video_font_draw_table24[bits >> 4][1]
531 & eorx) ^ bgx;
532 ((u32 *) dest)[2] =
533 (video_font_draw_table24[bits >> 4][2]
534 & eorx) ^ bgx;
Marek Vasutfd8cf992013-07-30 23:37:59 +0200535
536 if (VIDEO_FONT_WIDTH == 4)
537 continue;
538
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000539 ((u32 *) dest)[3] =
540 (video_font_draw_table24[bits & 15][0]
541 & eorx) ^ bgx;
542 ((u32 *) dest)[4] =
543 (video_font_draw_table24[bits & 15][1]
544 & eorx) ^ bgx;
545 ((u32 *) dest)[5] =
546 (video_font_draw_table24[bits & 15][2]
547 & eorx) ^ bgx;
wdenk4b248f32004-03-14 16:51:43 +0000548 }
549 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
550 s++;
551 }
552 break;
wdenk8bde7f72003-06-27 21:31:46 +0000553 }
wdenkc6097192002-11-03 00:24:07 +0000554}
555
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000556static inline void video_drawstring(int xx, int yy, unsigned char *s)
wdenkc6097192002-11-03 00:24:07 +0000557{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000558 video_drawchars(xx, yy, s, strlen((char *) s));
wdenkc6097192002-11-03 00:24:07 +0000559}
560
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000561static void video_putchar(int xx, int yy, unsigned char c)
wdenkc6097192002-11-03 00:24:07 +0000562{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000563 video_drawchars(xx, yy + video_logo_height, &c, 1);
wdenkc6097192002-11-03 00:24:07 +0000564}
565
Simon Glass7fe09332015-10-18 21:17:18 -0600566#if defined(CONFIG_VIDEO_SW_CURSOR)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000567static void video_set_cursor(void)
wdenkc6097192002-11-03 00:24:07 +0000568{
Gabe Black03d31fc2011-11-30 13:50:50 +0000569 if (cursor_state)
570 console_cursor(0);
571 console_cursor(1);
wdenkc6097192002-11-03 00:24:07 +0000572}
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000573
Anatolij Gustschina45adde2011-12-07 03:58:10 +0000574static void video_invertchar(int xx, int yy)
575{
576 int firstx = xx * VIDEO_PIXEL_SIZE;
577 int lastx = (xx + VIDEO_FONT_WIDTH) * VIDEO_PIXEL_SIZE;
578 int firsty = yy * VIDEO_LINE_LEN;
579 int lasty = (yy + VIDEO_FONT_HEIGHT) * VIDEO_LINE_LEN;
580 int x, y;
581 for (y = firsty; y < lasty; y += VIDEO_LINE_LEN) {
582 for (x = firstx; x < lastx; x++) {
583 u8 *dest = (u8 *)(video_fb_address) + x + y;
584 *dest = ~*dest;
585 }
586 }
587}
Gabe Black03d31fc2011-11-30 13:50:50 +0000588
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000589void console_cursor(int state)
wdenkc6097192002-11-03 00:24:07 +0000590{
Gabe Black03d31fc2011-11-30 13:50:50 +0000591 if (cursor_state != state) {
592 if (cursor_state) {
593 /* turn off the cursor */
594 video_invertchar(old_col * VIDEO_FONT_WIDTH,
595 old_row * VIDEO_FONT_HEIGHT +
596 video_logo_height);
597 } else {
598 /* turn off the cursor and record where it is */
599 video_invertchar(console_col * VIDEO_FONT_WIDTH,
600 console_row * VIDEO_FONT_HEIGHT +
601 video_logo_height);
602 old_col = console_col;
603 old_row = console_row;
604 }
605 cursor_state = state;
wdenk4b248f32004-03-14 16:51:43 +0000606 }
Eric Nelsondb0d47d2013-05-06 14:27:28 +0200607 if (cfb_do_flush_cache)
608 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
wdenkc6097192002-11-03 00:24:07 +0000609}
610#endif
611
wdenkc6097192002-11-03 00:24:07 +0000612#ifndef VIDEO_HW_RECTFILL
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000613static void memsetl(int *p, int c, int v)
wdenkc6097192002-11-03 00:24:07 +0000614{
wdenk4b248f32004-03-14 16:51:43 +0000615 while (c--)
616 *(p++) = v;
wdenkc6097192002-11-03 00:24:07 +0000617}
618#endif
619
wdenkc6097192002-11-03 00:24:07 +0000620#ifndef VIDEO_HW_BITBLT
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000621static void memcpyl(int *d, int *s, int c)
wdenkc6097192002-11-03 00:24:07 +0000622{
wdenk4b248f32004-03-14 16:51:43 +0000623 while (c--)
624 *(d++) = *(s++);
wdenkc6097192002-11-03 00:24:07 +0000625}
626#endif
627
Pali Rohár90f60a82012-04-28 07:26:44 +0000628static void console_clear_line(int line, int begin, int end)
629{
630#ifdef VIDEO_HW_RECTFILL
631 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */
632 VIDEO_FONT_WIDTH * begin, /* dest pos x */
633 video_logo_height +
634 VIDEO_FONT_HEIGHT * line, /* dest pos y */
635 VIDEO_FONT_WIDTH * (end - begin + 1), /* fr. width */
636 VIDEO_FONT_HEIGHT, /* frame height */
637 bgx /* fill color */
638 );
639#else
640 if (begin == 0 && (end + 1) == CONSOLE_COLS) {
641 memsetl(CONSOLE_ROW_FIRST +
642 CONSOLE_ROW_SIZE * line, /* offset of row */
643 CONSOLE_ROW_SIZE >> 2, /* length of row */
644 bgx /* fill color */
645 );
646 } else {
647 void *offset;
648 int i, size;
649
650 offset = CONSOLE_ROW_FIRST +
651 CONSOLE_ROW_SIZE * line + /* offset of row */
652 VIDEO_FONT_WIDTH *
653 VIDEO_PIXEL_SIZE * begin; /* offset of col */
654 size = VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE * (end - begin + 1);
655 size >>= 2; /* length to end for memsetl() */
656 /* fill at col offset of i'th line using bgx as fill color */
657 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
658 memsetl(offset + i * VIDEO_LINE_LEN, size, bgx);
659 }
660#endif
661}
662
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000663static void console_scrollup(void)
wdenkc6097192002-11-03 00:24:07 +0000664{
Simon Glass3c0b6682015-01-01 16:17:57 -0700665 const int rows = CONFIG_CONSOLE_SCROLL_LINES;
666 int i;
667
wdenk4b248f32004-03-14 16:51:43 +0000668 /* copy up rows ignoring the first one */
wdenkc6097192002-11-03 00:24:07 +0000669
670#ifdef VIDEO_HW_BITBLT
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000671 video_hw_bitblt(VIDEO_PIXEL_SIZE, /* bytes per pixel */
672 0, /* source pos x */
673 video_logo_height +
Simon Glass3c0b6682015-01-01 16:17:57 -0700674 VIDEO_FONT_HEIGHT * rows, /* source pos y */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000675 0, /* dest pos x */
676 video_logo_height, /* dest pos y */
677 VIDEO_VISIBLE_COLS, /* frame width */
678 VIDEO_VISIBLE_ROWS
679 - video_logo_height
Simon Glass3c0b6682015-01-01 16:17:57 -0700680 - VIDEO_FONT_HEIGHT * rows /* frame height */
wdenk4b248f32004-03-14 16:51:43 +0000681 );
wdenkc6097192002-11-03 00:24:07 +0000682#else
Simon Glass3c0b6682015-01-01 16:17:57 -0700683 memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_FIRST + rows * CONSOLE_ROW_SIZE,
684 (CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows) >> 2);
wdenkc6097192002-11-03 00:24:07 +0000685#endif
wdenk4b248f32004-03-14 16:51:43 +0000686 /* clear the last one */
Simon Glass3c0b6682015-01-01 16:17:57 -0700687 for (i = 1; i <= rows; i++)
688 console_clear_line(CONSOLE_ROWS - i, 0, CONSOLE_COLS - 1);
689
690 /* Decrement row number */
691 console_row -= rows;
wdenkc6097192002-11-03 00:24:07 +0000692}
693
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000694static void console_back(void)
wdenkc6097192002-11-03 00:24:07 +0000695{
Timur Tabi65618632010-08-27 15:45:47 -0500696 console_col--;
wdenkc6097192002-11-03 00:24:07 +0000697
wdenk4b248f32004-03-14 16:51:43 +0000698 if (console_col < 0) {
699 console_col = CONSOLE_COLS - 1;
700 console_row--;
701 if (console_row < 0)
702 console_row = 0;
703 }
wdenkc6097192002-11-03 00:24:07 +0000704}
705
Pali Rohár33a35bb2012-10-19 13:30:09 +0000706#ifdef CONFIG_CFB_CONSOLE_ANSI
707
708static void console_clear(void)
wdenkc6097192002-11-03 00:24:07 +0000709{
Pali Rohár33a35bb2012-10-19 13:30:09 +0000710#ifdef VIDEO_HW_RECTFILL
711 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */
712 0, /* dest pos x */
713 video_logo_height, /* dest pos y */
714 VIDEO_VISIBLE_COLS, /* frame width */
715 VIDEO_VISIBLE_ROWS, /* frame height */
716 bgx /* fill color */
717 );
718#else
719 memsetl(CONSOLE_ROW_FIRST, CONSOLE_SIZE, bgx);
720#endif
721}
722
723static void console_cursor_fix(void)
724{
725 if (console_row < 0)
726 console_row = 0;
727 if (console_row >= CONSOLE_ROWS)
728 console_row = CONSOLE_ROWS - 1;
729 if (console_col < 0)
730 console_col = 0;
731 if (console_col >= CONSOLE_COLS)
732 console_col = CONSOLE_COLS - 1;
733}
734
735static void console_cursor_up(int n)
736{
737 console_row -= n;
738 console_cursor_fix();
739}
740
741static void console_cursor_down(int n)
742{
743 console_row += n;
744 console_cursor_fix();
745}
746
747static void console_cursor_left(int n)
748{
749 console_col -= n;
750 console_cursor_fix();
751}
752
753static void console_cursor_right(int n)
754{
755 console_col += n;
756 console_cursor_fix();
757}
758
759static void console_cursor_set_position(int row, int col)
760{
761 if (console_row != -1)
762 console_row = row;
763 if (console_col != -1)
764 console_col = col;
765 console_cursor_fix();
766}
767
768static void console_previousline(int n)
769{
770 /* FIXME: also scroll terminal ? */
771 console_row -= n;
772 console_cursor_fix();
773}
774
775static void console_swap_colors(void)
776{
777 eorx = fgx;
778 fgx = bgx;
779 bgx = eorx;
780 eorx = fgx ^ bgx;
781}
782
783static inline int console_cursor_is_visible(void)
784{
785 return !ansi_cursor_hidden;
786}
787#else
788static inline int console_cursor_is_visible(void)
789{
790 return 1;
791}
792#endif
793
794static void console_newline(int n)
795{
796 console_row += n;
wdenk4b248f32004-03-14 16:51:43 +0000797 console_col = 0;
wdenkc6097192002-11-03 00:24:07 +0000798
wdenk4b248f32004-03-14 16:51:43 +0000799 /* Check if we need to scroll the terminal */
800 if (console_row >= CONSOLE_ROWS) {
801 /* Scroll everything up */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000802 console_scrollup();
wdenk4b248f32004-03-14 16:51:43 +0000803 }
wdenkc6097192002-11-03 00:24:07 +0000804}
805
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000806static void console_cr(void)
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100807{
Timur Tabi65618632010-08-27 15:45:47 -0500808 console_col = 0;
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100809}
810
Pali Rohár33a35bb2012-10-19 13:30:09 +0000811static void parse_putc(const char c)
wdenkc6097192002-11-03 00:24:07 +0000812{
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100813 static int nl = 1;
814
Pali Rohár33a35bb2012-10-19 13:30:09 +0000815 if (console_cursor_is_visible())
816 CURSOR_OFF;
Gabe Black03d31fc2011-11-30 13:50:50 +0000817
wdenk4b248f32004-03-14 16:51:43 +0000818 switch (c) {
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100819 case 13: /* back to first column */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000820 console_cr();
wdenk4b248f32004-03-14 16:51:43 +0000821 break;
wdenkc6097192002-11-03 00:24:07 +0000822
wdenk4b248f32004-03-14 16:51:43 +0000823 case '\n': /* next line */
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100824 if (console_col || (!console_col && nl))
Pali Rohár33a35bb2012-10-19 13:30:09 +0000825 console_newline(1);
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100826 nl = 1;
wdenk4b248f32004-03-14 16:51:43 +0000827 break;
wdenkc6097192002-11-03 00:24:07 +0000828
wdenk4b248f32004-03-14 16:51:43 +0000829 case 9: /* tab 8 */
Timur Tabi65618632010-08-27 15:45:47 -0500830 console_col |= 0x0008;
wdenk4b248f32004-03-14 16:51:43 +0000831 console_col &= ~0x0007;
wdenkc6097192002-11-03 00:24:07 +0000832
wdenk4b248f32004-03-14 16:51:43 +0000833 if (console_col >= CONSOLE_COLS)
Pali Rohár33a35bb2012-10-19 13:30:09 +0000834 console_newline(1);
wdenk4b248f32004-03-14 16:51:43 +0000835 break;
wdenkc6097192002-11-03 00:24:07 +0000836
wdenk4b248f32004-03-14 16:51:43 +0000837 case 8: /* backspace */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000838 console_back();
wdenk4b248f32004-03-14 16:51:43 +0000839 break;
wdenkc6097192002-11-03 00:24:07 +0000840
Pali Rohár24fe06c2012-04-28 07:26:47 +0000841 case 7: /* bell */
842 break; /* ignored */
843
wdenk4b248f32004-03-14 16:51:43 +0000844 default: /* draw the char */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000845 video_putchar(console_col * VIDEO_FONT_WIDTH,
846 console_row * VIDEO_FONT_HEIGHT, c);
wdenk4b248f32004-03-14 16:51:43 +0000847 console_col++;
wdenkc6097192002-11-03 00:24:07 +0000848
wdenk4b248f32004-03-14 16:51:43 +0000849 /* check for newline */
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100850 if (console_col >= CONSOLE_COLS) {
Pali Rohár33a35bb2012-10-19 13:30:09 +0000851 console_newline(1);
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100852 nl = 0;
853 }
wdenk4b248f32004-03-14 16:51:43 +0000854 }
Pali Rohár33a35bb2012-10-19 13:30:09 +0000855
856 if (console_cursor_is_visible())
857 CURSOR_SET;
858}
859
Jeroen Hofstee654f8d02014-10-08 22:57:44 +0200860static void video_putc(struct stdio_dev *dev, const char c)
Pali Rohár33a35bb2012-10-19 13:30:09 +0000861{
862#ifdef CONFIG_CFB_CONSOLE_ANSI
863 int i;
864
865 if (c == 27) {
866 for (i = 0; i < ansi_buf_size; ++i)
867 parse_putc(ansi_buf[i]);
868 ansi_buf[0] = 27;
869 ansi_buf_size = 1;
870 return;
871 }
872
873 if (ansi_buf_size > 0) {
874 /*
875 * 0 - ESC
876 * 1 - [
877 * 2 - num1
878 * 3 - ..
879 * 4 - ;
880 * 5 - num2
881 * 6 - ..
882 * - cchar
883 */
884 int next = 0;
885
886 int flush = 0;
887 int fail = 0;
888
889 int num1 = 0;
890 int num2 = 0;
891 int cchar = 0;
892
893 ansi_buf[ansi_buf_size++] = c;
894
895 if (ansi_buf_size >= sizeof(ansi_buf))
896 fail = 1;
897
898 for (i = 0; i < ansi_buf_size; ++i) {
899 if (fail)
900 break;
901
902 switch (next) {
903 case 0:
904 if (ansi_buf[i] == 27)
905 next = 1;
906 else
907 fail = 1;
908 break;
909
910 case 1:
911 if (ansi_buf[i] == '[')
912 next = 2;
913 else
914 fail = 1;
915 break;
916
917 case 2:
918 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
919 num1 = ansi_buf[i]-'0';
920 next = 3;
921 } else if (ansi_buf[i] != '?') {
922 --i;
923 num1 = 1;
924 next = 4;
925 }
926 break;
927
928 case 3:
929 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
930 num1 *= 10;
931 num1 += ansi_buf[i]-'0';
932 } else {
933 --i;
934 next = 4;
935 }
936 break;
937
938 case 4:
939 if (ansi_buf[i] != ';') {
940 --i;
941 next = 7;
942 } else
943 next = 5;
944 break;
945
946 case 5:
947 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
948 num2 = ansi_buf[i]-'0';
949 next = 6;
950 } else
951 fail = 1;
952 break;
953
954 case 6:
955 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
956 num2 *= 10;
957 num2 += ansi_buf[i]-'0';
958 } else {
959 --i;
960 next = 7;
961 }
962 break;
963
964 case 7:
965 if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H')
966 || ansi_buf[i] == 'J'
967 || ansi_buf[i] == 'K'
968 || ansi_buf[i] == 'h'
969 || ansi_buf[i] == 'l'
970 || ansi_buf[i] == 'm') {
971 cchar = ansi_buf[i];
972 flush = 1;
973 } else
974 fail = 1;
975 break;
976 }
977 }
978
979 if (fail) {
980 for (i = 0; i < ansi_buf_size; ++i)
981 parse_putc(ansi_buf[i]);
982 ansi_buf_size = 0;
983 return;
984 }
985
986 if (flush) {
987 if (!ansi_cursor_hidden)
988 CURSOR_OFF;
989 ansi_buf_size = 0;
990 switch (cchar) {
991 case 'A':
992 /* move cursor num1 rows up */
993 console_cursor_up(num1);
994 break;
995 case 'B':
996 /* move cursor num1 rows down */
997 console_cursor_down(num1);
998 break;
999 case 'C':
1000 /* move cursor num1 columns forward */
1001 console_cursor_right(num1);
1002 break;
1003 case 'D':
1004 /* move cursor num1 columns back */
1005 console_cursor_left(num1);
1006 break;
1007 case 'E':
1008 /* move cursor num1 rows up at begin of row */
1009 console_previousline(num1);
1010 break;
1011 case 'F':
1012 /* move cursor num1 rows down at begin of row */
1013 console_newline(num1);
1014 break;
1015 case 'G':
1016 /* move cursor to column num1 */
1017 console_cursor_set_position(-1, num1-1);
1018 break;
1019 case 'H':
1020 /* move cursor to row num1, column num2 */
1021 console_cursor_set_position(num1-1, num2-1);
1022 break;
1023 case 'J':
1024 /* clear console and move cursor to 0, 0 */
1025 console_clear();
1026 console_cursor_set_position(0, 0);
1027 break;
1028 case 'K':
1029 /* clear line */
1030 if (num1 == 0)
1031 console_clear_line(console_row,
1032 console_col,
1033 CONSOLE_COLS-1);
1034 else if (num1 == 1)
1035 console_clear_line(console_row,
1036 0, console_col);
1037 else
1038 console_clear_line(console_row,
1039 0, CONSOLE_COLS-1);
1040 break;
1041 case 'h':
1042 ansi_cursor_hidden = 0;
1043 break;
1044 case 'l':
1045 ansi_cursor_hidden = 1;
1046 break;
1047 case 'm':
1048 if (num1 == 0) { /* reset swapped colors */
1049 if (ansi_colors_need_revert) {
1050 console_swap_colors();
1051 ansi_colors_need_revert = 0;
1052 }
1053 } else if (num1 == 7) { /* once swap colors */
1054 if (!ansi_colors_need_revert) {
1055 console_swap_colors();
1056 ansi_colors_need_revert = 1;
1057 }
1058 }
1059 break;
1060 }
1061 if (!ansi_cursor_hidden)
1062 CURSOR_SET;
1063 }
1064 } else {
1065 parse_putc(c);
1066 }
1067#else
1068 parse_putc(c);
1069#endif
Eric Nelsondb0d47d2013-05-06 14:27:28 +02001070 if (cfb_do_flush_cache)
1071 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
Timur Tabi65618632010-08-27 15:45:47 -05001072}
wdenkc6097192002-11-03 00:24:07 +00001073
Jeroen Hofstee654f8d02014-10-08 22:57:44 +02001074static void video_puts(struct stdio_dev *dev, const char *s)
wdenkc6097192002-11-03 00:24:07 +00001075{
Soeren Mochd37e96e2014-10-24 16:33:30 +02001076 int flush = cfb_do_flush_cache;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001077 int count = strlen(s);
wdenkc6097192002-11-03 00:24:07 +00001078
Soeren Mochd37e96e2014-10-24 16:33:30 +02001079 /* temporarily disable cache flush */
1080 cfb_do_flush_cache = 0;
1081
wdenk4b248f32004-03-14 16:51:43 +00001082 while (count--)
Simon Glass709ea542014-07-23 06:54:59 -06001083 video_putc(dev, *s++);
Soeren Mochd37e96e2014-10-24 16:33:30 +02001084
1085 if (flush) {
1086 cfb_do_flush_cache = flush;
1087 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1088 }
wdenkc6097192002-11-03 00:24:07 +00001089}
1090
Anatolij Gustschin10543822010-05-01 22:21:09 +02001091/*
1092 * Do not enforce drivers (or board code) to provide empty
1093 * video_set_lut() if they do not support 8 bpp format.
1094 * Implement weak default function instead.
1095 */
Jeroen Hofstee69d27542014-10-08 22:57:30 +02001096__weak void video_set_lut(unsigned int index, unsigned char r,
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001097 unsigned char g, unsigned char b)
Anatolij Gustschin10543822010-05-01 22:21:09 +02001098{
1099}
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001100
Jon Loeliger07d38a12007-07-09 17:30:01 -05001101#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenk4b248f32004-03-14 16:51:43 +00001102
1103#define FILL_8BIT_332RGB(r,g,b) { \
1104 *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6); \
1105 fb ++; \
1106}
1107
1108#define FILL_15BIT_555RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001109 *(unsigned short *)fb = \
1110 SWAP16((unsigned short)(((r>>3)<<10) | \
1111 ((g>>3)<<5) | \
1112 (b>>3))); \
wdenk4b248f32004-03-14 16:51:43 +00001113 fb += 2; \
1114}
1115
1116#define FILL_16BIT_565RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001117 *(unsigned short *)fb = \
1118 SWAP16((unsigned short)((((r)>>3)<<11)| \
1119 (((g)>>2)<<5) | \
1120 ((b)>>3))); \
wdenk4b248f32004-03-14 16:51:43 +00001121 fb += 2; \
1122}
1123
1124#define FILL_32BIT_X888RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001125 *(unsigned long *)fb = \
1126 SWAP32((unsigned long)(((r<<16) | \
1127 (g<<8) | \
1128 b))); \
wdenk4b248f32004-03-14 16:51:43 +00001129 fb += 4; \
1130}
1131
1132#ifdef VIDEO_FB_LITTLE_ENDIAN
1133#define FILL_24BIT_888RGB(r,g,b) { \
1134 fb[0] = b; \
1135 fb[1] = g; \
1136 fb[2] = r; \
1137 fb += 3; \
1138}
1139#else
1140#define FILL_24BIT_888RGB(r,g,b) { \
1141 fb[0] = r; \
1142 fb[1] = g; \
1143 fb[2] = b; \
1144 fb += 3; \
1145}
1146#endif
1147
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001148#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001149static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001150{
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001151 ushort *dst = (ushort *) fb;
1152 ushort color = (ushort) (((r >> 3) << 10) |
1153 ((g >> 3) << 5) |
1154 (b >> 3));
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001155 if (x & 1)
1156 *(--dst) = color;
1157 else
1158 *(++dst) = color;
1159}
1160#endif
wdenk4b248f32004-03-14 16:51:43 +00001161
1162/*
Anatolij Gustschind5011762010-03-15 14:50:25 +01001163 * RLE8 bitmap support
1164 */
1165
1166#ifdef CONFIG_VIDEO_BMP_RLE8
1167/* Pre-calculated color table entry */
1168struct palette {
1169 union {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001170 unsigned short w; /* word */
1171 unsigned int dw; /* double word */
1172 } ce; /* color entry */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001173};
1174
1175/*
1176 * Helper to draw encoded/unencoded run.
1177 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001178static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
1179 int cnt, int enc)
Anatolij Gustschind5011762010-03-15 14:50:25 +01001180{
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001181 ulong addr = (ulong) *fb;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001182 int *off;
1183 int enc_off = 1;
1184 int i;
1185
1186 /*
1187 * Setup offset of the color index in the bitmap.
1188 * Color index of encoded run is at offset 1.
1189 */
1190 off = enc ? &enc_off : &i;
1191
1192 switch (VIDEO_DATA_FORMAT) {
1193 case GDF__8BIT_INDEX:
1194 for (i = 0; i < cnt; i++)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001195 *(unsigned char *) addr++ = bm[*off];
Anatolij Gustschind5011762010-03-15 14:50:25 +01001196 break;
1197 case GDF_15BIT_555RGB:
1198 case GDF_16BIT_565RGB:
1199 /* differences handled while pre-calculating palette */
1200 for (i = 0; i < cnt; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001201 *(unsigned short *) addr = p[bm[*off]].ce.w;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001202 addr += 2;
1203 }
1204 break;
1205 case GDF_32BIT_X888RGB:
1206 for (i = 0; i < cnt; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001207 *(unsigned long *) addr = p[bm[*off]].ce.dw;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001208 addr += 4;
1209 }
1210 break;
1211 }
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001212 *fb = (uchar *) addr; /* return modified address */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001213}
1214
Simon Glass1c3dbe52015-05-13 07:02:27 -06001215static int display_rle8_bitmap(struct bmp_image *img, int xoff, int yoff,
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001216 int width, int height)
Anatolij Gustschind5011762010-03-15 14:50:25 +01001217{
1218 unsigned char *bm;
1219 unsigned char *fbp;
1220 unsigned int cnt, runlen;
1221 int decode = 1;
1222 int x, y, bpp, i, ncolors;
1223 struct palette p[256];
Simon Glass1c3dbe52015-05-13 07:02:27 -06001224 struct bmp_color_table_entry cte;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001225 int green_shift, red_off;
Hans de Goedec67a8762015-08-04 12:15:39 +02001226 int limit = (VIDEO_LINE_LEN / VIDEO_PIXEL_SIZE) * VIDEO_ROWS;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001227 int pixels = 0;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001228
1229 x = 0;
1230 y = __le32_to_cpu(img->header.height) - 1;
1231 ncolors = __le32_to_cpu(img->header.colors_used);
1232 bpp = VIDEO_PIXEL_SIZE;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001233 fbp = (unsigned char *) ((unsigned int) video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001234 (y + yoff) * VIDEO_LINE_LEN +
1235 xoff * bpp);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001236
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001237 bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001238
1239 /* pre-calculate and setup palette */
1240 switch (VIDEO_DATA_FORMAT) {
1241 case GDF__8BIT_INDEX:
1242 for (i = 0; i < ncolors; i++) {
1243 cte = img->color_table[i];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001244 video_set_lut(i, cte.red, cte.green, cte.blue);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001245 }
1246 break;
1247 case GDF_15BIT_555RGB:
1248 case GDF_16BIT_565RGB:
1249 if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
1250 green_shift = 3;
1251 red_off = 10;
1252 } else {
1253 green_shift = 2;
1254 red_off = 11;
1255 }
1256 for (i = 0; i < ncolors; i++) {
1257 cte = img->color_table[i];
1258 p[i].ce.w = SWAP16((unsigned short)
1259 (((cte.red >> 3) << red_off) |
1260 ((cte.green >> green_shift) << 5) |
1261 cte.blue >> 3));
1262 }
1263 break;
1264 case GDF_32BIT_X888RGB:
1265 for (i = 0; i < ncolors; i++) {
1266 cte = img->color_table[i];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001267 p[i].ce.dw = SWAP32((cte.red << 16) |
1268 (cte.green << 8) |
Anatolij Gustschind5011762010-03-15 14:50:25 +01001269 cte.blue);
1270 }
1271 break;
1272 default:
1273 printf("RLE Bitmap unsupported in video mode 0x%x\n",
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001274 VIDEO_DATA_FORMAT);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001275 return -1;
1276 }
1277
1278 while (decode) {
1279 switch (bm[0]) {
1280 case 0:
1281 switch (bm[1]) {
1282 case 0:
1283 /* scan line end marker */
1284 bm += 2;
1285 x = 0;
1286 y--;
1287 fbp = (unsigned char *)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001288 ((unsigned int) video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001289 (y + yoff) * VIDEO_LINE_LEN +
1290 xoff * bpp);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001291 continue;
1292 case 1:
1293 /* end of bitmap data marker */
1294 decode = 0;
1295 break;
1296 case 2:
1297 /* run offset marker */
1298 x += bm[2];
1299 y -= bm[3];
1300 fbp = (unsigned char *)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001301 ((unsigned int) video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001302 (y + yoff) * VIDEO_LINE_LEN +
1303 xoff * bpp);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001304 bm += 4;
1305 break;
1306 default:
1307 /* unencoded run */
1308 cnt = bm[1];
1309 runlen = cnt;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001310 pixels += cnt;
1311 if (pixels > limit)
1312 goto error;
1313
Anatolij Gustschind5011762010-03-15 14:50:25 +01001314 bm += 2;
1315 if (y < height) {
1316 if (x >= width) {
1317 x += runlen;
1318 goto next_run;
1319 }
1320 if (x + runlen > width)
1321 cnt = width - x;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001322 draw_bitmap(&fbp, bm, p, cnt, 0);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001323 x += runlen;
1324 }
1325next_run:
1326 bm += runlen;
1327 if (runlen & 1)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001328 bm++; /* 0 padding if length is odd */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001329 }
1330 break;
1331 default:
1332 /* encoded run */
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001333 cnt = bm[0];
1334 runlen = cnt;
1335 pixels += cnt;
1336 if (pixels > limit)
1337 goto error;
1338
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001339 if (y < height) { /* only draw into visible area */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001340 if (x >= width) {
1341 x += runlen;
1342 bm += 2;
1343 continue;
1344 }
1345 if (x + runlen > width)
1346 cnt = width - x;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001347 draw_bitmap(&fbp, bm, p, cnt, 1);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001348 x += runlen;
1349 }
1350 bm += 2;
1351 break;
1352 }
1353 }
1354 return 0;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001355error:
1356 printf("Error: Too much encoded pixel data, validate your bitmap\n");
1357 return -1;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001358}
1359#endif
1360
1361/*
wdenk4b248f32004-03-14 16:51:43 +00001362 * Display the BMP file located at address bmp_image.
wdenk4b248f32004-03-14 16:51:43 +00001363 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001364int video_display_bitmap(ulong bmp_image, int x, int y)
wdenk4b248f32004-03-14 16:51:43 +00001365{
1366 ushort xcount, ycount;
1367 uchar *fb;
Simon Glass1c3dbe52015-05-13 07:02:27 -06001368 struct bmp_image *bmp = (struct bmp_image *)bmp_image;
wdenk4b248f32004-03-14 16:51:43 +00001369 uchar *bmap;
1370 ushort padded_line;
1371 unsigned long width, height, bpp;
1372 unsigned colors;
1373 unsigned long compression;
Simon Glass1c3dbe52015-05-13 07:02:27 -06001374 struct bmp_color_table_entry cte;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001375
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001376#ifdef CONFIG_VIDEO_BMP_GZIP
1377 unsigned char *dst = NULL;
1378 ulong len;
1379#endif
wdenk4b248f32004-03-14 16:51:43 +00001380
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001381 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001382
1383 if (!((bmp->header.signature[0] == 'B') &&
1384 (bmp->header.signature[1] == 'M'))) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001385
1386#ifdef CONFIG_VIDEO_BMP_GZIP
1387 /*
1388 * Could be a gzipped bmp image, try to decrompress...
1389 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001390 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1391 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001392 if (dst == NULL) {
1393 printf("Error: malloc in gunzip failed!\n");
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001394 return 1;
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001395 }
Eric Nelson5ca05c82014-03-08 07:55:52 -07001396 /*
1397 * NB: we need to force offset of +2
1398 * See doc/README.displaying-bmps
1399 */
1400 if (gunzip(dst+2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE-2,
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001401 (uchar *) bmp_image,
1402 &len) != 0) {
1403 printf("Error: no valid bmp or bmp.gz image at %lx\n",
1404 bmp_image);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001405 free(dst);
1406 return 1;
1407 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001408 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001409 printf("Image could be truncated "
1410 "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001411 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001412
1413 /*
1414 * Set addr to decompressed image
1415 */
Simon Glass1c3dbe52015-05-13 07:02:27 -06001416 bmp = (struct bmp_image *)(dst+2);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001417
1418 if (!((bmp->header.signature[0] == 'B') &&
1419 (bmp->header.signature[1] == 'M'))) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001420 printf("Error: no valid bmp.gz image at %lx\n",
1421 bmp_image);
Matthias Fuchsa49e0d12008-04-21 11:19:04 +02001422 free(dst);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001423 return 1;
1424 }
1425#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001426 printf("Error: no valid bmp image at %lx\n", bmp_image);
wdenk4b248f32004-03-14 16:51:43 +00001427 return 1;
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001428#endif /* CONFIG_VIDEO_BMP_GZIP */
wdenk4b248f32004-03-14 16:51:43 +00001429 }
1430
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001431 width = le32_to_cpu(bmp->header.width);
1432 height = le32_to_cpu(bmp->header.height);
1433 bpp = le16_to_cpu(bmp->header.bit_count);
1434 colors = le32_to_cpu(bmp->header.colors_used);
1435 compression = le32_to_cpu(bmp->header.compression);
wdenk4b248f32004-03-14 16:51:43 +00001436
Marek Vasut68da5b12011-10-21 14:17:04 +00001437 debug("Display-bmp: %ld x %ld with %d colors\n",
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001438 width, height, colors);
wdenk4b248f32004-03-14 16:51:43 +00001439
Anatolij Gustschind5011762010-03-15 14:50:25 +01001440 if (compression != BMP_BI_RGB
1441#ifdef CONFIG_VIDEO_BMP_RLE8
1442 && compression != BMP_BI_RLE8
1443#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001444 ) {
1445 printf("Error: compression type %ld not supported\n",
1446 compression);
Matthias Fuchsa49e0d12008-04-21 11:19:04 +02001447#ifdef CONFIG_VIDEO_BMP_GZIP
1448 if (dst)
1449 free(dst);
1450#endif
wdenk4b248f32004-03-14 16:51:43 +00001451 return 1;
1452 }
1453
1454 padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1455
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001456#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1457 if (x == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001458 x = max(0, (int)(VIDEO_VISIBLE_COLS - width) / 2);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001459 else if (x < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001460 x = max(0, (int)(VIDEO_VISIBLE_COLS - width + x + 1));
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001461
1462 if (y == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001463 y = max(0, (int)(VIDEO_VISIBLE_ROWS - height) / 2);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001464 else if (y < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001465 y = max(0, (int)(VIDEO_VISIBLE_ROWS - height + y + 1));
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001466#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1467
Matthias Weisseracf3baa2013-02-15 03:35:12 +00001468 /*
1469 * Just ignore elements which are completely beyond screen
1470 * dimensions.
1471 */
1472 if ((x >= VIDEO_VISIBLE_COLS) || (y >= VIDEO_VISIBLE_ROWS))
1473 return 0;
1474
wdenk4b248f32004-03-14 16:51:43 +00001475 if ((x + width) > VIDEO_VISIBLE_COLS)
1476 width = VIDEO_VISIBLE_COLS - x;
1477 if ((y + height) > VIDEO_VISIBLE_ROWS)
1478 height = VIDEO_VISIBLE_ROWS - y;
1479
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001480 bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
wdenk4b248f32004-03-14 16:51:43 +00001481 fb = (uchar *) (video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001482 ((y + height - 1) * VIDEO_LINE_LEN) +
wdenk4b248f32004-03-14 16:51:43 +00001483 x * VIDEO_PIXEL_SIZE);
1484
Anatolij Gustschind5011762010-03-15 14:50:25 +01001485#ifdef CONFIG_VIDEO_BMP_RLE8
1486 if (compression == BMP_BI_RLE8) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001487 return display_rle8_bitmap(bmp, x, y, width, height);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001488 }
1489#endif
1490
Timur Tabi68f66182010-08-23 16:58:00 -05001491 /* We handle only 4, 8, or 24 bpp bitmaps */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001492 switch (le16_to_cpu(bmp->header.bit_count)) {
Timur Tabi68f66182010-08-23 16:58:00 -05001493 case 4:
1494 padded_line -= width / 2;
1495 ycount = height;
1496
1497 switch (VIDEO_DATA_FORMAT) {
1498 case GDF_32BIT_X888RGB:
1499 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001500 WATCHDOG_RESET();
Timur Tabi68f66182010-08-23 16:58:00 -05001501 /*
1502 * Don't assume that 'width' is an
1503 * even number
1504 */
1505 for (xcount = 0; xcount < width; xcount++) {
1506 uchar idx;
1507
1508 if (xcount & 1) {
1509 idx = *bmap & 0xF;
1510 bmap++;
1511 } else
1512 idx = *bmap >> 4;
1513 cte = bmp->color_table[idx];
1514 FILL_32BIT_X888RGB(cte.red, cte.green,
1515 cte.blue);
1516 }
1517 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001518 fb -= VIDEO_LINE_LEN + width *
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001519 VIDEO_PIXEL_SIZE;
Timur Tabi68f66182010-08-23 16:58:00 -05001520 }
1521 break;
1522 default:
1523 puts("4bpp bitmap unsupported with current "
1524 "video mode\n");
1525 break;
1526 }
1527 break;
1528
wdenk4b248f32004-03-14 16:51:43 +00001529 case 8:
1530 padded_line -= width;
1531 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001532 /* Copy colormap */
wdenk4b248f32004-03-14 16:51:43 +00001533 for (xcount = 0; xcount < colors; ++xcount) {
1534 cte = bmp->color_table[xcount];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001535 video_set_lut(xcount, cte.red, cte.green,
1536 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001537 }
1538 }
1539 ycount = height;
1540 switch (VIDEO_DATA_FORMAT) {
1541 case GDF__8BIT_INDEX:
1542 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001543 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001544 xcount = width;
1545 while (xcount--) {
1546 *fb++ = *bmap++;
1547 }
1548 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001549 fb -= VIDEO_LINE_LEN + width *
1550 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001551 }
1552 break;
1553 case GDF__8BIT_332RGB:
1554 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001555 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001556 xcount = width;
1557 while (xcount--) {
1558 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001559 FILL_8BIT_332RGB(cte.red, cte.green,
1560 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001561 }
1562 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001563 fb -= VIDEO_LINE_LEN + width *
1564 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001565 }
1566 break;
1567 case GDF_15BIT_555RGB:
1568 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001569#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1570 int xpos = x;
1571#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001572 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001573 xcount = width;
1574 while (xcount--) {
1575 cte = bmp->color_table[*bmap++];
Andrew Dyercc347802008-08-29 12:30:39 -05001576#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001577 fill_555rgb_pswap(fb, xpos++, cte.red,
1578 cte.green,
1579 cte.blue);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001580 fb += 2;
Andrew Dyercc347802008-08-29 12:30:39 -05001581#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001582 FILL_15BIT_555RGB(cte.red, cte.green,
1583 cte.blue);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001584#endif
wdenk4b248f32004-03-14 16:51:43 +00001585 }
1586 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001587 fb -= VIDEO_LINE_LEN + width *
1588 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001589 }
1590 break;
1591 case GDF_16BIT_565RGB:
1592 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001593 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001594 xcount = width;
1595 while (xcount--) {
1596 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001597 FILL_16BIT_565RGB(cte.red, cte.green,
1598 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001599 }
1600 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001601 fb -= VIDEO_LINE_LEN + width *
1602 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001603 }
1604 break;
1605 case GDF_32BIT_X888RGB:
1606 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001607 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001608 xcount = width;
1609 while (xcount--) {
1610 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001611 FILL_32BIT_X888RGB(cte.red, cte.green,
1612 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001613 }
1614 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001615 fb -= VIDEO_LINE_LEN + width *
1616 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001617 }
1618 break;
1619 case GDF_24BIT_888RGB:
1620 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001621 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001622 xcount = width;
1623 while (xcount--) {
1624 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001625 FILL_24BIT_888RGB(cte.red, cte.green,
1626 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001627 }
1628 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001629 fb -= VIDEO_LINE_LEN + width *
1630 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001631 }
1632 break;
1633 }
1634 break;
1635 case 24:
1636 padded_line -= 3 * width;
1637 ycount = height;
1638 switch (VIDEO_DATA_FORMAT) {
1639 case GDF__8BIT_332RGB:
1640 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001641 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001642 xcount = width;
1643 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001644 FILL_8BIT_332RGB(bmap[2], bmap[1],
1645 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001646 bmap += 3;
1647 }
1648 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001649 fb -= VIDEO_LINE_LEN + width *
1650 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001651 }
1652 break;
1653 case GDF_15BIT_555RGB:
1654 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001655#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1656 int xpos = x;
1657#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001658 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001659 xcount = width;
1660 while (xcount--) {
Andrew Dyercc347802008-08-29 12:30:39 -05001661#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001662 fill_555rgb_pswap(fb, xpos++, bmap[2],
1663 bmap[1], bmap[0]);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001664 fb += 2;
Andrew Dyercc347802008-08-29 12:30:39 -05001665#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001666 FILL_15BIT_555RGB(bmap[2], bmap[1],
1667 bmap[0]);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001668#endif
wdenk4b248f32004-03-14 16:51:43 +00001669 bmap += 3;
1670 }
1671 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001672 fb -= VIDEO_LINE_LEN + width *
1673 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001674 }
1675 break;
1676 case GDF_16BIT_565RGB:
1677 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001678 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001679 xcount = width;
1680 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001681 FILL_16BIT_565RGB(bmap[2], bmap[1],
1682 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001683 bmap += 3;
1684 }
1685 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001686 fb -= VIDEO_LINE_LEN + width *
1687 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001688 }
1689 break;
1690 case GDF_32BIT_X888RGB:
1691 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001692 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001693 xcount = width;
1694 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001695 FILL_32BIT_X888RGB(bmap[2], bmap[1],
1696 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001697 bmap += 3;
1698 }
1699 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001700 fb -= VIDEO_LINE_LEN + width *
1701 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001702 }
1703 break;
1704 case GDF_24BIT_888RGB:
1705 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001706 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001707 xcount = width;
1708 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001709 FILL_24BIT_888RGB(bmap[2], bmap[1],
1710 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001711 bmap += 3;
1712 }
1713 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001714 fb -= VIDEO_LINE_LEN + width *
1715 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001716 }
1717 break;
1718 default:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001719 printf("Error: 24 bits/pixel bitmap incompatible "
1720 "with current video mode\n");
wdenk4b248f32004-03-14 16:51:43 +00001721 break;
1722 }
1723 break;
1724 default:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001725 printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1726 le16_to_cpu(bmp->header.bit_count));
wdenk4b248f32004-03-14 16:51:43 +00001727 break;
1728 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001729
1730#ifdef CONFIG_VIDEO_BMP_GZIP
1731 if (dst) {
1732 free(dst);
1733 }
1734#endif
1735
Eric Nelsondb0d47d2013-05-06 14:27:28 +02001736 if (cfb_do_flush_cache)
1737 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
wdenk4b248f32004-03-14 16:51:43 +00001738 return (0);
1739}
Jon Loeliger07d38a12007-07-09 17:30:01 -05001740#endif
wdenk4b248f32004-03-14 16:51:43 +00001741
wdenk4b248f32004-03-14 16:51:43 +00001742
wdenkc6097192002-11-03 00:24:07 +00001743#ifdef CONFIG_VIDEO_LOGO
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001744static int video_logo_xpos;
1745static int video_logo_ypos;
1746
Hans de Goedec4c9e812015-08-04 12:21:40 +02001747static void plot_logo_or_black(void *screen, int x, int y, int black);
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001748
Hans de Goedec4c9e812015-08-04 12:21:40 +02001749static void logo_plot(void *screen, int x, int y)
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001750{
Hans de Goedec4c9e812015-08-04 12:21:40 +02001751 plot_logo_or_black(screen, x, y, 0);
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001752}
1753
1754static void logo_black(void)
1755{
Hans de Goedec4c9e812015-08-04 12:21:40 +02001756 plot_logo_or_black(video_fb_address, video_logo_xpos, video_logo_ypos,
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001757 1);
1758}
1759
1760static int do_clrlogo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1761{
1762 if (argc != 1)
1763 return cmd_usage(cmdtp);
1764
1765 logo_black();
1766 return 0;
1767}
1768
1769U_BOOT_CMD(
1770 clrlogo, 1, 0, do_clrlogo,
1771 "fill the boot logo area with black",
1772 " "
1773 );
1774
Hans de Goedec4c9e812015-08-04 12:21:40 +02001775static void plot_logo_or_black(void *screen, int x, int y, int black)
wdenkc6097192002-11-03 00:24:07 +00001776{
wdenkc6097192002-11-03 00:24:07 +00001777
wdenk4b248f32004-03-14 16:51:43 +00001778 int xcount, i;
Hans de Goedec67a8762015-08-04 12:15:39 +02001779 int skip = VIDEO_LINE_LEN - VIDEO_LOGO_WIDTH * VIDEO_PIXEL_SIZE;
Matthias Weisserbe129aa2010-01-12 12:06:31 +01001780 int ycount = video_logo_height;
wdenk4b248f32004-03-14 16:51:43 +00001781 unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1782 unsigned char *source;
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001783 unsigned char *dest;
1784
1785#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1786 if (x == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001787 x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2);
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001788 else if (x < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001789 x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1));
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001790
1791 if (y == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001792 y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2);
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001793 else if (y < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001794 y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1));
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001795#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1796
Hans de Goedec67a8762015-08-04 12:15:39 +02001797 dest = (unsigned char *)screen + y * VIDEO_LINE_LEN + x * VIDEO_PIXEL_SIZE;
wdenka6c7ad22002-12-03 21:28:10 +00001798
1799#ifdef CONFIG_VIDEO_BMP_LOGO
wdenk4b248f32004-03-14 16:51:43 +00001800 source = bmp_logo_bitmap;
wdenk8bde7f72003-06-27 21:31:46 +00001801
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001802 /* Allocate temporary space for computing colormap */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001803 logo_red = malloc(BMP_LOGO_COLORS);
1804 logo_green = malloc(BMP_LOGO_COLORS);
1805 logo_blue = malloc(BMP_LOGO_COLORS);
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001806 /* Compute color map */
wdenk4b248f32004-03-14 16:51:43 +00001807 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1808 logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1809 logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1810 logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1811 }
wdenka6c7ad22002-12-03 21:28:10 +00001812#else
wdenk4b248f32004-03-14 16:51:43 +00001813 source = linux_logo;
1814 logo_red = linux_logo_red;
1815 logo_green = linux_logo_green;
1816 logo_blue = linux_logo_blue;
wdenka6c7ad22002-12-03 21:28:10 +00001817#endif
wdenk8bde7f72003-06-27 21:31:46 +00001818
wdenk4b248f32004-03-14 16:51:43 +00001819 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1820 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001821 video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
1822 logo_red[i], logo_green[i],
1823 logo_blue[i]);
wdenk4b248f32004-03-14 16:51:43 +00001824 }
wdenk8bde7f72003-06-27 21:31:46 +00001825 }
wdenkc6097192002-11-03 00:24:07 +00001826
wdenk4b248f32004-03-14 16:51:43 +00001827 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001828#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1829 int xpos = x;
1830#endif
wdenk4b248f32004-03-14 16:51:43 +00001831 xcount = VIDEO_LOGO_WIDTH;
1832 while (xcount--) {
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001833 if (black) {
1834 r = 0x00;
1835 g = 0x00;
1836 b = 0x00;
1837 } else {
1838 r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1839 g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1840 b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
1841 }
wdenk8bde7f72003-06-27 21:31:46 +00001842
wdenk4b248f32004-03-14 16:51:43 +00001843 switch (VIDEO_DATA_FORMAT) {
1844 case GDF__8BIT_INDEX:
1845 *dest = *source;
1846 break;
1847 case GDF__8BIT_332RGB:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001848 *dest = ((r >> 5) << 5) |
1849 ((g >> 5) << 2) |
1850 (b >> 6);
wdenk4b248f32004-03-14 16:51:43 +00001851 break;
1852 case GDF_15BIT_555RGB:
Andrew Dyercc347802008-08-29 12:30:39 -05001853#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001854 fill_555rgb_pswap(dest, xpos++, r, g, b);
Andrew Dyercc347802008-08-29 12:30:39 -05001855#else
wdenk4b248f32004-03-14 16:51:43 +00001856 *(unsigned short *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001857 SWAP16((unsigned short) (
1858 ((r >> 3) << 10) |
1859 ((g >> 3) << 5) |
1860 (b >> 3)));
Anatolij Gustschinbed53752008-01-11 14:30:01 +01001861#endif
wdenk4b248f32004-03-14 16:51:43 +00001862 break;
1863 case GDF_16BIT_565RGB:
1864 *(unsigned short *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001865 SWAP16((unsigned short) (
1866 ((r >> 3) << 11) |
1867 ((g >> 2) << 5) |
1868 (b >> 3)));
wdenk4b248f32004-03-14 16:51:43 +00001869 break;
1870 case GDF_32BIT_X888RGB:
1871 *(unsigned long *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001872 SWAP32((unsigned long) (
1873 (r << 16) |
1874 (g << 8) |
1875 b));
wdenk4b248f32004-03-14 16:51:43 +00001876 break;
1877 case GDF_24BIT_888RGB:
wdenkc6097192002-11-03 00:24:07 +00001878#ifdef VIDEO_FB_LITTLE_ENDIAN
wdenk4b248f32004-03-14 16:51:43 +00001879 dest[0] = b;
1880 dest[1] = g;
1881 dest[2] = r;
wdenkc6097192002-11-03 00:24:07 +00001882#else
wdenk4b248f32004-03-14 16:51:43 +00001883 dest[0] = r;
1884 dest[1] = g;
1885 dest[2] = b;
wdenkc6097192002-11-03 00:24:07 +00001886#endif
wdenk4b248f32004-03-14 16:51:43 +00001887 break;
1888 }
1889 source++;
1890 dest += VIDEO_PIXEL_SIZE;
1891 }
1892 dest += skip;
wdenk8bde7f72003-06-27 21:31:46 +00001893 }
wdenka6c7ad22002-12-03 21:28:10 +00001894#ifdef CONFIG_VIDEO_BMP_LOGO
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001895 free(logo_red);
1896 free(logo_green);
1897 free(logo_blue);
wdenka6c7ad22002-12-03 21:28:10 +00001898#endif
wdenkc6097192002-11-03 00:24:07 +00001899}
1900
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001901static void *video_logo(void)
wdenkc6097192002-11-03 00:24:07 +00001902{
wdenk4b248f32004-03-14 16:51:43 +00001903 char info[128];
Wolfgang Denka9a62af2011-11-04 15:55:20 +00001904 __maybe_unused int y_off = 0;
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001905 __maybe_unused ulong addr;
1906 __maybe_unused char *s;
Tim Harveyadde4352016-05-24 14:59:59 -07001907 __maybe_unused int len, space;
wdenkc6097192002-11-03 00:24:07 +00001908
Anatolij Gustschinff8fb562013-07-02 00:04:05 +02001909 splash_get_pos(&video_logo_xpos, &video_logo_ypos);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001910
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001911#ifdef CONFIG_SPLASH_SCREEN
1912 s = getenv("splashimage");
1913 if (s != NULL) {
Robert Winklerdd4425e2013-06-17 11:31:29 -07001914 splash_screen_prepare();
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001915 addr = simple_strtoul(s, NULL, 16);
1916
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001917 if (video_display_bitmap(addr,
1918 video_logo_xpos,
1919 video_logo_ypos) == 0) {
Matthias Weisserbe129aa2010-01-12 12:06:31 +01001920 video_logo_height = 0;
wdenk4b248f32004-03-14 16:51:43 +00001921 return ((void *) (video_fb_address));
1922 }
1923 }
1924#endif /* CONFIG_SPLASH_SCREEN */
1925
Hans de Goedec4c9e812015-08-04 12:21:40 +02001926 logo_plot(video_fb_address, video_logo_xpos, video_logo_ypos);
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001927
1928#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1929 /*
1930 * when using splashpos for video_logo, skip any info
1931 * output on video console if the logo is not at 0,0
1932 */
1933 if (video_logo_xpos || video_logo_ypos) {
1934 /*
1935 * video_logo_height is used in text and cursor offset
1936 * calculations. Since the console is below the logo,
1937 * we need to adjust the logo height
1938 */
1939 if (video_logo_ypos == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001940 video_logo_height += max(0, (int)(VIDEO_VISIBLE_ROWS -
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001941 VIDEO_LOGO_HEIGHT) / 2);
1942 else if (video_logo_ypos > 0)
1943 video_logo_height += video_logo_ypos;
1944
1945 return video_fb_address + video_logo_height * VIDEO_LINE_LEN;
1946 }
1947#endif
Heiko Schocher2bc4aa52013-08-03 07:22:53 +02001948 if (board_cfb_skip())
1949 return 0;
wdenk4b248f32004-03-14 16:51:43 +00001950
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001951 sprintf(info, " %s", version_string);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001952
Tim Harveyadde4352016-05-24 14:59:59 -07001953#ifndef CONFIG_HIDE_LOGO_VERSION
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001954 space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1955 len = strlen(info);
1956
1957 if (len > space) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001958 video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1959 (uchar *) info, space);
1960 video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1961 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
1962 (uchar *) info + space, len - space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001963 y_off = 1;
1964 } else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001965 video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
wdenkc6097192002-11-03 00:24:07 +00001966
1967#ifdef CONFIG_CONSOLE_EXTRA_INFO
wdenk4b248f32004-03-14 16:51:43 +00001968 {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001969 int i, n =
1970 ((video_logo_height -
1971 VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00001972
wdenk4b248f32004-03-14 16:51:43 +00001973 for (i = 1; i < n; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001974 video_get_info_str(i, info);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001975 if (!*info)
1976 continue;
1977
1978 len = strlen(info);
1979 if (len > space) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001980 video_drawchars(VIDEO_INFO_X,
1981 VIDEO_INFO_Y +
1982 (i + y_off) *
1983 VIDEO_FONT_HEIGHT,
1984 (uchar *) info, space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001985 y_off++;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001986 video_drawchars(VIDEO_INFO_X +
1987 VIDEO_FONT_WIDTH,
1988 VIDEO_INFO_Y +
1989 (i + y_off) *
1990 VIDEO_FONT_HEIGHT,
1991 (uchar *) info + space,
1992 len - space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001993 } else {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001994 video_drawstring(VIDEO_INFO_X,
1995 VIDEO_INFO_Y +
1996 (i + y_off) *
1997 VIDEO_FONT_HEIGHT,
1998 (uchar *) info);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001999 }
wdenk4b248f32004-03-14 16:51:43 +00002000 }
2001 }
wdenkc6097192002-11-03 00:24:07 +00002002#endif
Tim Harveyadde4352016-05-24 14:59:59 -07002003#endif
wdenkc6097192002-11-03 00:24:07 +00002004
Matthias Weisserbe129aa2010-01-12 12:06:31 +01002005 return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
wdenkc6097192002-11-03 00:24:07 +00002006}
2007#endif
2008
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +02002009static int cfb_fb_is_in_dram(void)
2010{
2011 bd_t *bd = gd->bd;
2012#if defined(CONFIG_ARM) || defined(CONFIG_AVR32) || defined(COFNIG_NDS32) || \
2013defined(CONFIG_SANDBOX) || defined(CONFIG_X86)
2014 ulong start, end;
2015 int i;
2016
2017 for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
2018 start = bd->bi_dram[i].start;
2019 end = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
2020 if ((ulong)video_fb_address >= start &&
2021 (ulong)video_fb_address < end)
2022 return 1;
2023 }
2024#else
2025 if ((ulong)video_fb_address >= bd->bi_memstart &&
2026 (ulong)video_fb_address < bd->bi_memstart + bd->bi_memsize)
2027 return 1;
2028#endif
2029 return 0;
2030}
2031
Heiko Schocher45ae2542013-10-22 11:06:06 +02002032void video_clear(void)
2033{
2034 if (!video_fb_address)
2035 return;
2036#ifdef VIDEO_HW_RECTFILL
2037 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */
2038 0, /* dest pos x */
2039 0, /* dest pos y */
2040 VIDEO_VISIBLE_COLS, /* frame width */
2041 VIDEO_VISIBLE_ROWS, /* frame height */
2042 bgx /* fill color */
2043 );
2044#else
2045 memsetl(video_fb_address,
2046 (VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), bgx);
2047#endif
2048}
2049
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002050static int video_init(void)
wdenkc6097192002-11-03 00:24:07 +00002051{
wdenk4b248f32004-03-14 16:51:43 +00002052 unsigned char color8;
wdenkc6097192002-11-03 00:24:07 +00002053
Wolfgang Denk57912932011-07-30 12:48:09 +00002054 pGD = video_hw_init();
2055 if (pGD == NULL)
wdenk4b248f32004-03-14 16:51:43 +00002056 return -1;
wdenkc6097192002-11-03 00:24:07 +00002057
wdenk4b248f32004-03-14 16:51:43 +00002058 video_fb_address = (void *) VIDEO_FB_ADRS;
wdenkc6097192002-11-03 00:24:07 +00002059#ifdef CONFIG_VIDEO_HW_CURSOR
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002060 video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00002061#endif
2062
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +02002063 cfb_do_flush_cache = cfb_fb_is_in_dram() && dcache_status();
2064
wdenk4b248f32004-03-14 16:51:43 +00002065 /* Init drawing pats */
2066 switch (VIDEO_DATA_FORMAT) {
2067 case GDF__8BIT_INDEX:
Simon Glass002f9672016-10-17 20:12:44 -06002068 video_set_lut(0x01, CONFIG_SYS_CONSOLE_FG_COL,
2069 CONFIG_SYS_CONSOLE_FG_COL,
2070 CONFIG_SYS_CONSOLE_FG_COL);
2071 video_set_lut(0x00, CONFIG_SYS_CONSOLE_BG_COL,
2072 CONFIG_SYS_CONSOLE_BG_COL,
2073 CONFIG_SYS_CONSOLE_BG_COL);
wdenk4b248f32004-03-14 16:51:43 +00002074 fgx = 0x01010101;
2075 bgx = 0x00000000;
2076 break;
2077 case GDF__8BIT_332RGB:
Simon Glass002f9672016-10-17 20:12:44 -06002078 color8 = ((CONFIG_SYS_CONSOLE_FG_COL & 0xe0) |
2079 ((CONFIG_SYS_CONSOLE_FG_COL >> 3) & 0x1c) |
2080 CONFIG_SYS_CONSOLE_FG_COL >> 6);
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002081 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2082 color8;
Simon Glass002f9672016-10-17 20:12:44 -06002083 color8 = ((CONFIG_SYS_CONSOLE_BG_COL & 0xe0) |
2084 ((CONFIG_SYS_CONSOLE_BG_COL >> 3) & 0x1c) |
2085 CONFIG_SYS_CONSOLE_BG_COL >> 6);
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002086 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2087 color8;
wdenk4b248f32004-03-14 16:51:43 +00002088 break;
2089 case GDF_15BIT_555RGB:
Simon Glass002f9672016-10-17 20:12:44 -06002090 fgx = (((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 26) |
2091 ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 21) |
2092 ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 16) |
2093 ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 10) |
2094 ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 5) |
2095 (CONFIG_SYS_CONSOLE_FG_COL >> 3));
2096 bgx = (((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 26) |
2097 ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 21) |
2098 ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 16) |
2099 ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 10) |
2100 ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 5) |
2101 (CONFIG_SYS_CONSOLE_BG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00002102 break;
2103 case GDF_16BIT_565RGB:
Simon Glass002f9672016-10-17 20:12:44 -06002104 fgx = (((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 27) |
2105 ((CONFIG_SYS_CONSOLE_FG_COL >> 2) << 21) |
2106 ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 16) |
2107 ((CONFIG_SYS_CONSOLE_FG_COL >> 3) << 11) |
2108 ((CONFIG_SYS_CONSOLE_FG_COL >> 2) << 5) |
2109 (CONFIG_SYS_CONSOLE_FG_COL >> 3));
2110 bgx = (((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 27) |
2111 ((CONFIG_SYS_CONSOLE_BG_COL >> 2) << 21) |
2112 ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 16) |
2113 ((CONFIG_SYS_CONSOLE_BG_COL >> 3) << 11) |
2114 ((CONFIG_SYS_CONSOLE_BG_COL >> 2) << 5) |
2115 (CONFIG_SYS_CONSOLE_BG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00002116 break;
2117 case GDF_32BIT_X888RGB:
Simon Glass002f9672016-10-17 20:12:44 -06002118 fgx = (CONFIG_SYS_CONSOLE_FG_COL << 16) |
2119 (CONFIG_SYS_CONSOLE_FG_COL << 8) |
2120 CONFIG_SYS_CONSOLE_FG_COL;
2121 bgx = (CONFIG_SYS_CONSOLE_BG_COL << 16) |
2122 (CONFIG_SYS_CONSOLE_BG_COL << 8) |
2123 CONFIG_SYS_CONSOLE_BG_COL;
wdenk4b248f32004-03-14 16:51:43 +00002124 break;
2125 case GDF_24BIT_888RGB:
Simon Glass002f9672016-10-17 20:12:44 -06002126 fgx = (CONFIG_SYS_CONSOLE_FG_COL << 24) |
2127 (CONFIG_SYS_CONSOLE_FG_COL << 16) |
2128 (CONFIG_SYS_CONSOLE_FG_COL << 8) |
2129 CONFIG_SYS_CONSOLE_FG_COL;
2130 bgx = (CONFIG_SYS_CONSOLE_BG_COL << 24) |
2131 (CONFIG_SYS_CONSOLE_BG_COL << 16) |
2132 (CONFIG_SYS_CONSOLE_BG_COL << 8) |
2133 CONFIG_SYS_CONSOLE_BG_COL;
wdenk4b248f32004-03-14 16:51:43 +00002134 break;
2135 }
2136 eorx = fgx ^ bgx;
wdenkc6097192002-11-03 00:24:07 +00002137
Heiko Schocher45ae2542013-10-22 11:06:06 +02002138 video_clear();
2139
wdenkc6097192002-11-03 00:24:07 +00002140#ifdef CONFIG_VIDEO_LOGO
wdenk4b248f32004-03-14 16:51:43 +00002141 /* Plot the logo and get start point of console */
Wolfgang Denk72c65f62011-07-29 09:55:28 +00002142 debug("Video: Drawing the logo ...\n");
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002143 video_console_address = video_logo();
wdenkc6097192002-11-03 00:24:07 +00002144#else
wdenk4b248f32004-03-14 16:51:43 +00002145 video_console_address = video_fb_address;
wdenkc6097192002-11-03 00:24:07 +00002146#endif
2147
wdenk4b248f32004-03-14 16:51:43 +00002148 /* Initialize the console */
2149 console_col = 0;
2150 console_row = 0;
wdenkc6097192002-11-03 00:24:07 +00002151
Eric Nelsondb0d47d2013-05-06 14:27:28 +02002152 if (cfb_do_flush_cache)
2153 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
2154
wdenk4b248f32004-03-14 16:51:43 +00002155 return 0;
wdenkc6097192002-11-03 00:24:07 +00002156}
2157
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002158/*
2159 * Implement a weak default function for boards that optionally
2160 * need to skip the video initialization.
2161 */
Jeroen Hofstee69d27542014-10-08 22:57:30 +02002162__weak int board_video_skip(void)
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002163{
2164 /* As default, don't skip test */
2165 return 0;
2166}
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002167
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002168int drv_video_init(void)
wdenkc6097192002-11-03 00:24:07 +00002169{
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02002170 struct stdio_dev console_dev;
Simon Glass5692ccf2015-03-02 12:40:50 -07002171 bool have_keyboard;
Bin Meng8ceb2422015-08-24 01:00:07 -07002172 bool __maybe_unused keyboard_ok = false;
wdenkc6097192002-11-03 00:24:07 +00002173
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002174 /* Check if video initialization should be skipped */
2175 if (board_video_skip())
2176 return 0;
2177
wdenk81050922004-07-11 20:04:51 +00002178 /* Init video chip - returns with framebuffer cleared */
Bin Meng8ceb2422015-08-24 01:00:07 -07002179 if (video_init() == -1)
2180 return 0;
wdenk81050922004-07-11 20:04:51 +00002181
Heiko Schocher2bc4aa52013-08-03 07:22:53 +02002182 if (board_cfb_skip())
2183 return 0;
2184
Simon Glass5692ccf2015-03-02 12:40:50 -07002185#if defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2186 have_keyboard = false;
2187#elif defined(CONFIG_OF_CONTROL)
2188 have_keyboard = !fdtdec_get_config_bool(gd->fdt_blob,
2189 "u-boot,no-keyboard");
2190#else
2191 have_keyboard = true;
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002192#endif
Simon Glass5692ccf2015-03-02 12:40:50 -07002193 if (have_keyboard) {
2194 debug("KBD: Keyboard init ...\n");
2195#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
Bin Meng8ceb2422015-08-24 01:00:07 -07002196 keyboard_ok = !(VIDEO_KBD_INIT_FCT == -1);
Simon Glass5692ccf2015-03-02 12:40:50 -07002197#endif
2198 }
wdenkc6097192002-11-03 00:24:07 +00002199
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002200 /* Init vga device */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002201 memset(&console_dev, 0, sizeof(console_dev));
2202 strcpy(console_dev.name, "vga");
Bin Meng1caf9342015-11-03 23:23:37 -08002203 console_dev.flags = DEV_FLAGS_OUTPUT;
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002204 console_dev.putc = video_putc; /* 'putc' function */
2205 console_dev.puts = video_puts; /* 'puts' function */
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002206
2207#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
Bin Meng8ceb2422015-08-24 01:00:07 -07002208 if (have_keyboard && keyboard_ok) {
Simon Glass5692ccf2015-03-02 12:40:50 -07002209 /* Also init console device */
2210 console_dev.flags |= DEV_FLAGS_INPUT;
2211 console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */
2212 console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */
2213 }
2214#endif
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002215
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002216 if (stdio_register(&console_dev) != 0)
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002217 return 0;
2218
2219 /* Return success */
2220 return 1;
wdenkc6097192002-11-03 00:24:07 +00002221}
Stefan Reinauerc20ee072012-09-28 15:11:12 +00002222
2223void video_position_cursor(unsigned col, unsigned row)
2224{
2225 console_col = min(col, CONSOLE_COLS - 1);
2226 console_row = min(row, CONSOLE_ROWS - 1);
2227}
2228
2229int video_get_pixel_width(void)
2230{
2231 return VIDEO_VISIBLE_COLS;
2232}
2233
2234int video_get_pixel_height(void)
2235{
2236 return VIDEO_VISIBLE_ROWS;
2237}
2238
2239int video_get_screen_rows(void)
2240{
2241 return CONSOLE_ROWS;
2242}
2243
2244int video_get_screen_columns(void)
2245{
2246 return CONSOLE_COLS;
2247}