blob: f1913922e59a34c6a40fc532d266b63f9066c1fa [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 *
18 * The console driver can use the standard PC keyboard interface (i8042)
19 * for character input. Character output goes to a memory mapped video
20 * framebuffer with little or big-endian organisation.
21 * With environment setting 'console=serial' the console i/o can be
22 * forced to serial port.
Wolfgang Denk64e40d72011-07-29 09:55:27 +000023 *
24 * The driver uses graphic specific defines/parameters/functions:
25 *
26 * (for SMI LynxE graphic chip)
27 *
28 * CONFIG_VIDEO_SMI_LYNXEM - use graphic driver for SMI 710,712,810
29 * VIDEO_FB_LITTLE_ENDIAN - framebuffer organisation default: big endian
30 * VIDEO_HW_RECTFILL - graphic driver supports hardware rectangle fill
31 * VIDEO_HW_BITBLT - graphic driver supports hardware bit blt
32 *
33 * Console Parameters are set by graphic drivers global struct:
34 *
35 * VIDEO_VISIBLE_COLS - x resolution
36 * VIDEO_VISIBLE_ROWS - y resolution
37 * VIDEO_PIXEL_SIZE - storage size in byte per pixel
38 * VIDEO_DATA_FORMAT - graphical data format GDF
39 * VIDEO_FB_ADRS - start of video memory
40 *
41 * CONFIG_I8042_KBD - AT Keyboard driver for i8042
42 * 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.
61 * CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be
62 * initialized as an output only device.
63 * The Keyboard driver will not be
64 * set-up. This may be used, if you have
65 * no or more than one Keyboard devices
66 * (USB Keyboard, AT Keyboard).
67 *
68 * CONFIG_VIDEO_SW_CURSOR: - Draws a cursor after the last
69 * character. No blinking is provided.
70 * Uses the macros CURSOR_SET and
71 * CURSOR_OFF.
72 *
73 * CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability
74 * of the graphic chip. Uses the macro
75 * CURSOR_SET. ATTENTION: If booting an
76 * OS, the display driver must disable
77 * the hardware register of the graphic
78 * chip. Otherwise a blinking field is
79 * displayed.
80 */
wdenkc6097192002-11-03 00:24:07 +000081
82#include <common.h>
Simon Glass5692ccf2015-03-02 12:40:50 -070083#include <fdtdec.h>
Andreas Bießmann09c2e902011-07-18 20:24:04 +020084#include <version.h>
wdenka6c7ad22002-12-03 21:28:10 +000085#include <malloc.h>
Wolfgang Denka9a62af2011-11-04 15:55:20 +000086#include <linux/compiler.h>
wdenka6c7ad22002-12-03 21:28:10 +000087
Wolfgang Denk64e40d72011-07-29 09:55:27 +000088/*
89 * Console device defines with SMI graphic
90 * Any other graphic must change this section
91 */
wdenkc6097192002-11-03 00:24:07 +000092
wdenk4b248f32004-03-14 16:51:43 +000093#ifdef CONFIG_VIDEO_SMI_LYNXEM
wdenkc6097192002-11-03 00:24:07 +000094
95#define VIDEO_FB_LITTLE_ENDIAN
96#define VIDEO_HW_RECTFILL
97#define VIDEO_HW_BITBLT
98#endif
99
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000100/*
101 * Defines for the CT69000 driver
102 */
wdenk4b248f32004-03-14 16:51:43 +0000103#ifdef CONFIG_VIDEO_CT69000
wdenkc6097192002-11-03 00:24:07 +0000104
105#define VIDEO_FB_LITTLE_ENDIAN
106#define VIDEO_HW_RECTFILL
107#define VIDEO_HW_BITBLT
108#endif
109
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000110/*
111 * Defines for the SED13806 driver
112 */
wdenka6c7ad22002-12-03 21:28:10 +0000113#ifdef CONFIG_VIDEO_SED13806
wdenka6c7ad22002-12-03 21:28:10 +0000114#define VIDEO_FB_LITTLE_ENDIAN
115#define VIDEO_HW_RECTFILL
116#define VIDEO_HW_BITBLT
117#endif
118
Marek Vasutfb8ddc22013-04-28 09:20:03 +0000119#ifdef CONFIG_VIDEO_MXS
120#define VIDEO_FB_16BPP_WORD_SWAP
121#endif
122
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000123/*
124 * Defines for the MB862xx driver
125 */
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100126#ifdef CONFIG_VIDEO_MB862xx
127
128#ifdef CONFIG_VIDEO_CORALP
129#define VIDEO_FB_LITTLE_ENDIAN
130#endif
Anatolij Gustschin5d16ca82009-10-23 12:03:14 +0200131#ifdef CONFIG_VIDEO_MB862xx_ACCEL
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100132#define VIDEO_HW_RECTFILL
133#define VIDEO_HW_BITBLT
134#endif
Anatolij Gustschin5d16ca82009-10-23 12:03:14 +0200135#endif
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100136
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000137/*
Helmut Raiger62a22dc2011-10-12 23:16:29 +0000138 * Defines for the i.MX31 driver (mx3fb.c)
139 */
Fabio Estevam695af9a2012-05-31 07:23:56 +0000140#if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3)
Helmut Raiger62a22dc2011-10-12 23:16:29 +0000141#define VIDEO_FB_16BPP_WORD_SWAP
142#endif
143
144/*
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000145 * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
146 */
wdenkc6097192002-11-03 00:24:07 +0000147#include <video_fb.h>
148
Robert Winklerdd4425e2013-06-17 11:31:29 -0700149#include <splash.h>
150
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000151/*
152 * some Macros
153 */
wdenk4b248f32004-03-14 16:51:43 +0000154#define VIDEO_VISIBLE_COLS (pGD->winSizeX)
155#define VIDEO_VISIBLE_ROWS (pGD->winSizeY)
156#define VIDEO_PIXEL_SIZE (pGD->gdfBytesPP)
157#define VIDEO_DATA_FORMAT (pGD->gdfIndex)
158#define VIDEO_FB_ADRS (pGD->frameAdrs)
wdenkc6097192002-11-03 00:24:07 +0000159
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000160/*
161 * Console device defines with i8042 keyboard controller
162 * Any other keyboard controller must change this section
163 */
wdenkc6097192002-11-03 00:24:07 +0000164
wdenk4b248f32004-03-14 16:51:43 +0000165#ifdef CONFIG_I8042_KBD
wdenkc6097192002-11-03 00:24:07 +0000166#include <i8042.h>
167
wdenk4b248f32004-03-14 16:51:43 +0000168#define VIDEO_KBD_INIT_FCT i8042_kbd_init()
169#define VIDEO_TSTC_FCT i8042_tstc
170#define VIDEO_GETC_FCT i8042_getc
wdenkc6097192002-11-03 00:24:07 +0000171#endif
172
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000173/*
174 * Console device
175 */
wdenkc6097192002-11-03 00:24:07 +0000176
177#include <version.h>
178#include <linux/types.h>
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200179#include <stdio_dev.h>
wdenkc6097192002-11-03 00:24:07 +0000180#include <video_font.h>
wdenkc6097192002-11-03 00:24:07 +0000181
Jon Loeligerddb5d86f2007-07-10 11:13:21 -0500182#if defined(CONFIG_CMD_DATE)
183#include <rtc.h>
wdenkc6097192002-11-03 00:24:07 +0000184#endif
185
Jon Loeliger07d38a12007-07-09 17:30:01 -0500186#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenk4b248f32004-03-14 16:51:43 +0000187#include <watchdog.h>
188#include <bmp_layout.h>
Anatolij Gustschinff8fb562013-07-02 00:04:05 +0200189#include <splash.h>
Jon Loeliger07d38a12007-07-09 17:30:01 -0500190#endif
wdenk4b248f32004-03-14 16:51:43 +0000191
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000192/*
193 * Cursor definition:
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000194 * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No
195 * blinking is provided. Uses the macros CURSOR_SET
196 * and CURSOR_OFF.
197 * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the
198 * graphic chip. Uses the macro CURSOR_SET.
199 * ATTENTION: If booting an OS, the display driver
200 * must disable the hardware register of the graphic
201 * chip. Otherwise a blinking field is displayed
202 */
Simon Glass7fe09332015-10-18 21:17:18 -0600203#if !defined(CONFIG_VIDEO_SW_CURSOR) && !defined(CONFIG_VIDEO_HW_CURSOR)
wdenkc6097192002-11-03 00:24:07 +0000204/* no Cursor defined */
205#define CURSOR_ON
206#define CURSOR_OFF
207#define CURSOR_SET
208#endif
209
Simon Glass7fe09332015-10-18 21:17:18 -0600210#if defined(CONFIG_VIDEO_SW_CURSOR)
211#if defined(CONFIG_VIDEO_HW_CURSOR)
212#error only one of CONFIG_VIDEO_SW_CURSOR or CONFIG_VIDEO_HW_CURSOR can be \
213 defined
wdenkc6097192002-11-03 00:24:07 +0000214#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000215void console_cursor(int state);
216
Timur Tabi65618632010-08-27 15:45:47 -0500217#define CURSOR_ON console_cursor(1)
218#define CURSOR_OFF console_cursor(0)
Gabe Black03d31fc2011-11-30 13:50:50 +0000219#define CURSOR_SET video_set_cursor()
Simon Glass7fe09332015-10-18 21:17:18 -0600220#endif /* CONFIG_VIDEO_SW_CURSOR */
wdenkc6097192002-11-03 00:24:07 +0000221
222#ifdef CONFIG_VIDEO_HW_CURSOR
wdenk4b248f32004-03-14 16:51:43 +0000223#ifdef CURSOR_ON
Simon Glass7fe09332015-10-18 21:17:18 -0600224#error only one of CONFIG_VIDEO_SW_CURSOR or CONFIG_VIDEO_HW_CURSOR can be \
225 defined
wdenkc6097192002-11-03 00:24:07 +0000226#endif
227#define CURSOR_ON
228#define CURSOR_OFF
229#define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \
Timur Tabi65618632010-08-27 15:45:47 -0500230 (console_row * VIDEO_FONT_HEIGHT) + video_logo_height)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000231#endif /* CONFIG_VIDEO_HW_CURSOR */
wdenkc6097192002-11-03 00:24:07 +0000232
wdenk4b248f32004-03-14 16:51:43 +0000233#ifdef CONFIG_VIDEO_LOGO
234#ifdef CONFIG_VIDEO_BMP_LOGO
wdenka6c7ad22002-12-03 21:28:10 +0000235#include <bmp_logo.h>
Che-Liang Chiouc2707302011-10-20 23:04:20 +0000236#include <bmp_logo_data.h>
wdenk4b248f32004-03-14 16:51:43 +0000237#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH
238#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT
239#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET
240#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS
wdenka6c7ad22002-12-03 21:28:10 +0000241
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000242#else /* CONFIG_VIDEO_BMP_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000243#define LINUX_LOGO_WIDTH 80
244#define LINUX_LOGO_HEIGHT 80
245#define LINUX_LOGO_COLORS 214
246#define LINUX_LOGO_LUT_OFFSET 0x20
wdenkc6097192002-11-03 00:24:07 +0000247#define __initdata
248#include <linux_logo.h>
wdenk4b248f32004-03-14 16:51:43 +0000249#define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH
250#define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT
251#define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET
252#define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000253#endif /* CONFIG_VIDEO_BMP_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000254#define VIDEO_INFO_X (VIDEO_LOGO_WIDTH)
255#define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000256#else /* CONFIG_VIDEO_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000257#define VIDEO_LOGO_WIDTH 0
258#define VIDEO_LOGO_HEIGHT 0
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000259#endif /* CONFIG_VIDEO_LOGO */
wdenkc6097192002-11-03 00:24:07 +0000260
wdenk4b248f32004-03-14 16:51:43 +0000261#define VIDEO_COLS VIDEO_VISIBLE_COLS
262#define VIDEO_ROWS VIDEO_VISIBLE_ROWS
Hans de Goedec67a8762015-08-04 12:15:39 +0200263#ifndef VIDEO_LINE_LEN
264#define VIDEO_LINE_LEN (VIDEO_COLS * VIDEO_PIXEL_SIZE)
265#endif
266#define VIDEO_SIZE (VIDEO_ROWS * VIDEO_LINE_LEN)
wdenk4b248f32004-03-14 16:51:43 +0000267#define VIDEO_BURST_LEN (VIDEO_COLS/8)
wdenkc6097192002-11-03 00:24:07 +0000268
wdenk4b248f32004-03-14 16:51:43 +0000269#ifdef CONFIG_VIDEO_LOGO
Matthias Weisserbe129aa2010-01-12 12:06:31 +0100270#define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000271#else
wdenk4b248f32004-03-14 16:51:43 +0000272#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000273#endif
274
wdenk4b248f32004-03-14 16:51:43 +0000275#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH)
276#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
277#define CONSOLE_ROW_FIRST (video_console_address)
278#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE)
279#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
280#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
Simon Glass3c0b6682015-01-01 16:17:57 -0700281
282/* By default we scroll by a single line */
283#ifndef CONFIG_CONSOLE_SCROLL_LINES
284#define CONFIG_CONSOLE_SCROLL_LINES 1
285#endif
wdenkc6097192002-11-03 00:24:07 +0000286
287/* Macros */
wdenk4b248f32004-03-14 16:51:43 +0000288#ifdef VIDEO_FB_LITTLE_ENDIAN
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000289#define SWAP16(x) ((((x) & 0x00ff) << 8) | \
290 ((x) >> 8) \
291 )
292#define SWAP32(x) ((((x) & 0x000000ff) << 24) | \
293 (((x) & 0x0000ff00) << 8) | \
294 (((x) & 0x00ff0000) >> 8) | \
295 (((x) & 0xff000000) >> 24) \
296 )
297#define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | \
298 (((x) & 0x0000ff00) >> 8) | \
299 (((x) & 0x00ff0000) << 8) | \
300 (((x) & 0xff000000) >> 8) \
301 )
wdenkc6097192002-11-03 00:24:07 +0000302#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000303#define SWAP16(x) (x)
304#define SWAP32(x) (x)
Wolfgang Grandegger229b6dc2009-10-23 12:03:15 +0200305#if defined(VIDEO_FB_16BPP_WORD_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000306#define SHORTSWAP32(x) (((x) >> 16) | ((x) << 16))
Andrew Dyercc347802008-08-29 12:30:39 -0500307#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000308#define SHORTSWAP32(x) (x)
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100309#endif
wdenkc6097192002-11-03 00:24:07 +0000310#endif
311
wdenkc6097192002-11-03 00:24:07 +0000312#ifdef CONFIG_CONSOLE_EXTRA_INFO
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000313/*
314 * setup a board string: type, speed, etc.
315 *
316 * line_number: location to place info string beside logo
317 * info: buffer for info string
318 */
319extern void video_get_info_str(int line_number, char *info);
wdenkc6097192002-11-03 00:24:07 +0000320#endif
321
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +0200322DECLARE_GLOBAL_DATA_PTR;
323
wdenkc6097192002-11-03 00:24:07 +0000324/* Locals */
325static GraphicDevice *pGD; /* Pointer to Graphic array */
326
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000327static void *video_fb_address; /* frame buffer address */
wdenk4b248f32004-03-14 16:51:43 +0000328static void *video_console_address; /* console buffer start address */
wdenkc6097192002-11-03 00:24:07 +0000329
Matthias Weisserbe129aa2010-01-12 12:06:31 +0100330static int video_logo_height = VIDEO_LOGO_HEIGHT;
331
Anatolij Gustschina45adde2011-12-07 03:58:10 +0000332static int __maybe_unused cursor_state;
333static int __maybe_unused old_col;
334static int __maybe_unused old_row;
Gabe Black03d31fc2011-11-30 13:50:50 +0000335
Wolfgang Denk57912932011-07-30 12:48:09 +0000336static int console_col; /* cursor col */
337static int console_row; /* cursor row */
wdenkc6097192002-11-03 00:24:07 +0000338
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000339static u32 eorx, fgx, bgx; /* color pats */
wdenkc6097192002-11-03 00:24:07 +0000340
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +0200341static int cfb_do_flush_cache;
342
Pali Rohár33a35bb2012-10-19 13:30:09 +0000343#ifdef CONFIG_CFB_CONSOLE_ANSI
344static char ansi_buf[10];
345static int ansi_buf_size;
346static int ansi_colors_need_revert;
347static int ansi_cursor_hidden;
348#endif
349
wdenkc6097192002-11-03 00:24:07 +0000350static const int video_font_draw_table8[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000351 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
352 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
353 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
354 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
355};
wdenkc6097192002-11-03 00:24:07 +0000356
357static const int video_font_draw_table15[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000358 0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff
359};
wdenkc6097192002-11-03 00:24:07 +0000360
361static const int video_font_draw_table16[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000362 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
363};
wdenkc6097192002-11-03 00:24:07 +0000364
365static const int video_font_draw_table24[16][3] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000366 {0x00000000, 0x00000000, 0x00000000},
367 {0x00000000, 0x00000000, 0x00ffffff},
368 {0x00000000, 0x0000ffff, 0xff000000},
369 {0x00000000, 0x0000ffff, 0xffffffff},
370 {0x000000ff, 0xffff0000, 0x00000000},
371 {0x000000ff, 0xffff0000, 0x00ffffff},
372 {0x000000ff, 0xffffffff, 0xff000000},
373 {0x000000ff, 0xffffffff, 0xffffffff},
374 {0xffffff00, 0x00000000, 0x00000000},
375 {0xffffff00, 0x00000000, 0x00ffffff},
376 {0xffffff00, 0x0000ffff, 0xff000000},
377 {0xffffff00, 0x0000ffff, 0xffffffff},
378 {0xffffffff, 0xffff0000, 0x00000000},
379 {0xffffffff, 0xffff0000, 0x00ffffff},
380 {0xffffffff, 0xffffffff, 0xff000000},
381 {0xffffffff, 0xffffffff, 0xffffffff}
382};
wdenkc6097192002-11-03 00:24:07 +0000383
384static const int video_font_draw_table32[16][4] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000385 {0x00000000, 0x00000000, 0x00000000, 0x00000000},
386 {0x00000000, 0x00000000, 0x00000000, 0x00ffffff},
387 {0x00000000, 0x00000000, 0x00ffffff, 0x00000000},
388 {0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff},
389 {0x00000000, 0x00ffffff, 0x00000000, 0x00000000},
390 {0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff},
391 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000},
392 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff},
393 {0x00ffffff, 0x00000000, 0x00000000, 0x00000000},
394 {0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff},
395 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000},
396 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff},
397 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000},
398 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff},
399 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000},
400 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff}
401};
wdenkc6097192002-11-03 00:24:07 +0000402
Heiko Schocher2bc4aa52013-08-03 07:22:53 +0200403/*
404 * Implement a weak default function for boards that optionally
405 * need to skip the cfb initialization.
406 */
407__weak int board_cfb_skip(void)
408{
409 /* As default, don't skip cfb init */
410 return 0;
411}
412
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000413static void video_drawchars(int xx, int yy, unsigned char *s, int count)
wdenkc6097192002-11-03 00:24:07 +0000414{
wdenk4b248f32004-03-14 16:51:43 +0000415 u8 *cdat, *dest, *dest0;
416 int rows, offset, c;
wdenkc6097192002-11-03 00:24:07 +0000417
wdenk4b248f32004-03-14 16:51:43 +0000418 offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
419 dest0 = video_fb_address + offset;
wdenkc6097192002-11-03 00:24:07 +0000420
wdenk4b248f32004-03-14 16:51:43 +0000421 switch (VIDEO_DATA_FORMAT) {
422 case GDF__8BIT_INDEX:
423 case GDF__8BIT_332RGB:
424 while (count--) {
425 c = *s;
426 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
427 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000428 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000429 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000430
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000431 ((u32 *) dest)[0] =
432 (video_font_draw_table8[bits >> 4] &
433 eorx) ^ bgx;
Marek Vasutfd8cf992013-07-30 23:37:59 +0200434
435 if (VIDEO_FONT_WIDTH == 4)
436 continue;
437
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000438 ((u32 *) dest)[1] =
439 (video_font_draw_table8[bits & 15] &
440 eorx) ^ bgx;
wdenk4b248f32004-03-14 16:51:43 +0000441 }
442 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
443 s++;
444 }
445 break;
wdenkc6097192002-11-03 00:24:07 +0000446
wdenk4b248f32004-03-14 16:51:43 +0000447 case GDF_15BIT_555RGB:
448 while (count--) {
449 c = *s;
450 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
451 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000452 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000453 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000454
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000455 ((u32 *) dest)[0] =
456 SHORTSWAP32((video_font_draw_table15
457 [bits >> 6] & eorx) ^
458 bgx);
459 ((u32 *) dest)[1] =
460 SHORTSWAP32((video_font_draw_table15
461 [bits >> 4 & 3] & eorx) ^
462 bgx);
Marek Vasutfd8cf992013-07-30 23:37:59 +0200463
464 if (VIDEO_FONT_WIDTH == 4)
465 continue;
466
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000467 ((u32 *) dest)[2] =
468 SHORTSWAP32((video_font_draw_table15
469 [bits >> 2 & 3] & eorx) ^
470 bgx);
471 ((u32 *) dest)[3] =
472 SHORTSWAP32((video_font_draw_table15
473 [bits & 3] & eorx) ^
474 bgx);
wdenk4b248f32004-03-14 16:51:43 +0000475 }
476 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
477 s++;
478 }
479 break;
wdenkc6097192002-11-03 00:24:07 +0000480
wdenk4b248f32004-03-14 16:51:43 +0000481 case GDF_16BIT_565RGB:
482 while (count--) {
483 c = *s;
484 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
485 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000486 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000487 u8 bits = *cdat++;
488
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000489 ((u32 *) dest)[0] =
490 SHORTSWAP32((video_font_draw_table16
491 [bits >> 6] & eorx) ^
492 bgx);
493 ((u32 *) dest)[1] =
494 SHORTSWAP32((video_font_draw_table16
495 [bits >> 4 & 3] & eorx) ^
496 bgx);
Marek Vasutfd8cf992013-07-30 23:37:59 +0200497
498 if (VIDEO_FONT_WIDTH == 4)
499 continue;
500
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000501 ((u32 *) dest)[2] =
502 SHORTSWAP32((video_font_draw_table16
503 [bits >> 2 & 3] & eorx) ^
504 bgx);
505 ((u32 *) dest)[3] =
506 SHORTSWAP32((video_font_draw_table16
507 [bits & 3] & eorx) ^
508 bgx);
wdenk4b248f32004-03-14 16:51:43 +0000509 }
510 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
511 s++;
512 }
513 break;
514
515 case GDF_32BIT_X888RGB:
516 while (count--) {
517 c = *s;
518 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
519 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000520 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000521 u8 bits = *cdat++;
522
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000523 ((u32 *) dest)[0] =
524 SWAP32((video_font_draw_table32
525 [bits >> 4][0] & eorx) ^ bgx);
526 ((u32 *) dest)[1] =
527 SWAP32((video_font_draw_table32
528 [bits >> 4][1] & eorx) ^ bgx);
529 ((u32 *) dest)[2] =
530 SWAP32((video_font_draw_table32
531 [bits >> 4][2] & eorx) ^ bgx);
532 ((u32 *) dest)[3] =
533 SWAP32((video_font_draw_table32
534 [bits >> 4][3] & eorx) ^ bgx);
Marek Vasutfd8cf992013-07-30 23:37:59 +0200535
536
537 if (VIDEO_FONT_WIDTH == 4)
538 continue;
539
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000540 ((u32 *) dest)[4] =
541 SWAP32((video_font_draw_table32
542 [bits & 15][0] & eorx) ^ bgx);
543 ((u32 *) dest)[5] =
544 SWAP32((video_font_draw_table32
545 [bits & 15][1] & eorx) ^ bgx);
546 ((u32 *) dest)[6] =
547 SWAP32((video_font_draw_table32
548 [bits & 15][2] & eorx) ^ bgx);
549 ((u32 *) dest)[7] =
550 SWAP32((video_font_draw_table32
551 [bits & 15][3] & eorx) ^ bgx);
wdenk4b248f32004-03-14 16:51:43 +0000552 }
553 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
554 s++;
555 }
556 break;
557
558 case GDF_24BIT_888RGB:
559 while (count--) {
560 c = *s;
561 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
562 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000563 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000564 u8 bits = *cdat++;
565
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000566 ((u32 *) dest)[0] =
567 (video_font_draw_table24[bits >> 4][0]
568 & eorx) ^ bgx;
569 ((u32 *) dest)[1] =
570 (video_font_draw_table24[bits >> 4][1]
571 & eorx) ^ bgx;
572 ((u32 *) dest)[2] =
573 (video_font_draw_table24[bits >> 4][2]
574 & eorx) ^ bgx;
Marek Vasutfd8cf992013-07-30 23:37:59 +0200575
576 if (VIDEO_FONT_WIDTH == 4)
577 continue;
578
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000579 ((u32 *) dest)[3] =
580 (video_font_draw_table24[bits & 15][0]
581 & eorx) ^ bgx;
582 ((u32 *) dest)[4] =
583 (video_font_draw_table24[bits & 15][1]
584 & eorx) ^ bgx;
585 ((u32 *) dest)[5] =
586 (video_font_draw_table24[bits & 15][2]
587 & eorx) ^ bgx;
wdenk4b248f32004-03-14 16:51:43 +0000588 }
589 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
590 s++;
591 }
592 break;
wdenk8bde7f72003-06-27 21:31:46 +0000593 }
wdenkc6097192002-11-03 00:24:07 +0000594}
595
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000596static inline void video_drawstring(int xx, int yy, unsigned char *s)
wdenkc6097192002-11-03 00:24:07 +0000597{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000598 video_drawchars(xx, yy, s, strlen((char *) s));
wdenkc6097192002-11-03 00:24:07 +0000599}
600
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000601static void video_putchar(int xx, int yy, unsigned char c)
wdenkc6097192002-11-03 00:24:07 +0000602{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000603 video_drawchars(xx, yy + video_logo_height, &c, 1);
wdenkc6097192002-11-03 00:24:07 +0000604}
605
Simon Glass7fe09332015-10-18 21:17:18 -0600606#if defined(CONFIG_VIDEO_SW_CURSOR)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000607static void video_set_cursor(void)
wdenkc6097192002-11-03 00:24:07 +0000608{
Gabe Black03d31fc2011-11-30 13:50:50 +0000609 if (cursor_state)
610 console_cursor(0);
611 console_cursor(1);
wdenkc6097192002-11-03 00:24:07 +0000612}
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000613
Anatolij Gustschina45adde2011-12-07 03:58:10 +0000614static void video_invertchar(int xx, int yy)
615{
616 int firstx = xx * VIDEO_PIXEL_SIZE;
617 int lastx = (xx + VIDEO_FONT_WIDTH) * VIDEO_PIXEL_SIZE;
618 int firsty = yy * VIDEO_LINE_LEN;
619 int lasty = (yy + VIDEO_FONT_HEIGHT) * VIDEO_LINE_LEN;
620 int x, y;
621 for (y = firsty; y < lasty; y += VIDEO_LINE_LEN) {
622 for (x = firstx; x < lastx; x++) {
623 u8 *dest = (u8 *)(video_fb_address) + x + y;
624 *dest = ~*dest;
625 }
626 }
627}
Gabe Black03d31fc2011-11-30 13:50:50 +0000628
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000629void console_cursor(int state)
wdenkc6097192002-11-03 00:24:07 +0000630{
Gabe Black03d31fc2011-11-30 13:50:50 +0000631 if (cursor_state != state) {
632 if (cursor_state) {
633 /* turn off the cursor */
634 video_invertchar(old_col * VIDEO_FONT_WIDTH,
635 old_row * VIDEO_FONT_HEIGHT +
636 video_logo_height);
637 } else {
638 /* turn off the cursor and record where it is */
639 video_invertchar(console_col * VIDEO_FONT_WIDTH,
640 console_row * VIDEO_FONT_HEIGHT +
641 video_logo_height);
642 old_col = console_col;
643 old_row = console_row;
644 }
645 cursor_state = state;
wdenk4b248f32004-03-14 16:51:43 +0000646 }
Eric Nelsondb0d47d2013-05-06 14:27:28 +0200647 if (cfb_do_flush_cache)
648 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
wdenkc6097192002-11-03 00:24:07 +0000649}
650#endif
651
wdenkc6097192002-11-03 00:24:07 +0000652#ifndef VIDEO_HW_RECTFILL
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000653static void memsetl(int *p, int c, int v)
wdenkc6097192002-11-03 00:24:07 +0000654{
wdenk4b248f32004-03-14 16:51:43 +0000655 while (c--)
656 *(p++) = v;
wdenkc6097192002-11-03 00:24:07 +0000657}
658#endif
659
wdenkc6097192002-11-03 00:24:07 +0000660#ifndef VIDEO_HW_BITBLT
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000661static void memcpyl(int *d, int *s, int c)
wdenkc6097192002-11-03 00:24:07 +0000662{
wdenk4b248f32004-03-14 16:51:43 +0000663 while (c--)
664 *(d++) = *(s++);
wdenkc6097192002-11-03 00:24:07 +0000665}
666#endif
667
Pali Rohár90f60a82012-04-28 07:26:44 +0000668static void console_clear_line(int line, int begin, int end)
669{
670#ifdef VIDEO_HW_RECTFILL
671 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */
672 VIDEO_FONT_WIDTH * begin, /* dest pos x */
673 video_logo_height +
674 VIDEO_FONT_HEIGHT * line, /* dest pos y */
675 VIDEO_FONT_WIDTH * (end - begin + 1), /* fr. width */
676 VIDEO_FONT_HEIGHT, /* frame height */
677 bgx /* fill color */
678 );
679#else
680 if (begin == 0 && (end + 1) == CONSOLE_COLS) {
681 memsetl(CONSOLE_ROW_FIRST +
682 CONSOLE_ROW_SIZE * line, /* offset of row */
683 CONSOLE_ROW_SIZE >> 2, /* length of row */
684 bgx /* fill color */
685 );
686 } else {
687 void *offset;
688 int i, size;
689
690 offset = CONSOLE_ROW_FIRST +
691 CONSOLE_ROW_SIZE * line + /* offset of row */
692 VIDEO_FONT_WIDTH *
693 VIDEO_PIXEL_SIZE * begin; /* offset of col */
694 size = VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE * (end - begin + 1);
695 size >>= 2; /* length to end for memsetl() */
696 /* fill at col offset of i'th line using bgx as fill color */
697 for (i = 0; i < VIDEO_FONT_HEIGHT; i++)
698 memsetl(offset + i * VIDEO_LINE_LEN, size, bgx);
699 }
700#endif
701}
702
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000703static void console_scrollup(void)
wdenkc6097192002-11-03 00:24:07 +0000704{
Simon Glass3c0b6682015-01-01 16:17:57 -0700705 const int rows = CONFIG_CONSOLE_SCROLL_LINES;
706 int i;
707
wdenk4b248f32004-03-14 16:51:43 +0000708 /* copy up rows ignoring the first one */
wdenkc6097192002-11-03 00:24:07 +0000709
710#ifdef VIDEO_HW_BITBLT
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000711 video_hw_bitblt(VIDEO_PIXEL_SIZE, /* bytes per pixel */
712 0, /* source pos x */
713 video_logo_height +
Simon Glass3c0b6682015-01-01 16:17:57 -0700714 VIDEO_FONT_HEIGHT * rows, /* source pos y */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000715 0, /* dest pos x */
716 video_logo_height, /* dest pos y */
717 VIDEO_VISIBLE_COLS, /* frame width */
718 VIDEO_VISIBLE_ROWS
719 - video_logo_height
Simon Glass3c0b6682015-01-01 16:17:57 -0700720 - VIDEO_FONT_HEIGHT * rows /* frame height */
wdenk4b248f32004-03-14 16:51:43 +0000721 );
wdenkc6097192002-11-03 00:24:07 +0000722#else
Simon Glass3c0b6682015-01-01 16:17:57 -0700723 memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_FIRST + rows * CONSOLE_ROW_SIZE,
724 (CONSOLE_SIZE - CONSOLE_ROW_SIZE * rows) >> 2);
wdenkc6097192002-11-03 00:24:07 +0000725#endif
wdenk4b248f32004-03-14 16:51:43 +0000726 /* clear the last one */
Simon Glass3c0b6682015-01-01 16:17:57 -0700727 for (i = 1; i <= rows; i++)
728 console_clear_line(CONSOLE_ROWS - i, 0, CONSOLE_COLS - 1);
729
730 /* Decrement row number */
731 console_row -= rows;
wdenkc6097192002-11-03 00:24:07 +0000732}
733
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000734static void console_back(void)
wdenkc6097192002-11-03 00:24:07 +0000735{
Timur Tabi65618632010-08-27 15:45:47 -0500736 console_col--;
wdenkc6097192002-11-03 00:24:07 +0000737
wdenk4b248f32004-03-14 16:51:43 +0000738 if (console_col < 0) {
739 console_col = CONSOLE_COLS - 1;
740 console_row--;
741 if (console_row < 0)
742 console_row = 0;
743 }
wdenkc6097192002-11-03 00:24:07 +0000744}
745
Pali Rohár33a35bb2012-10-19 13:30:09 +0000746#ifdef CONFIG_CFB_CONSOLE_ANSI
747
748static void console_clear(void)
wdenkc6097192002-11-03 00:24:07 +0000749{
Pali Rohár33a35bb2012-10-19 13:30:09 +0000750#ifdef VIDEO_HW_RECTFILL
751 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */
752 0, /* dest pos x */
753 video_logo_height, /* dest pos y */
754 VIDEO_VISIBLE_COLS, /* frame width */
755 VIDEO_VISIBLE_ROWS, /* frame height */
756 bgx /* fill color */
757 );
758#else
759 memsetl(CONSOLE_ROW_FIRST, CONSOLE_SIZE, bgx);
760#endif
761}
762
763static void console_cursor_fix(void)
764{
765 if (console_row < 0)
766 console_row = 0;
767 if (console_row >= CONSOLE_ROWS)
768 console_row = CONSOLE_ROWS - 1;
769 if (console_col < 0)
770 console_col = 0;
771 if (console_col >= CONSOLE_COLS)
772 console_col = CONSOLE_COLS - 1;
773}
774
775static void console_cursor_up(int n)
776{
777 console_row -= n;
778 console_cursor_fix();
779}
780
781static void console_cursor_down(int n)
782{
783 console_row += n;
784 console_cursor_fix();
785}
786
787static void console_cursor_left(int n)
788{
789 console_col -= n;
790 console_cursor_fix();
791}
792
793static void console_cursor_right(int n)
794{
795 console_col += n;
796 console_cursor_fix();
797}
798
799static void console_cursor_set_position(int row, int col)
800{
801 if (console_row != -1)
802 console_row = row;
803 if (console_col != -1)
804 console_col = col;
805 console_cursor_fix();
806}
807
808static void console_previousline(int n)
809{
810 /* FIXME: also scroll terminal ? */
811 console_row -= n;
812 console_cursor_fix();
813}
814
815static void console_swap_colors(void)
816{
817 eorx = fgx;
818 fgx = bgx;
819 bgx = eorx;
820 eorx = fgx ^ bgx;
821}
822
823static inline int console_cursor_is_visible(void)
824{
825 return !ansi_cursor_hidden;
826}
827#else
828static inline int console_cursor_is_visible(void)
829{
830 return 1;
831}
832#endif
833
834static void console_newline(int n)
835{
836 console_row += n;
wdenk4b248f32004-03-14 16:51:43 +0000837 console_col = 0;
wdenkc6097192002-11-03 00:24:07 +0000838
wdenk4b248f32004-03-14 16:51:43 +0000839 /* Check if we need to scroll the terminal */
840 if (console_row >= CONSOLE_ROWS) {
841 /* Scroll everything up */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000842 console_scrollup();
wdenk4b248f32004-03-14 16:51:43 +0000843 }
wdenkc6097192002-11-03 00:24:07 +0000844}
845
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000846static void console_cr(void)
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100847{
Timur Tabi65618632010-08-27 15:45:47 -0500848 console_col = 0;
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100849}
850
Pali Rohár33a35bb2012-10-19 13:30:09 +0000851static void parse_putc(const char c)
wdenkc6097192002-11-03 00:24:07 +0000852{
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100853 static int nl = 1;
854
Pali Rohár33a35bb2012-10-19 13:30:09 +0000855 if (console_cursor_is_visible())
856 CURSOR_OFF;
Gabe Black03d31fc2011-11-30 13:50:50 +0000857
wdenk4b248f32004-03-14 16:51:43 +0000858 switch (c) {
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100859 case 13: /* back to first column */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000860 console_cr();
wdenk4b248f32004-03-14 16:51:43 +0000861 break;
wdenkc6097192002-11-03 00:24:07 +0000862
wdenk4b248f32004-03-14 16:51:43 +0000863 case '\n': /* next line */
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100864 if (console_col || (!console_col && nl))
Pali Rohár33a35bb2012-10-19 13:30:09 +0000865 console_newline(1);
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100866 nl = 1;
wdenk4b248f32004-03-14 16:51:43 +0000867 break;
wdenkc6097192002-11-03 00:24:07 +0000868
wdenk4b248f32004-03-14 16:51:43 +0000869 case 9: /* tab 8 */
Timur Tabi65618632010-08-27 15:45:47 -0500870 console_col |= 0x0008;
wdenk4b248f32004-03-14 16:51:43 +0000871 console_col &= ~0x0007;
wdenkc6097192002-11-03 00:24:07 +0000872
wdenk4b248f32004-03-14 16:51:43 +0000873 if (console_col >= CONSOLE_COLS)
Pali Rohár33a35bb2012-10-19 13:30:09 +0000874 console_newline(1);
wdenk4b248f32004-03-14 16:51:43 +0000875 break;
wdenkc6097192002-11-03 00:24:07 +0000876
wdenk4b248f32004-03-14 16:51:43 +0000877 case 8: /* backspace */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000878 console_back();
wdenk4b248f32004-03-14 16:51:43 +0000879 break;
wdenkc6097192002-11-03 00:24:07 +0000880
Pali Rohár24fe06c2012-04-28 07:26:47 +0000881 case 7: /* bell */
882 break; /* ignored */
883
wdenk4b248f32004-03-14 16:51:43 +0000884 default: /* draw the char */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000885 video_putchar(console_col * VIDEO_FONT_WIDTH,
886 console_row * VIDEO_FONT_HEIGHT, c);
wdenk4b248f32004-03-14 16:51:43 +0000887 console_col++;
wdenkc6097192002-11-03 00:24:07 +0000888
wdenk4b248f32004-03-14 16:51:43 +0000889 /* check for newline */
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100890 if (console_col >= CONSOLE_COLS) {
Pali Rohár33a35bb2012-10-19 13:30:09 +0000891 console_newline(1);
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100892 nl = 0;
893 }
wdenk4b248f32004-03-14 16:51:43 +0000894 }
Pali Rohár33a35bb2012-10-19 13:30:09 +0000895
896 if (console_cursor_is_visible())
897 CURSOR_SET;
898}
899
Jeroen Hofstee654f8d02014-10-08 22:57:44 +0200900static void video_putc(struct stdio_dev *dev, const char c)
Pali Rohár33a35bb2012-10-19 13:30:09 +0000901{
902#ifdef CONFIG_CFB_CONSOLE_ANSI
903 int i;
904
905 if (c == 27) {
906 for (i = 0; i < ansi_buf_size; ++i)
907 parse_putc(ansi_buf[i]);
908 ansi_buf[0] = 27;
909 ansi_buf_size = 1;
910 return;
911 }
912
913 if (ansi_buf_size > 0) {
914 /*
915 * 0 - ESC
916 * 1 - [
917 * 2 - num1
918 * 3 - ..
919 * 4 - ;
920 * 5 - num2
921 * 6 - ..
922 * - cchar
923 */
924 int next = 0;
925
926 int flush = 0;
927 int fail = 0;
928
929 int num1 = 0;
930 int num2 = 0;
931 int cchar = 0;
932
933 ansi_buf[ansi_buf_size++] = c;
934
935 if (ansi_buf_size >= sizeof(ansi_buf))
936 fail = 1;
937
938 for (i = 0; i < ansi_buf_size; ++i) {
939 if (fail)
940 break;
941
942 switch (next) {
943 case 0:
944 if (ansi_buf[i] == 27)
945 next = 1;
946 else
947 fail = 1;
948 break;
949
950 case 1:
951 if (ansi_buf[i] == '[')
952 next = 2;
953 else
954 fail = 1;
955 break;
956
957 case 2:
958 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
959 num1 = ansi_buf[i]-'0';
960 next = 3;
961 } else if (ansi_buf[i] != '?') {
962 --i;
963 num1 = 1;
964 next = 4;
965 }
966 break;
967
968 case 3:
969 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
970 num1 *= 10;
971 num1 += ansi_buf[i]-'0';
972 } else {
973 --i;
974 next = 4;
975 }
976 break;
977
978 case 4:
979 if (ansi_buf[i] != ';') {
980 --i;
981 next = 7;
982 } else
983 next = 5;
984 break;
985
986 case 5:
987 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
988 num2 = ansi_buf[i]-'0';
989 next = 6;
990 } else
991 fail = 1;
992 break;
993
994 case 6:
995 if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
996 num2 *= 10;
997 num2 += ansi_buf[i]-'0';
998 } else {
999 --i;
1000 next = 7;
1001 }
1002 break;
1003
1004 case 7:
1005 if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H')
1006 || ansi_buf[i] == 'J'
1007 || ansi_buf[i] == 'K'
1008 || ansi_buf[i] == 'h'
1009 || ansi_buf[i] == 'l'
1010 || ansi_buf[i] == 'm') {
1011 cchar = ansi_buf[i];
1012 flush = 1;
1013 } else
1014 fail = 1;
1015 break;
1016 }
1017 }
1018
1019 if (fail) {
1020 for (i = 0; i < ansi_buf_size; ++i)
1021 parse_putc(ansi_buf[i]);
1022 ansi_buf_size = 0;
1023 return;
1024 }
1025
1026 if (flush) {
1027 if (!ansi_cursor_hidden)
1028 CURSOR_OFF;
1029 ansi_buf_size = 0;
1030 switch (cchar) {
1031 case 'A':
1032 /* move cursor num1 rows up */
1033 console_cursor_up(num1);
1034 break;
1035 case 'B':
1036 /* move cursor num1 rows down */
1037 console_cursor_down(num1);
1038 break;
1039 case 'C':
1040 /* move cursor num1 columns forward */
1041 console_cursor_right(num1);
1042 break;
1043 case 'D':
1044 /* move cursor num1 columns back */
1045 console_cursor_left(num1);
1046 break;
1047 case 'E':
1048 /* move cursor num1 rows up at begin of row */
1049 console_previousline(num1);
1050 break;
1051 case 'F':
1052 /* move cursor num1 rows down at begin of row */
1053 console_newline(num1);
1054 break;
1055 case 'G':
1056 /* move cursor to column num1 */
1057 console_cursor_set_position(-1, num1-1);
1058 break;
1059 case 'H':
1060 /* move cursor to row num1, column num2 */
1061 console_cursor_set_position(num1-1, num2-1);
1062 break;
1063 case 'J':
1064 /* clear console and move cursor to 0, 0 */
1065 console_clear();
1066 console_cursor_set_position(0, 0);
1067 break;
1068 case 'K':
1069 /* clear line */
1070 if (num1 == 0)
1071 console_clear_line(console_row,
1072 console_col,
1073 CONSOLE_COLS-1);
1074 else if (num1 == 1)
1075 console_clear_line(console_row,
1076 0, console_col);
1077 else
1078 console_clear_line(console_row,
1079 0, CONSOLE_COLS-1);
1080 break;
1081 case 'h':
1082 ansi_cursor_hidden = 0;
1083 break;
1084 case 'l':
1085 ansi_cursor_hidden = 1;
1086 break;
1087 case 'm':
1088 if (num1 == 0) { /* reset swapped colors */
1089 if (ansi_colors_need_revert) {
1090 console_swap_colors();
1091 ansi_colors_need_revert = 0;
1092 }
1093 } else if (num1 == 7) { /* once swap colors */
1094 if (!ansi_colors_need_revert) {
1095 console_swap_colors();
1096 ansi_colors_need_revert = 1;
1097 }
1098 }
1099 break;
1100 }
1101 if (!ansi_cursor_hidden)
1102 CURSOR_SET;
1103 }
1104 } else {
1105 parse_putc(c);
1106 }
1107#else
1108 parse_putc(c);
1109#endif
Eric Nelsondb0d47d2013-05-06 14:27:28 +02001110 if (cfb_do_flush_cache)
1111 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
Timur Tabi65618632010-08-27 15:45:47 -05001112}
wdenkc6097192002-11-03 00:24:07 +00001113
Jeroen Hofstee654f8d02014-10-08 22:57:44 +02001114static void video_puts(struct stdio_dev *dev, const char *s)
wdenkc6097192002-11-03 00:24:07 +00001115{
Soeren Mochd37e96e2014-10-24 16:33:30 +02001116 int flush = cfb_do_flush_cache;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001117 int count = strlen(s);
wdenkc6097192002-11-03 00:24:07 +00001118
Soeren Mochd37e96e2014-10-24 16:33:30 +02001119 /* temporarily disable cache flush */
1120 cfb_do_flush_cache = 0;
1121
wdenk4b248f32004-03-14 16:51:43 +00001122 while (count--)
Simon Glass709ea542014-07-23 06:54:59 -06001123 video_putc(dev, *s++);
Soeren Mochd37e96e2014-10-24 16:33:30 +02001124
1125 if (flush) {
1126 cfb_do_flush_cache = flush;
1127 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
1128 }
wdenkc6097192002-11-03 00:24:07 +00001129}
1130
Anatolij Gustschin10543822010-05-01 22:21:09 +02001131/*
1132 * Do not enforce drivers (or board code) to provide empty
1133 * video_set_lut() if they do not support 8 bpp format.
1134 * Implement weak default function instead.
1135 */
Jeroen Hofstee69d27542014-10-08 22:57:30 +02001136__weak void video_set_lut(unsigned int index, unsigned char r,
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001137 unsigned char g, unsigned char b)
Anatolij Gustschin10543822010-05-01 22:21:09 +02001138{
1139}
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001140
Jon Loeliger07d38a12007-07-09 17:30:01 -05001141#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenk4b248f32004-03-14 16:51:43 +00001142
1143#define FILL_8BIT_332RGB(r,g,b) { \
1144 *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6); \
1145 fb ++; \
1146}
1147
1148#define FILL_15BIT_555RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001149 *(unsigned short *)fb = \
1150 SWAP16((unsigned short)(((r>>3)<<10) | \
1151 ((g>>3)<<5) | \
1152 (b>>3))); \
wdenk4b248f32004-03-14 16:51:43 +00001153 fb += 2; \
1154}
1155
1156#define FILL_16BIT_565RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001157 *(unsigned short *)fb = \
1158 SWAP16((unsigned short)((((r)>>3)<<11)| \
1159 (((g)>>2)<<5) | \
1160 ((b)>>3))); \
wdenk4b248f32004-03-14 16:51:43 +00001161 fb += 2; \
1162}
1163
1164#define FILL_32BIT_X888RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001165 *(unsigned long *)fb = \
1166 SWAP32((unsigned long)(((r<<16) | \
1167 (g<<8) | \
1168 b))); \
wdenk4b248f32004-03-14 16:51:43 +00001169 fb += 4; \
1170}
1171
1172#ifdef VIDEO_FB_LITTLE_ENDIAN
1173#define FILL_24BIT_888RGB(r,g,b) { \
1174 fb[0] = b; \
1175 fb[1] = g; \
1176 fb[2] = r; \
1177 fb += 3; \
1178}
1179#else
1180#define FILL_24BIT_888RGB(r,g,b) { \
1181 fb[0] = r; \
1182 fb[1] = g; \
1183 fb[2] = b; \
1184 fb += 3; \
1185}
1186#endif
1187
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001188#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001189static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001190{
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001191 ushort *dst = (ushort *) fb;
1192 ushort color = (ushort) (((r >> 3) << 10) |
1193 ((g >> 3) << 5) |
1194 (b >> 3));
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001195 if (x & 1)
1196 *(--dst) = color;
1197 else
1198 *(++dst) = color;
1199}
1200#endif
wdenk4b248f32004-03-14 16:51:43 +00001201
1202/*
Anatolij Gustschind5011762010-03-15 14:50:25 +01001203 * RLE8 bitmap support
1204 */
1205
1206#ifdef CONFIG_VIDEO_BMP_RLE8
1207/* Pre-calculated color table entry */
1208struct palette {
1209 union {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001210 unsigned short w; /* word */
1211 unsigned int dw; /* double word */
1212 } ce; /* color entry */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001213};
1214
1215/*
1216 * Helper to draw encoded/unencoded run.
1217 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001218static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
1219 int cnt, int enc)
Anatolij Gustschind5011762010-03-15 14:50:25 +01001220{
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001221 ulong addr = (ulong) *fb;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001222 int *off;
1223 int enc_off = 1;
1224 int i;
1225
1226 /*
1227 * Setup offset of the color index in the bitmap.
1228 * Color index of encoded run is at offset 1.
1229 */
1230 off = enc ? &enc_off : &i;
1231
1232 switch (VIDEO_DATA_FORMAT) {
1233 case GDF__8BIT_INDEX:
1234 for (i = 0; i < cnt; i++)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001235 *(unsigned char *) addr++ = bm[*off];
Anatolij Gustschind5011762010-03-15 14:50:25 +01001236 break;
1237 case GDF_15BIT_555RGB:
1238 case GDF_16BIT_565RGB:
1239 /* differences handled while pre-calculating palette */
1240 for (i = 0; i < cnt; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001241 *(unsigned short *) addr = p[bm[*off]].ce.w;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001242 addr += 2;
1243 }
1244 break;
1245 case GDF_32BIT_X888RGB:
1246 for (i = 0; i < cnt; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001247 *(unsigned long *) addr = p[bm[*off]].ce.dw;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001248 addr += 4;
1249 }
1250 break;
1251 }
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001252 *fb = (uchar *) addr; /* return modified address */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001253}
1254
Simon Glass1c3dbe52015-05-13 07:02:27 -06001255static int display_rle8_bitmap(struct bmp_image *img, int xoff, int yoff,
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001256 int width, int height)
Anatolij Gustschind5011762010-03-15 14:50:25 +01001257{
1258 unsigned char *bm;
1259 unsigned char *fbp;
1260 unsigned int cnt, runlen;
1261 int decode = 1;
1262 int x, y, bpp, i, ncolors;
1263 struct palette p[256];
Simon Glass1c3dbe52015-05-13 07:02:27 -06001264 struct bmp_color_table_entry cte;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001265 int green_shift, red_off;
Hans de Goedec67a8762015-08-04 12:15:39 +02001266 int limit = (VIDEO_LINE_LEN / VIDEO_PIXEL_SIZE) * VIDEO_ROWS;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001267 int pixels = 0;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001268
1269 x = 0;
1270 y = __le32_to_cpu(img->header.height) - 1;
1271 ncolors = __le32_to_cpu(img->header.colors_used);
1272 bpp = VIDEO_PIXEL_SIZE;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001273 fbp = (unsigned char *) ((unsigned int) video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001274 (y + yoff) * VIDEO_LINE_LEN +
1275 xoff * bpp);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001276
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001277 bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001278
1279 /* pre-calculate and setup palette */
1280 switch (VIDEO_DATA_FORMAT) {
1281 case GDF__8BIT_INDEX:
1282 for (i = 0; i < ncolors; i++) {
1283 cte = img->color_table[i];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001284 video_set_lut(i, cte.red, cte.green, cte.blue);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001285 }
1286 break;
1287 case GDF_15BIT_555RGB:
1288 case GDF_16BIT_565RGB:
1289 if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
1290 green_shift = 3;
1291 red_off = 10;
1292 } else {
1293 green_shift = 2;
1294 red_off = 11;
1295 }
1296 for (i = 0; i < ncolors; i++) {
1297 cte = img->color_table[i];
1298 p[i].ce.w = SWAP16((unsigned short)
1299 (((cte.red >> 3) << red_off) |
1300 ((cte.green >> green_shift) << 5) |
1301 cte.blue >> 3));
1302 }
1303 break;
1304 case GDF_32BIT_X888RGB:
1305 for (i = 0; i < ncolors; i++) {
1306 cte = img->color_table[i];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001307 p[i].ce.dw = SWAP32((cte.red << 16) |
1308 (cte.green << 8) |
Anatolij Gustschind5011762010-03-15 14:50:25 +01001309 cte.blue);
1310 }
1311 break;
1312 default:
1313 printf("RLE Bitmap unsupported in video mode 0x%x\n",
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001314 VIDEO_DATA_FORMAT);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001315 return -1;
1316 }
1317
1318 while (decode) {
1319 switch (bm[0]) {
1320 case 0:
1321 switch (bm[1]) {
1322 case 0:
1323 /* scan line end marker */
1324 bm += 2;
1325 x = 0;
1326 y--;
1327 fbp = (unsigned char *)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001328 ((unsigned int) video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001329 (y + yoff) * VIDEO_LINE_LEN +
1330 xoff * bpp);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001331 continue;
1332 case 1:
1333 /* end of bitmap data marker */
1334 decode = 0;
1335 break;
1336 case 2:
1337 /* run offset marker */
1338 x += bm[2];
1339 y -= bm[3];
1340 fbp = (unsigned char *)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001341 ((unsigned int) video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001342 (y + yoff) * VIDEO_LINE_LEN +
1343 xoff * bpp);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001344 bm += 4;
1345 break;
1346 default:
1347 /* unencoded run */
1348 cnt = bm[1];
1349 runlen = cnt;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001350 pixels += cnt;
1351 if (pixels > limit)
1352 goto error;
1353
Anatolij Gustschind5011762010-03-15 14:50:25 +01001354 bm += 2;
1355 if (y < height) {
1356 if (x >= width) {
1357 x += runlen;
1358 goto next_run;
1359 }
1360 if (x + runlen > width)
1361 cnt = width - x;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001362 draw_bitmap(&fbp, bm, p, cnt, 0);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001363 x += runlen;
1364 }
1365next_run:
1366 bm += runlen;
1367 if (runlen & 1)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001368 bm++; /* 0 padding if length is odd */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001369 }
1370 break;
1371 default:
1372 /* encoded run */
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001373 cnt = bm[0];
1374 runlen = cnt;
1375 pixels += cnt;
1376 if (pixels > limit)
1377 goto error;
1378
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001379 if (y < height) { /* only draw into visible area */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001380 if (x >= width) {
1381 x += runlen;
1382 bm += 2;
1383 continue;
1384 }
1385 if (x + runlen > width)
1386 cnt = width - x;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001387 draw_bitmap(&fbp, bm, p, cnt, 1);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001388 x += runlen;
1389 }
1390 bm += 2;
1391 break;
1392 }
1393 }
1394 return 0;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001395error:
1396 printf("Error: Too much encoded pixel data, validate your bitmap\n");
1397 return -1;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001398}
1399#endif
1400
1401/*
wdenk4b248f32004-03-14 16:51:43 +00001402 * Display the BMP file located at address bmp_image.
wdenk4b248f32004-03-14 16:51:43 +00001403 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001404int video_display_bitmap(ulong bmp_image, int x, int y)
wdenk4b248f32004-03-14 16:51:43 +00001405{
1406 ushort xcount, ycount;
1407 uchar *fb;
Simon Glass1c3dbe52015-05-13 07:02:27 -06001408 struct bmp_image *bmp = (struct bmp_image *)bmp_image;
wdenk4b248f32004-03-14 16:51:43 +00001409 uchar *bmap;
1410 ushort padded_line;
1411 unsigned long width, height, bpp;
1412 unsigned colors;
1413 unsigned long compression;
Simon Glass1c3dbe52015-05-13 07:02:27 -06001414 struct bmp_color_table_entry cte;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001415
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001416#ifdef CONFIG_VIDEO_BMP_GZIP
1417 unsigned char *dst = NULL;
1418 ulong len;
1419#endif
wdenk4b248f32004-03-14 16:51:43 +00001420
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001421 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001422
1423 if (!((bmp->header.signature[0] == 'B') &&
1424 (bmp->header.signature[1] == 'M'))) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001425
1426#ifdef CONFIG_VIDEO_BMP_GZIP
1427 /*
1428 * Could be a gzipped bmp image, try to decrompress...
1429 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001430 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1431 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001432 if (dst == NULL) {
1433 printf("Error: malloc in gunzip failed!\n");
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001434 return 1;
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001435 }
Eric Nelson5ca05c82014-03-08 07:55:52 -07001436 /*
1437 * NB: we need to force offset of +2
1438 * See doc/README.displaying-bmps
1439 */
1440 if (gunzip(dst+2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE-2,
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001441 (uchar *) bmp_image,
1442 &len) != 0) {
1443 printf("Error: no valid bmp or bmp.gz image at %lx\n",
1444 bmp_image);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001445 free(dst);
1446 return 1;
1447 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001448 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001449 printf("Image could be truncated "
1450 "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001451 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001452
1453 /*
1454 * Set addr to decompressed image
1455 */
Simon Glass1c3dbe52015-05-13 07:02:27 -06001456 bmp = (struct bmp_image *)(dst+2);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001457
1458 if (!((bmp->header.signature[0] == 'B') &&
1459 (bmp->header.signature[1] == 'M'))) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001460 printf("Error: no valid bmp.gz image at %lx\n",
1461 bmp_image);
Matthias Fuchsa49e0d12008-04-21 11:19:04 +02001462 free(dst);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001463 return 1;
1464 }
1465#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001466 printf("Error: no valid bmp image at %lx\n", bmp_image);
wdenk4b248f32004-03-14 16:51:43 +00001467 return 1;
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001468#endif /* CONFIG_VIDEO_BMP_GZIP */
wdenk4b248f32004-03-14 16:51:43 +00001469 }
1470
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001471 width = le32_to_cpu(bmp->header.width);
1472 height = le32_to_cpu(bmp->header.height);
1473 bpp = le16_to_cpu(bmp->header.bit_count);
1474 colors = le32_to_cpu(bmp->header.colors_used);
1475 compression = le32_to_cpu(bmp->header.compression);
wdenk4b248f32004-03-14 16:51:43 +00001476
Marek Vasut68da5b12011-10-21 14:17:04 +00001477 debug("Display-bmp: %ld x %ld with %d colors\n",
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001478 width, height, colors);
wdenk4b248f32004-03-14 16:51:43 +00001479
Anatolij Gustschind5011762010-03-15 14:50:25 +01001480 if (compression != BMP_BI_RGB
1481#ifdef CONFIG_VIDEO_BMP_RLE8
1482 && compression != BMP_BI_RLE8
1483#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001484 ) {
1485 printf("Error: compression type %ld not supported\n",
1486 compression);
Matthias Fuchsa49e0d12008-04-21 11:19:04 +02001487#ifdef CONFIG_VIDEO_BMP_GZIP
1488 if (dst)
1489 free(dst);
1490#endif
wdenk4b248f32004-03-14 16:51:43 +00001491 return 1;
1492 }
1493
1494 padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1495
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001496#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1497 if (x == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001498 x = max(0, (int)(VIDEO_VISIBLE_COLS - width) / 2);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001499 else if (x < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001500 x = max(0, (int)(VIDEO_VISIBLE_COLS - width + x + 1));
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001501
1502 if (y == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001503 y = max(0, (int)(VIDEO_VISIBLE_ROWS - height) / 2);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001504 else if (y < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001505 y = max(0, (int)(VIDEO_VISIBLE_ROWS - height + y + 1));
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001506#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1507
Matthias Weisseracf3baa2013-02-15 03:35:12 +00001508 /*
1509 * Just ignore elements which are completely beyond screen
1510 * dimensions.
1511 */
1512 if ((x >= VIDEO_VISIBLE_COLS) || (y >= VIDEO_VISIBLE_ROWS))
1513 return 0;
1514
wdenk4b248f32004-03-14 16:51:43 +00001515 if ((x + width) > VIDEO_VISIBLE_COLS)
1516 width = VIDEO_VISIBLE_COLS - x;
1517 if ((y + height) > VIDEO_VISIBLE_ROWS)
1518 height = VIDEO_VISIBLE_ROWS - y;
1519
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001520 bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
wdenk4b248f32004-03-14 16:51:43 +00001521 fb = (uchar *) (video_fb_address +
Hans de Goedec67a8762015-08-04 12:15:39 +02001522 ((y + height - 1) * VIDEO_LINE_LEN) +
wdenk4b248f32004-03-14 16:51:43 +00001523 x * VIDEO_PIXEL_SIZE);
1524
Anatolij Gustschind5011762010-03-15 14:50:25 +01001525#ifdef CONFIG_VIDEO_BMP_RLE8
1526 if (compression == BMP_BI_RLE8) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001527 return display_rle8_bitmap(bmp, x, y, width, height);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001528 }
1529#endif
1530
Timur Tabi68f66182010-08-23 16:58:00 -05001531 /* We handle only 4, 8, or 24 bpp bitmaps */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001532 switch (le16_to_cpu(bmp->header.bit_count)) {
Timur Tabi68f66182010-08-23 16:58:00 -05001533 case 4:
1534 padded_line -= width / 2;
1535 ycount = height;
1536
1537 switch (VIDEO_DATA_FORMAT) {
1538 case GDF_32BIT_X888RGB:
1539 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001540 WATCHDOG_RESET();
Timur Tabi68f66182010-08-23 16:58:00 -05001541 /*
1542 * Don't assume that 'width' is an
1543 * even number
1544 */
1545 for (xcount = 0; xcount < width; xcount++) {
1546 uchar idx;
1547
1548 if (xcount & 1) {
1549 idx = *bmap & 0xF;
1550 bmap++;
1551 } else
1552 idx = *bmap >> 4;
1553 cte = bmp->color_table[idx];
1554 FILL_32BIT_X888RGB(cte.red, cte.green,
1555 cte.blue);
1556 }
1557 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001558 fb -= VIDEO_LINE_LEN + width *
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001559 VIDEO_PIXEL_SIZE;
Timur Tabi68f66182010-08-23 16:58:00 -05001560 }
1561 break;
1562 default:
1563 puts("4bpp bitmap unsupported with current "
1564 "video mode\n");
1565 break;
1566 }
1567 break;
1568
wdenk4b248f32004-03-14 16:51:43 +00001569 case 8:
1570 padded_line -= width;
1571 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001572 /* Copy colormap */
wdenk4b248f32004-03-14 16:51:43 +00001573 for (xcount = 0; xcount < colors; ++xcount) {
1574 cte = bmp->color_table[xcount];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001575 video_set_lut(xcount, cte.red, cte.green,
1576 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001577 }
1578 }
1579 ycount = height;
1580 switch (VIDEO_DATA_FORMAT) {
1581 case GDF__8BIT_INDEX:
1582 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001583 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001584 xcount = width;
1585 while (xcount--) {
1586 *fb++ = *bmap++;
1587 }
1588 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001589 fb -= VIDEO_LINE_LEN + width *
1590 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001591 }
1592 break;
1593 case GDF__8BIT_332RGB:
1594 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001595 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001596 xcount = width;
1597 while (xcount--) {
1598 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001599 FILL_8BIT_332RGB(cte.red, cte.green,
1600 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001601 }
1602 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001603 fb -= VIDEO_LINE_LEN + width *
1604 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001605 }
1606 break;
1607 case GDF_15BIT_555RGB:
1608 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001609#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1610 int xpos = x;
1611#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001612 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001613 xcount = width;
1614 while (xcount--) {
1615 cte = bmp->color_table[*bmap++];
Andrew Dyercc347802008-08-29 12:30:39 -05001616#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001617 fill_555rgb_pswap(fb, xpos++, cte.red,
1618 cte.green,
1619 cte.blue);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001620 fb += 2;
Andrew Dyercc347802008-08-29 12:30:39 -05001621#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001622 FILL_15BIT_555RGB(cte.red, cte.green,
1623 cte.blue);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001624#endif
wdenk4b248f32004-03-14 16:51:43 +00001625 }
1626 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001627 fb -= VIDEO_LINE_LEN + width *
1628 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001629 }
1630 break;
1631 case GDF_16BIT_565RGB:
1632 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001633 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001634 xcount = width;
1635 while (xcount--) {
1636 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001637 FILL_16BIT_565RGB(cte.red, cte.green,
1638 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001639 }
1640 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001641 fb -= VIDEO_LINE_LEN + width *
1642 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001643 }
1644 break;
1645 case GDF_32BIT_X888RGB:
1646 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001647 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001648 xcount = width;
1649 while (xcount--) {
1650 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001651 FILL_32BIT_X888RGB(cte.red, cte.green,
1652 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001653 }
1654 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001655 fb -= VIDEO_LINE_LEN + width *
1656 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001657 }
1658 break;
1659 case GDF_24BIT_888RGB:
1660 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001661 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001662 xcount = width;
1663 while (xcount--) {
1664 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001665 FILL_24BIT_888RGB(cte.red, cte.green,
1666 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001667 }
1668 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001669 fb -= VIDEO_LINE_LEN + width *
1670 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001671 }
1672 break;
1673 }
1674 break;
1675 case 24:
1676 padded_line -= 3 * width;
1677 ycount = height;
1678 switch (VIDEO_DATA_FORMAT) {
1679 case GDF__8BIT_332RGB:
1680 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001681 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001682 xcount = width;
1683 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001684 FILL_8BIT_332RGB(bmap[2], bmap[1],
1685 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001686 bmap += 3;
1687 }
1688 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001689 fb -= VIDEO_LINE_LEN + width *
1690 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001691 }
1692 break;
1693 case GDF_15BIT_555RGB:
1694 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001695#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1696 int xpos = x;
1697#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001698 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001699 xcount = width;
1700 while (xcount--) {
Andrew Dyercc347802008-08-29 12:30:39 -05001701#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001702 fill_555rgb_pswap(fb, xpos++, bmap[2],
1703 bmap[1], bmap[0]);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001704 fb += 2;
Andrew Dyercc347802008-08-29 12:30:39 -05001705#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001706 FILL_15BIT_555RGB(bmap[2], bmap[1],
1707 bmap[0]);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001708#endif
wdenk4b248f32004-03-14 16:51:43 +00001709 bmap += 3;
1710 }
1711 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001712 fb -= VIDEO_LINE_LEN + width *
1713 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001714 }
1715 break;
1716 case GDF_16BIT_565RGB:
1717 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001718 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001719 xcount = width;
1720 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001721 FILL_16BIT_565RGB(bmap[2], bmap[1],
1722 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001723 bmap += 3;
1724 }
1725 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001726 fb -= VIDEO_LINE_LEN + width *
1727 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001728 }
1729 break;
1730 case GDF_32BIT_X888RGB:
1731 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001732 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001733 xcount = width;
1734 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001735 FILL_32BIT_X888RGB(bmap[2], bmap[1],
1736 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001737 bmap += 3;
1738 }
1739 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001740 fb -= VIDEO_LINE_LEN + width *
1741 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001742 }
1743 break;
1744 case GDF_24BIT_888RGB:
1745 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001746 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001747 xcount = width;
1748 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001749 FILL_24BIT_888RGB(bmap[2], bmap[1],
1750 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001751 bmap += 3;
1752 }
1753 bmap += padded_line;
Hans de Goedec67a8762015-08-04 12:15:39 +02001754 fb -= VIDEO_LINE_LEN + width *
1755 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001756 }
1757 break;
1758 default:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001759 printf("Error: 24 bits/pixel bitmap incompatible "
1760 "with current video mode\n");
wdenk4b248f32004-03-14 16:51:43 +00001761 break;
1762 }
1763 break;
1764 default:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001765 printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1766 le16_to_cpu(bmp->header.bit_count));
wdenk4b248f32004-03-14 16:51:43 +00001767 break;
1768 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001769
1770#ifdef CONFIG_VIDEO_BMP_GZIP
1771 if (dst) {
1772 free(dst);
1773 }
1774#endif
1775
Eric Nelsondb0d47d2013-05-06 14:27:28 +02001776 if (cfb_do_flush_cache)
1777 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
wdenk4b248f32004-03-14 16:51:43 +00001778 return (0);
1779}
Jon Loeliger07d38a12007-07-09 17:30:01 -05001780#endif
wdenk4b248f32004-03-14 16:51:43 +00001781
wdenk4b248f32004-03-14 16:51:43 +00001782
wdenkc6097192002-11-03 00:24:07 +00001783#ifdef CONFIG_VIDEO_LOGO
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001784static int video_logo_xpos;
1785static int video_logo_ypos;
1786
Hans de Goedec4c9e812015-08-04 12:21:40 +02001787static void plot_logo_or_black(void *screen, int x, int y, int black);
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001788
Hans de Goedec4c9e812015-08-04 12:21:40 +02001789static void logo_plot(void *screen, int x, int y)
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001790{
Hans de Goedec4c9e812015-08-04 12:21:40 +02001791 plot_logo_or_black(screen, x, y, 0);
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001792}
1793
1794static void logo_black(void)
1795{
Hans de Goedec4c9e812015-08-04 12:21:40 +02001796 plot_logo_or_black(video_fb_address, video_logo_xpos, video_logo_ypos,
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001797 1);
1798}
1799
1800static int do_clrlogo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1801{
1802 if (argc != 1)
1803 return cmd_usage(cmdtp);
1804
1805 logo_black();
1806 return 0;
1807}
1808
1809U_BOOT_CMD(
1810 clrlogo, 1, 0, do_clrlogo,
1811 "fill the boot logo area with black",
1812 " "
1813 );
1814
Hans de Goedec4c9e812015-08-04 12:21:40 +02001815static void plot_logo_or_black(void *screen, int x, int y, int black)
wdenkc6097192002-11-03 00:24:07 +00001816{
wdenkc6097192002-11-03 00:24:07 +00001817
wdenk4b248f32004-03-14 16:51:43 +00001818 int xcount, i;
Hans de Goedec67a8762015-08-04 12:15:39 +02001819 int skip = VIDEO_LINE_LEN - VIDEO_LOGO_WIDTH * VIDEO_PIXEL_SIZE;
Matthias Weisserbe129aa2010-01-12 12:06:31 +01001820 int ycount = video_logo_height;
wdenk4b248f32004-03-14 16:51:43 +00001821 unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1822 unsigned char *source;
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001823 unsigned char *dest;
1824
1825#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1826 if (x == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001827 x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH) / 2);
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001828 else if (x < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001829 x = max(0, (int)(VIDEO_VISIBLE_COLS - VIDEO_LOGO_WIDTH + x + 1));
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001830
1831 if (y == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001832 y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT) / 2);
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001833 else if (y < 0)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001834 y = max(0, (int)(VIDEO_VISIBLE_ROWS - VIDEO_LOGO_HEIGHT + y + 1));
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001835#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1836
Hans de Goedec67a8762015-08-04 12:15:39 +02001837 dest = (unsigned char *)screen + y * VIDEO_LINE_LEN + x * VIDEO_PIXEL_SIZE;
wdenka6c7ad22002-12-03 21:28:10 +00001838
1839#ifdef CONFIG_VIDEO_BMP_LOGO
wdenk4b248f32004-03-14 16:51:43 +00001840 source = bmp_logo_bitmap;
wdenk8bde7f72003-06-27 21:31:46 +00001841
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001842 /* Allocate temporary space for computing colormap */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001843 logo_red = malloc(BMP_LOGO_COLORS);
1844 logo_green = malloc(BMP_LOGO_COLORS);
1845 logo_blue = malloc(BMP_LOGO_COLORS);
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001846 /* Compute color map */
wdenk4b248f32004-03-14 16:51:43 +00001847 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1848 logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1849 logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1850 logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1851 }
wdenka6c7ad22002-12-03 21:28:10 +00001852#else
wdenk4b248f32004-03-14 16:51:43 +00001853 source = linux_logo;
1854 logo_red = linux_logo_red;
1855 logo_green = linux_logo_green;
1856 logo_blue = linux_logo_blue;
wdenka6c7ad22002-12-03 21:28:10 +00001857#endif
wdenk8bde7f72003-06-27 21:31:46 +00001858
wdenk4b248f32004-03-14 16:51:43 +00001859 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1860 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001861 video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
1862 logo_red[i], logo_green[i],
1863 logo_blue[i]);
wdenk4b248f32004-03-14 16:51:43 +00001864 }
wdenk8bde7f72003-06-27 21:31:46 +00001865 }
wdenkc6097192002-11-03 00:24:07 +00001866
wdenk4b248f32004-03-14 16:51:43 +00001867 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001868#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1869 int xpos = x;
1870#endif
wdenk4b248f32004-03-14 16:51:43 +00001871 xcount = VIDEO_LOGO_WIDTH;
1872 while (xcount--) {
Bastian Ruppert4b7d3a02012-09-13 22:29:02 +00001873 if (black) {
1874 r = 0x00;
1875 g = 0x00;
1876 b = 0x00;
1877 } else {
1878 r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1879 g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1880 b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
1881 }
wdenk8bde7f72003-06-27 21:31:46 +00001882
wdenk4b248f32004-03-14 16:51:43 +00001883 switch (VIDEO_DATA_FORMAT) {
1884 case GDF__8BIT_INDEX:
1885 *dest = *source;
1886 break;
1887 case GDF__8BIT_332RGB:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001888 *dest = ((r >> 5) << 5) |
1889 ((g >> 5) << 2) |
1890 (b >> 6);
wdenk4b248f32004-03-14 16:51:43 +00001891 break;
1892 case GDF_15BIT_555RGB:
Andrew Dyercc347802008-08-29 12:30:39 -05001893#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001894 fill_555rgb_pswap(dest, xpos++, r, g, b);
Andrew Dyercc347802008-08-29 12:30:39 -05001895#else
wdenk4b248f32004-03-14 16:51:43 +00001896 *(unsigned short *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001897 SWAP16((unsigned short) (
1898 ((r >> 3) << 10) |
1899 ((g >> 3) << 5) |
1900 (b >> 3)));
Anatolij Gustschinbed53752008-01-11 14:30:01 +01001901#endif
wdenk4b248f32004-03-14 16:51:43 +00001902 break;
1903 case GDF_16BIT_565RGB:
1904 *(unsigned short *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001905 SWAP16((unsigned short) (
1906 ((r >> 3) << 11) |
1907 ((g >> 2) << 5) |
1908 (b >> 3)));
wdenk4b248f32004-03-14 16:51:43 +00001909 break;
1910 case GDF_32BIT_X888RGB:
1911 *(unsigned long *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001912 SWAP32((unsigned long) (
1913 (r << 16) |
1914 (g << 8) |
1915 b));
wdenk4b248f32004-03-14 16:51:43 +00001916 break;
1917 case GDF_24BIT_888RGB:
wdenkc6097192002-11-03 00:24:07 +00001918#ifdef VIDEO_FB_LITTLE_ENDIAN
wdenk4b248f32004-03-14 16:51:43 +00001919 dest[0] = b;
1920 dest[1] = g;
1921 dest[2] = r;
wdenkc6097192002-11-03 00:24:07 +00001922#else
wdenk4b248f32004-03-14 16:51:43 +00001923 dest[0] = r;
1924 dest[1] = g;
1925 dest[2] = b;
wdenkc6097192002-11-03 00:24:07 +00001926#endif
wdenk4b248f32004-03-14 16:51:43 +00001927 break;
1928 }
1929 source++;
1930 dest += VIDEO_PIXEL_SIZE;
1931 }
1932 dest += skip;
wdenk8bde7f72003-06-27 21:31:46 +00001933 }
wdenka6c7ad22002-12-03 21:28:10 +00001934#ifdef CONFIG_VIDEO_BMP_LOGO
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001935 free(logo_red);
1936 free(logo_green);
1937 free(logo_blue);
wdenka6c7ad22002-12-03 21:28:10 +00001938#endif
wdenkc6097192002-11-03 00:24:07 +00001939}
1940
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001941static void *video_logo(void)
wdenkc6097192002-11-03 00:24:07 +00001942{
wdenk4b248f32004-03-14 16:51:43 +00001943 char info[128];
Wolfgang Denka9a62af2011-11-04 15:55:20 +00001944 int space, len;
1945 __maybe_unused int y_off = 0;
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001946 __maybe_unused ulong addr;
1947 __maybe_unused char *s;
wdenkc6097192002-11-03 00:24:07 +00001948
Anatolij Gustschinff8fb562013-07-02 00:04:05 +02001949 splash_get_pos(&video_logo_xpos, &video_logo_ypos);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001950
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001951#ifdef CONFIG_SPLASH_SCREEN
1952 s = getenv("splashimage");
1953 if (s != NULL) {
Robert Winklerdd4425e2013-06-17 11:31:29 -07001954 splash_screen_prepare();
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001955 addr = simple_strtoul(s, NULL, 16);
1956
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001957 if (video_display_bitmap(addr,
1958 video_logo_xpos,
1959 video_logo_ypos) == 0) {
Matthias Weisserbe129aa2010-01-12 12:06:31 +01001960 video_logo_height = 0;
wdenk4b248f32004-03-14 16:51:43 +00001961 return ((void *) (video_fb_address));
1962 }
1963 }
1964#endif /* CONFIG_SPLASH_SCREEN */
1965
Hans de Goedec4c9e812015-08-04 12:21:40 +02001966 logo_plot(video_fb_address, video_logo_xpos, video_logo_ypos);
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001967
1968#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1969 /*
1970 * when using splashpos for video_logo, skip any info
1971 * output on video console if the logo is not at 0,0
1972 */
1973 if (video_logo_xpos || video_logo_ypos) {
1974 /*
1975 * video_logo_height is used in text and cursor offset
1976 * calculations. Since the console is below the logo,
1977 * we need to adjust the logo height
1978 */
1979 if (video_logo_ypos == BMP_ALIGN_CENTER)
Masahiro Yamadab4141192014-11-07 03:03:31 +09001980 video_logo_height += max(0, (int)(VIDEO_VISIBLE_ROWS -
Bastian Ruppert1e681f92012-09-13 22:29:01 +00001981 VIDEO_LOGO_HEIGHT) / 2);
1982 else if (video_logo_ypos > 0)
1983 video_logo_height += video_logo_ypos;
1984
1985 return video_fb_address + video_logo_height * VIDEO_LINE_LEN;
1986 }
1987#endif
Heiko Schocher2bc4aa52013-08-03 07:22:53 +02001988 if (board_cfb_skip())
1989 return 0;
wdenk4b248f32004-03-14 16:51:43 +00001990
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001991 sprintf(info, " %s", version_string);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001992
1993 space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1994 len = strlen(info);
1995
1996 if (len > space) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001997 video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1998 (uchar *) info, space);
1999 video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
2000 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
2001 (uchar *) info + space, len - space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02002002 y_off = 1;
2003 } else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002004 video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
wdenkc6097192002-11-03 00:24:07 +00002005
2006#ifdef CONFIG_CONSOLE_EXTRA_INFO
wdenk4b248f32004-03-14 16:51:43 +00002007 {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002008 int i, n =
2009 ((video_logo_height -
2010 VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00002011
wdenk4b248f32004-03-14 16:51:43 +00002012 for (i = 1; i < n; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002013 video_get_info_str(i, info);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02002014 if (!*info)
2015 continue;
2016
2017 len = strlen(info);
2018 if (len > space) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002019 video_drawchars(VIDEO_INFO_X,
2020 VIDEO_INFO_Y +
2021 (i + y_off) *
2022 VIDEO_FONT_HEIGHT,
2023 (uchar *) info, space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02002024 y_off++;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002025 video_drawchars(VIDEO_INFO_X +
2026 VIDEO_FONT_WIDTH,
2027 VIDEO_INFO_Y +
2028 (i + y_off) *
2029 VIDEO_FONT_HEIGHT,
2030 (uchar *) info + space,
2031 len - space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02002032 } else {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002033 video_drawstring(VIDEO_INFO_X,
2034 VIDEO_INFO_Y +
2035 (i + y_off) *
2036 VIDEO_FONT_HEIGHT,
2037 (uchar *) info);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02002038 }
wdenk4b248f32004-03-14 16:51:43 +00002039 }
2040 }
wdenkc6097192002-11-03 00:24:07 +00002041#endif
2042
Matthias Weisserbe129aa2010-01-12 12:06:31 +01002043 return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
wdenkc6097192002-11-03 00:24:07 +00002044}
2045#endif
2046
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +02002047static int cfb_fb_is_in_dram(void)
2048{
2049 bd_t *bd = gd->bd;
2050#if defined(CONFIG_ARM) || defined(CONFIG_AVR32) || defined(COFNIG_NDS32) || \
2051defined(CONFIG_SANDBOX) || defined(CONFIG_X86)
2052 ulong start, end;
2053 int i;
2054
2055 for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
2056 start = bd->bi_dram[i].start;
2057 end = bd->bi_dram[i].start + bd->bi_dram[i].size - 1;
2058 if ((ulong)video_fb_address >= start &&
2059 (ulong)video_fb_address < end)
2060 return 1;
2061 }
2062#else
2063 if ((ulong)video_fb_address >= bd->bi_memstart &&
2064 (ulong)video_fb_address < bd->bi_memstart + bd->bi_memsize)
2065 return 1;
2066#endif
2067 return 0;
2068}
2069
Heiko Schocher45ae2542013-10-22 11:06:06 +02002070void video_clear(void)
2071{
2072 if (!video_fb_address)
2073 return;
2074#ifdef VIDEO_HW_RECTFILL
2075 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */
2076 0, /* dest pos x */
2077 0, /* dest pos y */
2078 VIDEO_VISIBLE_COLS, /* frame width */
2079 VIDEO_VISIBLE_ROWS, /* frame height */
2080 bgx /* fill color */
2081 );
2082#else
2083 memsetl(video_fb_address,
2084 (VIDEO_VISIBLE_ROWS * VIDEO_LINE_LEN) / sizeof(int), bgx);
2085#endif
2086}
2087
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002088static int video_init(void)
wdenkc6097192002-11-03 00:24:07 +00002089{
wdenk4b248f32004-03-14 16:51:43 +00002090 unsigned char color8;
wdenkc6097192002-11-03 00:24:07 +00002091
Wolfgang Denk57912932011-07-30 12:48:09 +00002092 pGD = video_hw_init();
2093 if (pGD == NULL)
wdenk4b248f32004-03-14 16:51:43 +00002094 return -1;
wdenkc6097192002-11-03 00:24:07 +00002095
wdenk4b248f32004-03-14 16:51:43 +00002096 video_fb_address = (void *) VIDEO_FB_ADRS;
wdenkc6097192002-11-03 00:24:07 +00002097#ifdef CONFIG_VIDEO_HW_CURSOR
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002098 video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00002099#endif
2100
Anatolij Gustschinbfd4be82012-06-05 09:19:18 +02002101 cfb_do_flush_cache = cfb_fb_is_in_dram() && dcache_status();
2102
wdenk4b248f32004-03-14 16:51:43 +00002103 /* Init drawing pats */
2104 switch (VIDEO_DATA_FORMAT) {
2105 case GDF__8BIT_INDEX:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002106 video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL,
2107 CONSOLE_FG_COL);
2108 video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL,
2109 CONSOLE_BG_COL);
wdenk4b248f32004-03-14 16:51:43 +00002110 fgx = 0x01010101;
2111 bgx = 0x00000000;
2112 break;
2113 case GDF__8BIT_332RGB:
2114 color8 = ((CONSOLE_FG_COL & 0xe0) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002115 ((CONSOLE_FG_COL >> 3) & 0x1c) |
2116 CONSOLE_FG_COL >> 6);
2117 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2118 color8;
wdenk4b248f32004-03-14 16:51:43 +00002119 color8 = ((CONSOLE_BG_COL & 0xe0) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002120 ((CONSOLE_BG_COL >> 3) & 0x1c) |
2121 CONSOLE_BG_COL >> 6);
2122 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
2123 color8;
wdenk4b248f32004-03-14 16:51:43 +00002124 break;
2125 case GDF_15BIT_555RGB:
2126 fgx = (((CONSOLE_FG_COL >> 3) << 26) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002127 ((CONSOLE_FG_COL >> 3) << 21) |
2128 ((CONSOLE_FG_COL >> 3) << 16) |
2129 ((CONSOLE_FG_COL >> 3) << 10) |
2130 ((CONSOLE_FG_COL >> 3) << 5) |
2131 (CONSOLE_FG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00002132 bgx = (((CONSOLE_BG_COL >> 3) << 26) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002133 ((CONSOLE_BG_COL >> 3) << 21) |
2134 ((CONSOLE_BG_COL >> 3) << 16) |
2135 ((CONSOLE_BG_COL >> 3) << 10) |
2136 ((CONSOLE_BG_COL >> 3) << 5) |
2137 (CONSOLE_BG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00002138 break;
2139 case GDF_16BIT_565RGB:
2140 fgx = (((CONSOLE_FG_COL >> 3) << 27) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002141 ((CONSOLE_FG_COL >> 2) << 21) |
2142 ((CONSOLE_FG_COL >> 3) << 16) |
2143 ((CONSOLE_FG_COL >> 3) << 11) |
2144 ((CONSOLE_FG_COL >> 2) << 5) |
2145 (CONSOLE_FG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00002146 bgx = (((CONSOLE_BG_COL >> 3) << 27) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002147 ((CONSOLE_BG_COL >> 2) << 21) |
2148 ((CONSOLE_BG_COL >> 3) << 16) |
2149 ((CONSOLE_BG_COL >> 3) << 11) |
2150 ((CONSOLE_BG_COL >> 2) << 5) |
2151 (CONSOLE_BG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00002152 break;
2153 case GDF_32BIT_X888RGB:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002154 fgx = (CONSOLE_FG_COL << 16) |
2155 (CONSOLE_FG_COL << 8) |
2156 CONSOLE_FG_COL;
2157 bgx = (CONSOLE_BG_COL << 16) |
2158 (CONSOLE_BG_COL << 8) |
2159 CONSOLE_BG_COL;
wdenk4b248f32004-03-14 16:51:43 +00002160 break;
2161 case GDF_24BIT_888RGB:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002162 fgx = (CONSOLE_FG_COL << 24) |
2163 (CONSOLE_FG_COL << 16) |
2164 (CONSOLE_FG_COL << 8) |
2165 CONSOLE_FG_COL;
2166 bgx = (CONSOLE_BG_COL << 24) |
2167 (CONSOLE_BG_COL << 16) |
2168 (CONSOLE_BG_COL << 8) |
2169 CONSOLE_BG_COL;
wdenk4b248f32004-03-14 16:51:43 +00002170 break;
2171 }
2172 eorx = fgx ^ bgx;
wdenkc6097192002-11-03 00:24:07 +00002173
Heiko Schocher45ae2542013-10-22 11:06:06 +02002174 video_clear();
2175
wdenkc6097192002-11-03 00:24:07 +00002176#ifdef CONFIG_VIDEO_LOGO
wdenk4b248f32004-03-14 16:51:43 +00002177 /* Plot the logo and get start point of console */
Wolfgang Denk72c65f62011-07-29 09:55:28 +00002178 debug("Video: Drawing the logo ...\n");
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002179 video_console_address = video_logo();
wdenkc6097192002-11-03 00:24:07 +00002180#else
wdenk4b248f32004-03-14 16:51:43 +00002181 video_console_address = video_fb_address;
wdenkc6097192002-11-03 00:24:07 +00002182#endif
2183
wdenk4b248f32004-03-14 16:51:43 +00002184 /* Initialize the console */
2185 console_col = 0;
2186 console_row = 0;
wdenkc6097192002-11-03 00:24:07 +00002187
Eric Nelsondb0d47d2013-05-06 14:27:28 +02002188 if (cfb_do_flush_cache)
2189 flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE);
2190
wdenk4b248f32004-03-14 16:51:43 +00002191 return 0;
wdenkc6097192002-11-03 00:24:07 +00002192}
2193
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002194/*
2195 * Implement a weak default function for boards that optionally
2196 * need to skip the video initialization.
2197 */
Jeroen Hofstee69d27542014-10-08 22:57:30 +02002198__weak int board_video_skip(void)
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002199{
2200 /* As default, don't skip test */
2201 return 0;
2202}
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002203
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002204int drv_video_init(void)
wdenkc6097192002-11-03 00:24:07 +00002205{
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02002206 struct stdio_dev console_dev;
Simon Glass5692ccf2015-03-02 12:40:50 -07002207 bool have_keyboard;
Bin Meng8ceb2422015-08-24 01:00:07 -07002208 bool __maybe_unused keyboard_ok = false;
wdenkc6097192002-11-03 00:24:07 +00002209
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02002210 /* Check if video initialization should be skipped */
2211 if (board_video_skip())
2212 return 0;
2213
wdenk81050922004-07-11 20:04:51 +00002214 /* Init video chip - returns with framebuffer cleared */
Bin Meng8ceb2422015-08-24 01:00:07 -07002215 if (video_init() == -1)
2216 return 0;
wdenk81050922004-07-11 20:04:51 +00002217
Heiko Schocher2bc4aa52013-08-03 07:22:53 +02002218 if (board_cfb_skip())
2219 return 0;
2220
Simon Glass5692ccf2015-03-02 12:40:50 -07002221#if defined(CONFIG_VGA_AS_SINGLE_DEVICE)
2222 have_keyboard = false;
2223#elif defined(CONFIG_OF_CONTROL)
2224 have_keyboard = !fdtdec_get_config_bool(gd->fdt_blob,
2225 "u-boot,no-keyboard");
2226#else
2227 have_keyboard = true;
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002228#endif
Simon Glass5692ccf2015-03-02 12:40:50 -07002229 if (have_keyboard) {
2230 debug("KBD: Keyboard init ...\n");
2231#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
Bin Meng8ceb2422015-08-24 01:00:07 -07002232 keyboard_ok = !(VIDEO_KBD_INIT_FCT == -1);
Simon Glass5692ccf2015-03-02 12:40:50 -07002233#endif
2234 }
wdenkc6097192002-11-03 00:24:07 +00002235
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002236 /* Init vga device */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002237 memset(&console_dev, 0, sizeof(console_dev));
2238 strcpy(console_dev.name, "vga");
Bin Meng1caf9342015-11-03 23:23:37 -08002239 console_dev.flags = DEV_FLAGS_OUTPUT;
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002240 console_dev.putc = video_putc; /* 'putc' function */
2241 console_dev.puts = video_puts; /* 'puts' function */
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002242
2243#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
Bin Meng8ceb2422015-08-24 01:00:07 -07002244 if (have_keyboard && keyboard_ok) {
Simon Glass5692ccf2015-03-02 12:40:50 -07002245 /* Also init console device */
2246 console_dev.flags |= DEV_FLAGS_INPUT;
2247 console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */
2248 console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */
2249 }
2250#endif
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002251
Wolfgang Denk64e40d72011-07-29 09:55:27 +00002252 if (stdio_register(&console_dev) != 0)
Wolfgang Denkf62f6462009-05-15 10:07:42 +02002253 return 0;
2254
2255 /* Return success */
2256 return 1;
wdenkc6097192002-11-03 00:24:07 +00002257}
Stefan Reinauerc20ee072012-09-28 15:11:12 +00002258
2259void video_position_cursor(unsigned col, unsigned row)
2260{
2261 console_col = min(col, CONSOLE_COLS - 1);
2262 console_row = min(row, CONSOLE_ROWS - 1);
2263}
2264
2265int video_get_pixel_width(void)
2266{
2267 return VIDEO_VISIBLE_COLS;
2268}
2269
2270int video_get_pixel_height(void)
2271{
2272 return VIDEO_VISIBLE_ROWS;
2273}
2274
2275int video_get_screen_rows(void)
2276{
2277 return CONSOLE_ROWS;
2278}
2279
2280int video_get_screen_columns(void)
2281{
2282 return CONSOLE_COLS;
2283}