blob: 4e653b8279418a5a2f56b6fb94c5bdc1bfff59d7 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2002 ELTEC Elektronik AG
3 * Frank Gottschling <fgottschling@eltec.de>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
wdenk4b248f32004-03-14 16:51:43 +000015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
wdenkc6097192002-11-03 00:24:07 +000016 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * cfb_console.c
26 *
27 * Color Framebuffer Console driver for 8/15/16/24/32 bits per pixel.
28 *
29 * At the moment only the 8x16 font is tested and the font fore- and
30 * background color is limited to black/white/gray colors. The Linux
31 * logo can be placed in the upper left corner and additional board
Wolfgang Denk64e40d72011-07-29 09:55:27 +000032 * information strings (that normally goes to serial port) can be drawn.
wdenkc6097192002-11-03 00:24:07 +000033 *
34 * The console driver can use the standard PC keyboard interface (i8042)
35 * for character input. Character output goes to a memory mapped video
36 * framebuffer with little or big-endian organisation.
37 * With environment setting 'console=serial' the console i/o can be
38 * forced to serial port.
Wolfgang Denk64e40d72011-07-29 09:55:27 +000039 *
40 * The driver uses graphic specific defines/parameters/functions:
41 *
42 * (for SMI LynxE graphic chip)
43 *
44 * CONFIG_VIDEO_SMI_LYNXEM - use graphic driver for SMI 710,712,810
45 * VIDEO_FB_LITTLE_ENDIAN - framebuffer organisation default: big endian
46 * VIDEO_HW_RECTFILL - graphic driver supports hardware rectangle fill
47 * VIDEO_HW_BITBLT - graphic driver supports hardware bit blt
48 *
49 * Console Parameters are set by graphic drivers global struct:
50 *
51 * VIDEO_VISIBLE_COLS - x resolution
52 * VIDEO_VISIBLE_ROWS - y resolution
53 * VIDEO_PIXEL_SIZE - storage size in byte per pixel
54 * VIDEO_DATA_FORMAT - graphical data format GDF
55 * VIDEO_FB_ADRS - start of video memory
56 *
57 * CONFIG_I8042_KBD - AT Keyboard driver for i8042
58 * VIDEO_KBD_INIT_FCT - init function for keyboard
59 * VIDEO_TSTC_FCT - keyboard_tstc function
60 * VIDEO_GETC_FCT - keyboard_getc function
61 *
62 * CONFIG_CONSOLE_CURSOR - on/off drawing cursor is done with
63 * delay loop in VIDEO_TSTC_FCT (i8042)
64 *
65 * CONFIG_SYS_CONSOLE_BLINK_COUNT - value for delay loop - blink rate
66 * CONFIG_CONSOLE_TIME - display time/date in upper right
67 * corner, needs CONFIG_CMD_DATE and
68 * CONFIG_CONSOLE_CURSOR
69 * CONFIG_VIDEO_LOGO - display Linux Logo in upper left corner
70 * CONFIG_VIDEO_BMP_LOGO - use bmp_logo instead of linux_logo
71 * CONFIG_CONSOLE_EXTRA_INFO - display additional board information
72 * strings that normaly goes to serial
73 * port. This define requires a board
74 * specific function:
75 * video_drawstring (VIDEO_INFO_X,
76 * VIDEO_INFO_Y + i*VIDEO_FONT_HEIGHT,
77 * info);
78 * that fills a info buffer at i=row.
79 * s.a: board/eltec/bab7xx.
80 * CONFIG_VGA_AS_SINGLE_DEVICE - If set the framebuffer device will be
81 * initialized as an output only device.
82 * The Keyboard driver will not be
83 * set-up. This may be used, if you have
84 * no or more than one Keyboard devices
85 * (USB Keyboard, AT Keyboard).
86 *
87 * CONFIG_VIDEO_SW_CURSOR: - Draws a cursor after the last
88 * character. No blinking is provided.
89 * Uses the macros CURSOR_SET and
90 * CURSOR_OFF.
91 *
92 * CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability
93 * of the graphic chip. Uses the macro
94 * CURSOR_SET. ATTENTION: If booting an
95 * OS, the display driver must disable
96 * the hardware register of the graphic
97 * chip. Otherwise a blinking field is
98 * displayed.
99 */
wdenkc6097192002-11-03 00:24:07 +0000100
101#include <common.h>
Andreas Bießmann09c2e902011-07-18 20:24:04 +0200102#include <version.h>
wdenka6c7ad22002-12-03 21:28:10 +0000103#include <malloc.h>
104
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000105/*
106 * Console device defines with SMI graphic
107 * Any other graphic must change this section
108 */
wdenkc6097192002-11-03 00:24:07 +0000109
wdenk4b248f32004-03-14 16:51:43 +0000110#ifdef CONFIG_VIDEO_SMI_LYNXEM
wdenkc6097192002-11-03 00:24:07 +0000111
112#define VIDEO_FB_LITTLE_ENDIAN
113#define VIDEO_HW_RECTFILL
114#define VIDEO_HW_BITBLT
115#endif
116
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000117/*
118 * Defines for the CT69000 driver
119 */
wdenk4b248f32004-03-14 16:51:43 +0000120#ifdef CONFIG_VIDEO_CT69000
wdenkc6097192002-11-03 00:24:07 +0000121
122#define VIDEO_FB_LITTLE_ENDIAN
123#define VIDEO_HW_RECTFILL
124#define VIDEO_HW_BITBLT
125#endif
126
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000127/*
128 * Defines for the SED13806 driver
129 */
wdenka6c7ad22002-12-03 21:28:10 +0000130#ifdef CONFIG_VIDEO_SED13806
131
wdenk89394042004-08-04 21:56:49 +0000132#ifndef CONFIG_TOTAL5200
wdenka6c7ad22002-12-03 21:28:10 +0000133#define VIDEO_FB_LITTLE_ENDIAN
wdenk89394042004-08-04 21:56:49 +0000134#endif
wdenka6c7ad22002-12-03 21:28:10 +0000135#define VIDEO_HW_RECTFILL
136#define VIDEO_HW_BITBLT
137#endif
138
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000139/*
140 * Defines for the SED13806 driver
141 */
Stefan Roese98f4a3d2005-09-22 09:04:17 +0200142#ifdef CONFIG_VIDEO_SM501
143
144#ifdef CONFIG_HH405
145#define VIDEO_FB_LITTLE_ENDIAN
146#endif
147#endif
148
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000149/*
150 * Defines for the MB862xx driver
151 */
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100152#ifdef CONFIG_VIDEO_MB862xx
153
154#ifdef CONFIG_VIDEO_CORALP
155#define VIDEO_FB_LITTLE_ENDIAN
156#endif
Anatolij Gustschin5d16ca82009-10-23 12:03:14 +0200157#ifdef CONFIG_VIDEO_MB862xx_ACCEL
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100158#define VIDEO_HW_RECTFILL
159#define VIDEO_HW_BITBLT
160#endif
Anatolij Gustschin5d16ca82009-10-23 12:03:14 +0200161#endif
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100162
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000163/*
Helmut Raiger62a22dc2011-10-12 23:16:29 +0000164 * Defines for the i.MX31 driver (mx3fb.c)
165 */
166#ifdef CONFIG_VIDEO_MX3
167#define VIDEO_FB_16BPP_WORD_SWAP
168#endif
169
170/*
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000171 * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
172 */
wdenkc6097192002-11-03 00:24:07 +0000173#include <video_fb.h>
174
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000175/*
176 * some Macros
177 */
wdenk4b248f32004-03-14 16:51:43 +0000178#define VIDEO_VISIBLE_COLS (pGD->winSizeX)
179#define VIDEO_VISIBLE_ROWS (pGD->winSizeY)
180#define VIDEO_PIXEL_SIZE (pGD->gdfBytesPP)
181#define VIDEO_DATA_FORMAT (pGD->gdfIndex)
182#define VIDEO_FB_ADRS (pGD->frameAdrs)
wdenkc6097192002-11-03 00:24:07 +0000183
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000184/*
185 * Console device defines with i8042 keyboard controller
186 * Any other keyboard controller must change this section
187 */
wdenkc6097192002-11-03 00:24:07 +0000188
wdenk4b248f32004-03-14 16:51:43 +0000189#ifdef CONFIG_I8042_KBD
wdenkc6097192002-11-03 00:24:07 +0000190#include <i8042.h>
191
wdenk4b248f32004-03-14 16:51:43 +0000192#define VIDEO_KBD_INIT_FCT i8042_kbd_init()
193#define VIDEO_TSTC_FCT i8042_tstc
194#define VIDEO_GETC_FCT i8042_getc
wdenkc6097192002-11-03 00:24:07 +0000195#endif
196
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000197/*
198 * Console device
199 */
wdenkc6097192002-11-03 00:24:07 +0000200
201#include <version.h>
202#include <linux/types.h>
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200203#include <stdio_dev.h>
wdenkc6097192002-11-03 00:24:07 +0000204#include <video_font.h>
wdenkc6097192002-11-03 00:24:07 +0000205
Jon Loeligerddb5d86f2007-07-10 11:13:21 -0500206#if defined(CONFIG_CMD_DATE)
207#include <rtc.h>
wdenkc6097192002-11-03 00:24:07 +0000208#endif
209
Jon Loeliger07d38a12007-07-09 17:30:01 -0500210#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenk4b248f32004-03-14 16:51:43 +0000211#include <watchdog.h>
212#include <bmp_layout.h>
Matthias Weisser1ca298c2009-07-09 16:07:30 +0200213
214#ifdef CONFIG_SPLASH_SCREEN_ALIGN
215#define BMP_ALIGN_CENTER 0x7FFF
216#endif
217
Jon Loeliger07d38a12007-07-09 17:30:01 -0500218#endif
wdenk4b248f32004-03-14 16:51:43 +0000219
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000220/*
221 * Cursor definition:
222 * CONFIG_CONSOLE_CURSOR: Uses a timer function (see drivers/input/i8042.c)
223 * to let the cursor blink. Uses the macros
224 * CURSOR_OFF and CURSOR_ON.
225 * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No
226 * blinking is provided. Uses the macros CURSOR_SET
227 * and CURSOR_OFF.
228 * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the
229 * graphic chip. Uses the macro CURSOR_SET.
230 * ATTENTION: If booting an OS, the display driver
231 * must disable the hardware register of the graphic
232 * chip. Otherwise a blinking field is displayed
233 */
wdenkc6097192002-11-03 00:24:07 +0000234#if !defined(CONFIG_CONSOLE_CURSOR) && \
235 !defined(CONFIG_VIDEO_SW_CURSOR) && \
236 !defined(CONFIG_VIDEO_HW_CURSOR)
237/* no Cursor defined */
238#define CURSOR_ON
239#define CURSOR_OFF
240#define CURSOR_SET
241#endif
242
wdenk4b248f32004-03-14 16:51:43 +0000243#ifdef CONFIG_CONSOLE_CURSOR
244#ifdef CURSOR_ON
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000245#error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
246 or CONFIG_VIDEO_HW_CURSOR can be defined
wdenkc6097192002-11-03 00:24:07 +0000247#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000248void console_cursor(int state);
249
Timur Tabi65618632010-08-27 15:45:47 -0500250#define CURSOR_ON console_cursor(1)
251#define CURSOR_OFF console_cursor(0)
wdenkc6097192002-11-03 00:24:07 +0000252#define CURSOR_SET
253#ifndef CONFIG_I8042_KBD
Marcel Ziswiler7817cb22007-12-30 03:30:46 +0100254#warning Cursor drawing on/off needs timer function s.a. drivers/input/i8042.c
wdenkc6097192002-11-03 00:24:07 +0000255#endif
256#else
wdenk4b248f32004-03-14 16:51:43 +0000257#ifdef CONFIG_CONSOLE_TIME
258#error CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME
wdenkc6097192002-11-03 00:24:07 +0000259#endif
260#endif /* CONFIG_CONSOLE_CURSOR */
261
wdenk4b248f32004-03-14 16:51:43 +0000262#ifdef CONFIG_VIDEO_SW_CURSOR
263#ifdef CURSOR_ON
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000264#error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
265 or CONFIG_VIDEO_HW_CURSOR can be defined
wdenkc6097192002-11-03 00:24:07 +0000266#endif
267#define CURSOR_ON
268#define CURSOR_OFF video_putchar(console_col * VIDEO_FONT_WIDTH,\
Timur Tabi65618632010-08-27 15:45:47 -0500269 console_row * VIDEO_FONT_HEIGHT, ' ')
270#define CURSOR_SET video_set_cursor()
wdenkc6097192002-11-03 00:24:07 +0000271#endif /* CONFIG_VIDEO_SW_CURSOR */
272
273
274#ifdef CONFIG_VIDEO_HW_CURSOR
wdenk4b248f32004-03-14 16:51:43 +0000275#ifdef CURSOR_ON
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000276#error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
277 or CONFIG_VIDEO_HW_CURSOR can be defined
wdenkc6097192002-11-03 00:24:07 +0000278#endif
279#define CURSOR_ON
280#define CURSOR_OFF
281#define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \
Timur Tabi65618632010-08-27 15:45:47 -0500282 (console_row * VIDEO_FONT_HEIGHT) + video_logo_height)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000283#endif /* CONFIG_VIDEO_HW_CURSOR */
wdenkc6097192002-11-03 00:24:07 +0000284
wdenk4b248f32004-03-14 16:51:43 +0000285#ifdef CONFIG_VIDEO_LOGO
286#ifdef CONFIG_VIDEO_BMP_LOGO
wdenka6c7ad22002-12-03 21:28:10 +0000287#include <bmp_logo.h>
wdenk4b248f32004-03-14 16:51:43 +0000288#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH
289#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT
290#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET
291#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS
wdenka6c7ad22002-12-03 21:28:10 +0000292
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000293#else /* CONFIG_VIDEO_BMP_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000294#define LINUX_LOGO_WIDTH 80
295#define LINUX_LOGO_HEIGHT 80
296#define LINUX_LOGO_COLORS 214
297#define LINUX_LOGO_LUT_OFFSET 0x20
wdenkc6097192002-11-03 00:24:07 +0000298#define __initdata
299#include <linux_logo.h>
wdenk4b248f32004-03-14 16:51:43 +0000300#define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH
301#define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT
302#define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET
303#define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000304#endif /* CONFIG_VIDEO_BMP_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000305#define VIDEO_INFO_X (VIDEO_LOGO_WIDTH)
306#define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000307#else /* CONFIG_VIDEO_LOGO */
wdenk4b248f32004-03-14 16:51:43 +0000308#define VIDEO_LOGO_WIDTH 0
309#define VIDEO_LOGO_HEIGHT 0
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000310#endif /* CONFIG_VIDEO_LOGO */
wdenkc6097192002-11-03 00:24:07 +0000311
wdenk4b248f32004-03-14 16:51:43 +0000312#define VIDEO_COLS VIDEO_VISIBLE_COLS
313#define VIDEO_ROWS VIDEO_VISIBLE_ROWS
314#define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE)
315#define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2)
316#define VIDEO_LINE_LEN (VIDEO_COLS*VIDEO_PIXEL_SIZE)
317#define VIDEO_BURST_LEN (VIDEO_COLS/8)
wdenkc6097192002-11-03 00:24:07 +0000318
wdenk4b248f32004-03-14 16:51:43 +0000319#ifdef CONFIG_VIDEO_LOGO
Matthias Weisserbe129aa2010-01-12 12:06:31 +0100320#define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000321#else
wdenk4b248f32004-03-14 16:51:43 +0000322#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000323#endif
324
wdenk4b248f32004-03-14 16:51:43 +0000325#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH)
326#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
327#define CONSOLE_ROW_FIRST (video_console_address)
328#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE)
329#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
330#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
331#define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
wdenkc6097192002-11-03 00:24:07 +0000332
333/* Macros */
wdenk4b248f32004-03-14 16:51:43 +0000334#ifdef VIDEO_FB_LITTLE_ENDIAN
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000335#define SWAP16(x) ((((x) & 0x00ff) << 8) | \
336 ((x) >> 8) \
337 )
338#define SWAP32(x) ((((x) & 0x000000ff) << 24) | \
339 (((x) & 0x0000ff00) << 8) | \
340 (((x) & 0x00ff0000) >> 8) | \
341 (((x) & 0xff000000) >> 24) \
342 )
343#define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | \
344 (((x) & 0x0000ff00) >> 8) | \
345 (((x) & 0x00ff0000) << 8) | \
346 (((x) & 0xff000000) >> 8) \
347 )
wdenkc6097192002-11-03 00:24:07 +0000348#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000349#define SWAP16(x) (x)
350#define SWAP32(x) (x)
Wolfgang Grandegger229b6dc2009-10-23 12:03:15 +0200351#if defined(VIDEO_FB_16BPP_WORD_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000352#define SHORTSWAP32(x) (((x) >> 16) | ((x) << 16))
Andrew Dyercc347802008-08-29 12:30:39 -0500353#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000354#define SHORTSWAP32(x) (x)
Anatolij Gustschinbed53752008-01-11 14:30:01 +0100355#endif
wdenkc6097192002-11-03 00:24:07 +0000356#endif
357
wdenkc6097192002-11-03 00:24:07 +0000358#ifdef CONFIG_CONSOLE_EXTRA_INFO
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000359/*
360 * setup a board string: type, speed, etc.
361 *
362 * line_number: location to place info string beside logo
363 * info: buffer for info string
364 */
365extern void video_get_info_str(int line_number, char *info);
wdenkc6097192002-11-03 00:24:07 +0000366#endif
367
368/* Locals */
369static GraphicDevice *pGD; /* Pointer to Graphic array */
370
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000371static void *video_fb_address; /* frame buffer address */
wdenk4b248f32004-03-14 16:51:43 +0000372static void *video_console_address; /* console buffer start address */
wdenkc6097192002-11-03 00:24:07 +0000373
Matthias Weisserbe129aa2010-01-12 12:06:31 +0100374static int video_logo_height = VIDEO_LOGO_HEIGHT;
375
Wolfgang Denk57912932011-07-30 12:48:09 +0000376static int console_col; /* cursor col */
377static int console_row; /* cursor row */
wdenkc6097192002-11-03 00:24:07 +0000378
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000379static u32 eorx, fgx, bgx; /* color pats */
wdenkc6097192002-11-03 00:24:07 +0000380
381static const int video_font_draw_table8[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000382 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
383 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
384 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
385 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
386};
wdenkc6097192002-11-03 00:24:07 +0000387
388static const int video_font_draw_table15[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000389 0x00000000, 0x00007fff, 0x7fff0000, 0x7fff7fff
390};
wdenkc6097192002-11-03 00:24:07 +0000391
392static const int video_font_draw_table16[] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000393 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
394};
wdenkc6097192002-11-03 00:24:07 +0000395
396static const int video_font_draw_table24[16][3] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000397 {0x00000000, 0x00000000, 0x00000000},
398 {0x00000000, 0x00000000, 0x00ffffff},
399 {0x00000000, 0x0000ffff, 0xff000000},
400 {0x00000000, 0x0000ffff, 0xffffffff},
401 {0x000000ff, 0xffff0000, 0x00000000},
402 {0x000000ff, 0xffff0000, 0x00ffffff},
403 {0x000000ff, 0xffffffff, 0xff000000},
404 {0x000000ff, 0xffffffff, 0xffffffff},
405 {0xffffff00, 0x00000000, 0x00000000},
406 {0xffffff00, 0x00000000, 0x00ffffff},
407 {0xffffff00, 0x0000ffff, 0xff000000},
408 {0xffffff00, 0x0000ffff, 0xffffffff},
409 {0xffffffff, 0xffff0000, 0x00000000},
410 {0xffffffff, 0xffff0000, 0x00ffffff},
411 {0xffffffff, 0xffffffff, 0xff000000},
412 {0xffffffff, 0xffffffff, 0xffffffff}
413};
wdenkc6097192002-11-03 00:24:07 +0000414
415static const int video_font_draw_table32[16][4] = {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000416 {0x00000000, 0x00000000, 0x00000000, 0x00000000},
417 {0x00000000, 0x00000000, 0x00000000, 0x00ffffff},
418 {0x00000000, 0x00000000, 0x00ffffff, 0x00000000},
419 {0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff},
420 {0x00000000, 0x00ffffff, 0x00000000, 0x00000000},
421 {0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff},
422 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000},
423 {0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff},
424 {0x00ffffff, 0x00000000, 0x00000000, 0x00000000},
425 {0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff},
426 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000},
427 {0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff},
428 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000},
429 {0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff},
430 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000},
431 {0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff}
432};
wdenkc6097192002-11-03 00:24:07 +0000433
434
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000435static void video_drawchars(int xx, int yy, unsigned char *s, int count)
wdenkc6097192002-11-03 00:24:07 +0000436{
wdenk4b248f32004-03-14 16:51:43 +0000437 u8 *cdat, *dest, *dest0;
438 int rows, offset, c;
wdenkc6097192002-11-03 00:24:07 +0000439
wdenk4b248f32004-03-14 16:51:43 +0000440 offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
441 dest0 = video_fb_address + offset;
wdenkc6097192002-11-03 00:24:07 +0000442
wdenk4b248f32004-03-14 16:51:43 +0000443 switch (VIDEO_DATA_FORMAT) {
444 case GDF__8BIT_INDEX:
445 case GDF__8BIT_332RGB:
446 while (count--) {
447 c = *s;
448 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
449 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000450 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000451 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000452
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000453 ((u32 *) dest)[0] =
454 (video_font_draw_table8[bits >> 4] &
455 eorx) ^ bgx;
456 ((u32 *) dest)[1] =
457 (video_font_draw_table8[bits & 15] &
458 eorx) ^ bgx;
wdenk4b248f32004-03-14 16:51:43 +0000459 }
460 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
461 s++;
462 }
463 break;
wdenkc6097192002-11-03 00:24:07 +0000464
wdenk4b248f32004-03-14 16:51:43 +0000465 case GDF_15BIT_555RGB:
466 while (count--) {
467 c = *s;
468 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
469 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000470 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000471 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000472
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000473 ((u32 *) dest)[0] =
474 SHORTSWAP32((video_font_draw_table15
475 [bits >> 6] & eorx) ^
476 bgx);
477 ((u32 *) dest)[1] =
478 SHORTSWAP32((video_font_draw_table15
479 [bits >> 4 & 3] & eorx) ^
480 bgx);
481 ((u32 *) dest)[2] =
482 SHORTSWAP32((video_font_draw_table15
483 [bits >> 2 & 3] & eorx) ^
484 bgx);
485 ((u32 *) dest)[3] =
486 SHORTSWAP32((video_font_draw_table15
487 [bits & 3] & eorx) ^
488 bgx);
wdenk4b248f32004-03-14 16:51:43 +0000489 }
490 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
491 s++;
492 }
493 break;
wdenkc6097192002-11-03 00:24:07 +0000494
wdenk4b248f32004-03-14 16:51:43 +0000495 case GDF_16BIT_565RGB:
496 while (count--) {
497 c = *s;
498 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
499 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000500 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000501 u8 bits = *cdat++;
502
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000503 ((u32 *) dest)[0] =
504 SHORTSWAP32((video_font_draw_table16
505 [bits >> 6] & eorx) ^
506 bgx);
507 ((u32 *) dest)[1] =
508 SHORTSWAP32((video_font_draw_table16
509 [bits >> 4 & 3] & eorx) ^
510 bgx);
511 ((u32 *) dest)[2] =
512 SHORTSWAP32((video_font_draw_table16
513 [bits >> 2 & 3] & eorx) ^
514 bgx);
515 ((u32 *) dest)[3] =
516 SHORTSWAP32((video_font_draw_table16
517 [bits & 3] & eorx) ^
518 bgx);
wdenk4b248f32004-03-14 16:51:43 +0000519 }
520 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
521 s++;
522 }
523 break;
524
525 case GDF_32BIT_X888RGB:
526 while (count--) {
527 c = *s;
528 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
529 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000530 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000531 u8 bits = *cdat++;
532
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000533 ((u32 *) dest)[0] =
534 SWAP32((video_font_draw_table32
535 [bits >> 4][0] & eorx) ^ bgx);
536 ((u32 *) dest)[1] =
537 SWAP32((video_font_draw_table32
538 [bits >> 4][1] & eorx) ^ bgx);
539 ((u32 *) dest)[2] =
540 SWAP32((video_font_draw_table32
541 [bits >> 4][2] & eorx) ^ bgx);
542 ((u32 *) dest)[3] =
543 SWAP32((video_font_draw_table32
544 [bits >> 4][3] & eorx) ^ bgx);
545 ((u32 *) dest)[4] =
546 SWAP32((video_font_draw_table32
547 [bits & 15][0] & eorx) ^ bgx);
548 ((u32 *) dest)[5] =
549 SWAP32((video_font_draw_table32
550 [bits & 15][1] & eorx) ^ bgx);
551 ((u32 *) dest)[6] =
552 SWAP32((video_font_draw_table32
553 [bits & 15][2] & eorx) ^ bgx);
554 ((u32 *) dest)[7] =
555 SWAP32((video_font_draw_table32
556 [bits & 15][3] & eorx) ^ bgx);
wdenk4b248f32004-03-14 16:51:43 +0000557 }
558 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
559 s++;
560 }
561 break;
562
563 case GDF_24BIT_888RGB:
564 while (count--) {
565 c = *s;
566 cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
567 for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000568 rows--; dest += VIDEO_LINE_LEN) {
wdenk4b248f32004-03-14 16:51:43 +0000569 u8 bits = *cdat++;
570
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000571 ((u32 *) dest)[0] =
572 (video_font_draw_table24[bits >> 4][0]
573 & eorx) ^ bgx;
574 ((u32 *) dest)[1] =
575 (video_font_draw_table24[bits >> 4][1]
576 & eorx) ^ bgx;
577 ((u32 *) dest)[2] =
578 (video_font_draw_table24[bits >> 4][2]
579 & eorx) ^ bgx;
580 ((u32 *) dest)[3] =
581 (video_font_draw_table24[bits & 15][0]
582 & eorx) ^ bgx;
583 ((u32 *) dest)[4] =
584 (video_font_draw_table24[bits & 15][1]
585 & eorx) ^ bgx;
586 ((u32 *) dest)[5] =
587 (video_font_draw_table24[bits & 15][2]
588 & eorx) ^ bgx;
wdenk4b248f32004-03-14 16:51:43 +0000589 }
590 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
591 s++;
592 }
593 break;
wdenk8bde7f72003-06-27 21:31:46 +0000594 }
wdenkc6097192002-11-03 00:24:07 +0000595}
596
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000597static inline void video_drawstring(int xx, int yy, unsigned char *s)
wdenkc6097192002-11-03 00:24:07 +0000598{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000599 video_drawchars(xx, yy, s, strlen((char *) s));
wdenkc6097192002-11-03 00:24:07 +0000600}
601
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000602static void video_putchar(int xx, int yy, unsigned char c)
wdenkc6097192002-11-03 00:24:07 +0000603{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000604 video_drawchars(xx, yy + video_logo_height, &c, 1);
wdenkc6097192002-11-03 00:24:07 +0000605}
606
wdenkc6097192002-11-03 00:24:07 +0000607#if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000608static void video_set_cursor(void)
wdenkc6097192002-11-03 00:24:07 +0000609{
wdenk4b248f32004-03-14 16:51:43 +0000610 /* swap drawing colors */
611 eorx = fgx;
612 fgx = bgx;
613 bgx = eorx;
614 eorx = fgx ^ bgx;
615 /* draw cursor */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000616 video_putchar(console_col * VIDEO_FONT_WIDTH,
617 console_row * VIDEO_FONT_HEIGHT, ' ');
wdenk4b248f32004-03-14 16:51:43 +0000618 /* restore drawing colors */
619 eorx = fgx;
620 fgx = bgx;
621 bgx = eorx;
622 eorx = fgx ^ bgx;
wdenkc6097192002-11-03 00:24:07 +0000623}
624#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000625
wdenkc6097192002-11-03 00:24:07 +0000626#ifdef CONFIG_CONSOLE_CURSOR
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000627void console_cursor(int state)
wdenkc6097192002-11-03 00:24:07 +0000628{
wdenk4b248f32004-03-14 16:51:43 +0000629 static int last_state = 0;
630
wdenkc6097192002-11-03 00:24:07 +0000631#ifdef CONFIG_CONSOLE_TIME
wdenk4b248f32004-03-14 16:51:43 +0000632 struct rtc_time tm;
633 char info[16];
wdenkc6097192002-11-03 00:24:07 +0000634
wdenk4b248f32004-03-14 16:51:43 +0000635 /* time update only if cursor is on (faster scroll) */
636 if (state) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000637 rtc_get(&tm);
wdenkc6097192002-11-03 00:24:07 +0000638
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000639 sprintf(info, " %02d:%02d:%02d ", tm.tm_hour, tm.tm_min,
640 tm.tm_sec);
641 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH,
642 VIDEO_INFO_Y, (uchar *) info);
wdenkc6097192002-11-03 00:24:07 +0000643
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000644 sprintf(info, "%02d.%02d.%04d", tm.tm_mday, tm.tm_mon,
645 tm.tm_year);
646 video_drawstring(VIDEO_VISIBLE_COLS - 10 * VIDEO_FONT_WIDTH,
647 VIDEO_INFO_Y + 1 * VIDEO_FONT_HEIGHT,
648 (uchar *) info);
wdenk4b248f32004-03-14 16:51:43 +0000649 }
wdenkc6097192002-11-03 00:24:07 +0000650#endif
651
wdenk4b248f32004-03-14 16:51:43 +0000652 if (state && (last_state != state)) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000653 video_set_cursor();
wdenk4b248f32004-03-14 16:51:43 +0000654 }
wdenkc6097192002-11-03 00:24:07 +0000655
wdenk4b248f32004-03-14 16:51:43 +0000656 if (!state && (last_state != state)) {
657 /* clear cursor */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000658 video_putchar(console_col * VIDEO_FONT_WIDTH,
659 console_row * VIDEO_FONT_HEIGHT, ' ');
wdenk4b248f32004-03-14 16:51:43 +0000660 }
wdenkc6097192002-11-03 00:24:07 +0000661
wdenk4b248f32004-03-14 16:51:43 +0000662 last_state = state;
wdenkc6097192002-11-03 00:24:07 +0000663}
664#endif
665
wdenkc6097192002-11-03 00:24:07 +0000666#ifndef VIDEO_HW_RECTFILL
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000667static void memsetl(int *p, int c, int v)
wdenkc6097192002-11-03 00:24:07 +0000668{
wdenk4b248f32004-03-14 16:51:43 +0000669 while (c--)
670 *(p++) = v;
wdenkc6097192002-11-03 00:24:07 +0000671}
672#endif
673
wdenkc6097192002-11-03 00:24:07 +0000674#ifndef VIDEO_HW_BITBLT
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000675static void memcpyl(int *d, int *s, int c)
wdenkc6097192002-11-03 00:24:07 +0000676{
wdenk4b248f32004-03-14 16:51:43 +0000677 while (c--)
678 *(d++) = *(s++);
wdenkc6097192002-11-03 00:24:07 +0000679}
680#endif
681
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000682static void console_scrollup(void)
wdenkc6097192002-11-03 00:24:07 +0000683{
wdenk4b248f32004-03-14 16:51:43 +0000684 /* copy up rows ignoring the first one */
wdenkc6097192002-11-03 00:24:07 +0000685
686#ifdef VIDEO_HW_BITBLT
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000687 video_hw_bitblt(VIDEO_PIXEL_SIZE, /* bytes per pixel */
688 0, /* source pos x */
689 video_logo_height +
690 VIDEO_FONT_HEIGHT, /* source pos y */
691 0, /* dest pos x */
692 video_logo_height, /* dest pos y */
693 VIDEO_VISIBLE_COLS, /* frame width */
694 VIDEO_VISIBLE_ROWS
695 - video_logo_height
696 - VIDEO_FONT_HEIGHT /* frame height */
wdenk4b248f32004-03-14 16:51:43 +0000697 );
wdenkc6097192002-11-03 00:24:07 +0000698#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000699 memcpyl(CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND,
700 CONSOLE_SCROLL_SIZE >> 2);
wdenkc6097192002-11-03 00:24:07 +0000701#endif
702
wdenk4b248f32004-03-14 16:51:43 +0000703 /* clear the last one */
wdenkc6097192002-11-03 00:24:07 +0000704#ifdef VIDEO_HW_RECTFILL
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000705 video_hw_rectfill(VIDEO_PIXEL_SIZE, /* bytes per pixel */
706 0, /* dest pos x */
707 VIDEO_VISIBLE_ROWS
708 - VIDEO_FONT_HEIGHT, /* dest pos y */
709 VIDEO_VISIBLE_COLS, /* frame width */
710 VIDEO_FONT_HEIGHT, /* frame height */
711 CONSOLE_BG_COL /* fill color */
wdenk4b248f32004-03-14 16:51:43 +0000712 );
wdenkc6097192002-11-03 00:24:07 +0000713#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000714 memsetl(CONSOLE_ROW_LAST, CONSOLE_ROW_SIZE >> 2, CONSOLE_BG_COL);
wdenkc6097192002-11-03 00:24:07 +0000715#endif
716}
717
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000718static void console_back(void)
wdenkc6097192002-11-03 00:24:07 +0000719{
Timur Tabi65618632010-08-27 15:45:47 -0500720 CURSOR_OFF;
721 console_col--;
wdenkc6097192002-11-03 00:24:07 +0000722
wdenk4b248f32004-03-14 16:51:43 +0000723 if (console_col < 0) {
724 console_col = CONSOLE_COLS - 1;
725 console_row--;
726 if (console_row < 0)
727 console_row = 0;
728 }
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000729 video_putchar(console_col * VIDEO_FONT_WIDTH,
730 console_row * VIDEO_FONT_HEIGHT, ' ');
wdenkc6097192002-11-03 00:24:07 +0000731}
732
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000733static void console_newline(void)
wdenkc6097192002-11-03 00:24:07 +0000734{
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100735 /* Check if last character in the line was just drawn. If so, cursor was
736 overwriten and need not to be cleared. Cursor clearing without this
737 check causes overwriting the 1st character of the line if line lenght
738 is >= CONSOLE_COLS
739 */
740 if (console_col < CONSOLE_COLS)
Timur Tabi65618632010-08-27 15:45:47 -0500741 CURSOR_OFF;
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100742 console_row++;
wdenk4b248f32004-03-14 16:51:43 +0000743 console_col = 0;
wdenkc6097192002-11-03 00:24:07 +0000744
wdenk4b248f32004-03-14 16:51:43 +0000745 /* Check if we need to scroll the terminal */
746 if (console_row >= CONSOLE_ROWS) {
747 /* Scroll everything up */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000748 console_scrollup();
wdenkc6097192002-11-03 00:24:07 +0000749
wdenk4b248f32004-03-14 16:51:43 +0000750 /* Decrement row number */
751 console_row--;
752 }
wdenkc6097192002-11-03 00:24:07 +0000753}
754
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000755static void console_cr(void)
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100756{
Timur Tabi65618632010-08-27 15:45:47 -0500757 CURSOR_OFF;
758 console_col = 0;
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100759}
760
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000761void video_putc(const char c)
wdenkc6097192002-11-03 00:24:07 +0000762{
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100763 static int nl = 1;
764
wdenk4b248f32004-03-14 16:51:43 +0000765 switch (c) {
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100766 case 13: /* back to first column */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000767 console_cr();
wdenk4b248f32004-03-14 16:51:43 +0000768 break;
wdenkc6097192002-11-03 00:24:07 +0000769
wdenk4b248f32004-03-14 16:51:43 +0000770 case '\n': /* next line */
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100771 if (console_col || (!console_col && nl))
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000772 console_newline();
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100773 nl = 1;
wdenk4b248f32004-03-14 16:51:43 +0000774 break;
wdenkc6097192002-11-03 00:24:07 +0000775
wdenk4b248f32004-03-14 16:51:43 +0000776 case 9: /* tab 8 */
Timur Tabi65618632010-08-27 15:45:47 -0500777 CURSOR_OFF;
778 console_col |= 0x0008;
wdenk4b248f32004-03-14 16:51:43 +0000779 console_col &= ~0x0007;
wdenkc6097192002-11-03 00:24:07 +0000780
wdenk4b248f32004-03-14 16:51:43 +0000781 if (console_col >= CONSOLE_COLS)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000782 console_newline();
wdenk4b248f32004-03-14 16:51:43 +0000783 break;
wdenkc6097192002-11-03 00:24:07 +0000784
wdenk4b248f32004-03-14 16:51:43 +0000785 case 8: /* backspace */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000786 console_back();
wdenk4b248f32004-03-14 16:51:43 +0000787 break;
wdenkc6097192002-11-03 00:24:07 +0000788
wdenk4b248f32004-03-14 16:51:43 +0000789 default: /* draw the char */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000790 video_putchar(console_col * VIDEO_FONT_WIDTH,
791 console_row * VIDEO_FONT_HEIGHT, c);
wdenk4b248f32004-03-14 16:51:43 +0000792 console_col++;
wdenkc6097192002-11-03 00:24:07 +0000793
wdenk4b248f32004-03-14 16:51:43 +0000794 /* check for newline */
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100795 if (console_col >= CONSOLE_COLS) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000796 console_newline();
Anatolij Gustschin20c450e2008-01-11 02:39:47 +0100797 nl = 0;
798 }
wdenk4b248f32004-03-14 16:51:43 +0000799 }
Timur Tabi65618632010-08-27 15:45:47 -0500800 CURSOR_SET;
801}
wdenkc6097192002-11-03 00:24:07 +0000802
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000803void video_puts(const char *s)
wdenkc6097192002-11-03 00:24:07 +0000804{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000805 int count = strlen(s);
wdenkc6097192002-11-03 00:24:07 +0000806
wdenk4b248f32004-03-14 16:51:43 +0000807 while (count--)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000808 video_putc(*s++);
wdenkc6097192002-11-03 00:24:07 +0000809}
810
Anatolij Gustschin10543822010-05-01 22:21:09 +0200811/*
812 * Do not enforce drivers (or board code) to provide empty
813 * video_set_lut() if they do not support 8 bpp format.
814 * Implement weak default function instead.
815 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000816void __video_set_lut(unsigned int index, unsigned char r,
817 unsigned char g, unsigned char b)
Anatolij Gustschin10543822010-05-01 22:21:09 +0200818{
819}
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000820
821void video_set_lut(unsigned int, unsigned char, unsigned char, unsigned char)
822 __attribute__ ((weak, alias("__video_set_lut")));
Anatolij Gustschin10543822010-05-01 22:21:09 +0200823
Jon Loeliger07d38a12007-07-09 17:30:01 -0500824#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenk4b248f32004-03-14 16:51:43 +0000825
826#define FILL_8BIT_332RGB(r,g,b) { \
827 *fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6); \
828 fb ++; \
829}
830
831#define FILL_15BIT_555RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000832 *(unsigned short *)fb = \
833 SWAP16((unsigned short)(((r>>3)<<10) | \
834 ((g>>3)<<5) | \
835 (b>>3))); \
wdenk4b248f32004-03-14 16:51:43 +0000836 fb += 2; \
837}
838
839#define FILL_16BIT_565RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000840 *(unsigned short *)fb = \
841 SWAP16((unsigned short)((((r)>>3)<<11)| \
842 (((g)>>2)<<5) | \
843 ((b)>>3))); \
wdenk4b248f32004-03-14 16:51:43 +0000844 fb += 2; \
845}
846
847#define FILL_32BIT_X888RGB(r,g,b) { \
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000848 *(unsigned long *)fb = \
849 SWAP32((unsigned long)(((r<<16) | \
850 (g<<8) | \
851 b))); \
wdenk4b248f32004-03-14 16:51:43 +0000852 fb += 4; \
853}
854
855#ifdef VIDEO_FB_LITTLE_ENDIAN
856#define FILL_24BIT_888RGB(r,g,b) { \
857 fb[0] = b; \
858 fb[1] = g; \
859 fb[2] = r; \
860 fb += 3; \
861}
862#else
863#define FILL_24BIT_888RGB(r,g,b) { \
864 fb[0] = r; \
865 fb[1] = g; \
866 fb[2] = b; \
867 fb += 3; \
868}
869#endif
870
Anatolij Gustschine84d5682008-08-08 18:00:40 +0200871#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000872static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
Anatolij Gustschine84d5682008-08-08 18:00:40 +0200873{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000874 ushort *dst = (ushort *) fb;
875 ushort color = (ushort) (((r >> 3) << 10) |
876 ((g >> 3) << 5) |
877 (b >> 3));
Anatolij Gustschine84d5682008-08-08 18:00:40 +0200878 if (x & 1)
879 *(--dst) = color;
880 else
881 *(++dst) = color;
882}
883#endif
wdenk4b248f32004-03-14 16:51:43 +0000884
885/*
Anatolij Gustschind5011762010-03-15 14:50:25 +0100886 * RLE8 bitmap support
887 */
888
889#ifdef CONFIG_VIDEO_BMP_RLE8
890/* Pre-calculated color table entry */
891struct palette {
892 union {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000893 unsigned short w; /* word */
894 unsigned int dw; /* double word */
895 } ce; /* color entry */
Anatolij Gustschind5011762010-03-15 14:50:25 +0100896};
897
898/*
899 * Helper to draw encoded/unencoded run.
900 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000901static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
902 int cnt, int enc)
Anatolij Gustschind5011762010-03-15 14:50:25 +0100903{
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000904 ulong addr = (ulong) *fb;
Anatolij Gustschind5011762010-03-15 14:50:25 +0100905 int *off;
906 int enc_off = 1;
907 int i;
908
909 /*
910 * Setup offset of the color index in the bitmap.
911 * Color index of encoded run is at offset 1.
912 */
913 off = enc ? &enc_off : &i;
914
915 switch (VIDEO_DATA_FORMAT) {
916 case GDF__8BIT_INDEX:
917 for (i = 0; i < cnt; i++)
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000918 *(unsigned char *) addr++ = bm[*off];
Anatolij Gustschind5011762010-03-15 14:50:25 +0100919 break;
920 case GDF_15BIT_555RGB:
921 case GDF_16BIT_565RGB:
922 /* differences handled while pre-calculating palette */
923 for (i = 0; i < cnt; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000924 *(unsigned short *) addr = p[bm[*off]].ce.w;
Anatolij Gustschind5011762010-03-15 14:50:25 +0100925 addr += 2;
926 }
927 break;
928 case GDF_32BIT_X888RGB:
929 for (i = 0; i < cnt; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000930 *(unsigned long *) addr = p[bm[*off]].ce.dw;
Anatolij Gustschind5011762010-03-15 14:50:25 +0100931 addr += 4;
932 }
933 break;
934 }
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000935 *fb = (uchar *) addr; /* return modified address */
Anatolij Gustschind5011762010-03-15 14:50:25 +0100936}
937
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000938static int display_rle8_bitmap(bmp_image_t *img, int xoff, int yoff,
939 int width, int height)
Anatolij Gustschind5011762010-03-15 14:50:25 +0100940{
941 unsigned char *bm;
942 unsigned char *fbp;
943 unsigned int cnt, runlen;
944 int decode = 1;
945 int x, y, bpp, i, ncolors;
946 struct palette p[256];
947 bmp_color_table_entry_t cte;
948 int green_shift, red_off;
Anatolij Gustschin74446b62011-02-21 21:33:29 +0100949 int limit = VIDEO_COLS * VIDEO_ROWS;
950 int pixels = 0;
Anatolij Gustschind5011762010-03-15 14:50:25 +0100951
952 x = 0;
953 y = __le32_to_cpu(img->header.height) - 1;
954 ncolors = __le32_to_cpu(img->header.colors_used);
955 bpp = VIDEO_PIXEL_SIZE;
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000956 fbp = (unsigned char *) ((unsigned int) video_fb_address +
957 (((y + yoff) * VIDEO_COLS) + xoff) * bpp);
Anatolij Gustschind5011762010-03-15 14:50:25 +0100958
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000959 bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
Anatolij Gustschind5011762010-03-15 14:50:25 +0100960
961 /* pre-calculate and setup palette */
962 switch (VIDEO_DATA_FORMAT) {
963 case GDF__8BIT_INDEX:
964 for (i = 0; i < ncolors; i++) {
965 cte = img->color_table[i];
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000966 video_set_lut(i, cte.red, cte.green, cte.blue);
Anatolij Gustschind5011762010-03-15 14:50:25 +0100967 }
968 break;
969 case GDF_15BIT_555RGB:
970 case GDF_16BIT_565RGB:
971 if (VIDEO_DATA_FORMAT == GDF_15BIT_555RGB) {
972 green_shift = 3;
973 red_off = 10;
974 } else {
975 green_shift = 2;
976 red_off = 11;
977 }
978 for (i = 0; i < ncolors; i++) {
979 cte = img->color_table[i];
980 p[i].ce.w = SWAP16((unsigned short)
981 (((cte.red >> 3) << red_off) |
982 ((cte.green >> green_shift) << 5) |
983 cte.blue >> 3));
984 }
985 break;
986 case GDF_32BIT_X888RGB:
987 for (i = 0; i < ncolors; i++) {
988 cte = img->color_table[i];
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000989 p[i].ce.dw = SWAP32((cte.red << 16) |
990 (cte.green << 8) |
Anatolij Gustschind5011762010-03-15 14:50:25 +0100991 cte.blue);
992 }
993 break;
994 default:
995 printf("RLE Bitmap unsupported in video mode 0x%x\n",
Wolfgang Denk64e40d72011-07-29 09:55:27 +0000996 VIDEO_DATA_FORMAT);
Anatolij Gustschind5011762010-03-15 14:50:25 +0100997 return -1;
998 }
999
1000 while (decode) {
1001 switch (bm[0]) {
1002 case 0:
1003 switch (bm[1]) {
1004 case 0:
1005 /* scan line end marker */
1006 bm += 2;
1007 x = 0;
1008 y--;
1009 fbp = (unsigned char *)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001010 ((unsigned int) video_fb_address +
Anatolij Gustschind5011762010-03-15 14:50:25 +01001011 (((y + yoff) * VIDEO_COLS) +
1012 xoff) * bpp);
1013 continue;
1014 case 1:
1015 /* end of bitmap data marker */
1016 decode = 0;
1017 break;
1018 case 2:
1019 /* run offset marker */
1020 x += bm[2];
1021 y -= bm[3];
1022 fbp = (unsigned char *)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001023 ((unsigned int) video_fb_address +
Anatolij Gustschind5011762010-03-15 14:50:25 +01001024 (((y + yoff) * VIDEO_COLS) +
1025 x + xoff) * bpp);
1026 bm += 4;
1027 break;
1028 default:
1029 /* unencoded run */
1030 cnt = bm[1];
1031 runlen = cnt;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001032 pixels += cnt;
1033 if (pixels > limit)
1034 goto error;
1035
Anatolij Gustschind5011762010-03-15 14:50:25 +01001036 bm += 2;
1037 if (y < height) {
1038 if (x >= width) {
1039 x += runlen;
1040 goto next_run;
1041 }
1042 if (x + runlen > width)
1043 cnt = width - x;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001044 draw_bitmap(&fbp, bm, p, cnt, 0);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001045 x += runlen;
1046 }
1047next_run:
1048 bm += runlen;
1049 if (runlen & 1)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001050 bm++; /* 0 padding if length is odd */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001051 }
1052 break;
1053 default:
1054 /* encoded run */
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001055 cnt = bm[0];
1056 runlen = cnt;
1057 pixels += cnt;
1058 if (pixels > limit)
1059 goto error;
1060
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001061 if (y < height) { /* only draw into visible area */
Anatolij Gustschind5011762010-03-15 14:50:25 +01001062 if (x >= width) {
1063 x += runlen;
1064 bm += 2;
1065 continue;
1066 }
1067 if (x + runlen > width)
1068 cnt = width - x;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001069 draw_bitmap(&fbp, bm, p, cnt, 1);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001070 x += runlen;
1071 }
1072 bm += 2;
1073 break;
1074 }
1075 }
1076 return 0;
Anatolij Gustschin74446b62011-02-21 21:33:29 +01001077error:
1078 printf("Error: Too much encoded pixel data, validate your bitmap\n");
1079 return -1;
Anatolij Gustschind5011762010-03-15 14:50:25 +01001080}
1081#endif
1082
1083/*
wdenk4b248f32004-03-14 16:51:43 +00001084 * Display the BMP file located at address bmp_image.
wdenk4b248f32004-03-14 16:51:43 +00001085 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001086int video_display_bitmap(ulong bmp_image, int x, int y)
wdenk4b248f32004-03-14 16:51:43 +00001087{
1088 ushort xcount, ycount;
1089 uchar *fb;
1090 bmp_image_t *bmp = (bmp_image_t *) bmp_image;
1091 uchar *bmap;
1092 ushort padded_line;
1093 unsigned long width, height, bpp;
1094 unsigned colors;
1095 unsigned long compression;
1096 bmp_color_table_entry_t cte;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001097
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001098#ifdef CONFIG_VIDEO_BMP_GZIP
1099 unsigned char *dst = NULL;
1100 ulong len;
1101#endif
wdenk4b248f32004-03-14 16:51:43 +00001102
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001103 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001104
1105 if (!((bmp->header.signature[0] == 'B') &&
1106 (bmp->header.signature[1] == 'M'))) {
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001107
1108#ifdef CONFIG_VIDEO_BMP_GZIP
1109 /*
1110 * Could be a gzipped bmp image, try to decrompress...
1111 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001112 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1113 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001114 if (dst == NULL) {
1115 printf("Error: malloc in gunzip failed!\n");
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001116 return 1;
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001117 }
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001118 if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE,
1119 (uchar *) bmp_image,
1120 &len) != 0) {
1121 printf("Error: no valid bmp or bmp.gz image at %lx\n",
1122 bmp_image);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001123 free(dst);
1124 return 1;
1125 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +02001126 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001127 printf("Image could be truncated "
1128 "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
Stefan Roesec29ab9d2005-10-08 10:19:07 +02001129 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001130
1131 /*
1132 * Set addr to decompressed image
1133 */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001134 bmp = (bmp_image_t *) dst;
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001135
1136 if (!((bmp->header.signature[0] == 'B') &&
1137 (bmp->header.signature[1] == 'M'))) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001138 printf("Error: no valid bmp.gz image at %lx\n",
1139 bmp_image);
Matthias Fuchsa49e0d12008-04-21 11:19:04 +02001140 free(dst);
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001141 return 1;
1142 }
1143#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001144 printf("Error: no valid bmp image at %lx\n", bmp_image);
wdenk4b248f32004-03-14 16:51:43 +00001145 return 1;
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001146#endif /* CONFIG_VIDEO_BMP_GZIP */
wdenk4b248f32004-03-14 16:51:43 +00001147 }
1148
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001149 width = le32_to_cpu(bmp->header.width);
1150 height = le32_to_cpu(bmp->header.height);
1151 bpp = le16_to_cpu(bmp->header.bit_count);
1152 colors = le32_to_cpu(bmp->header.colors_used);
1153 compression = le32_to_cpu(bmp->header.compression);
wdenk4b248f32004-03-14 16:51:43 +00001154
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001155 debug("Display-bmp: %d x %d with %d colors\n",
1156 width, height, colors);
wdenk4b248f32004-03-14 16:51:43 +00001157
Anatolij Gustschind5011762010-03-15 14:50:25 +01001158 if (compression != BMP_BI_RGB
1159#ifdef CONFIG_VIDEO_BMP_RLE8
1160 && compression != BMP_BI_RLE8
1161#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001162 ) {
1163 printf("Error: compression type %ld not supported\n",
1164 compression);
Matthias Fuchsa49e0d12008-04-21 11:19:04 +02001165#ifdef CONFIG_VIDEO_BMP_GZIP
1166 if (dst)
1167 free(dst);
1168#endif
wdenk4b248f32004-03-14 16:51:43 +00001169 return 1;
1170 }
1171
1172 padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1173
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001174#ifdef CONFIG_SPLASH_SCREEN_ALIGN
1175 if (x == BMP_ALIGN_CENTER)
1176 x = max(0, (VIDEO_VISIBLE_COLS - width) / 2);
1177 else if (x < 0)
1178 x = max(0, VIDEO_VISIBLE_COLS - width + x + 1);
1179
1180 if (y == BMP_ALIGN_CENTER)
1181 y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2);
1182 else if (y < 0)
1183 y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1);
1184#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1185
wdenk4b248f32004-03-14 16:51:43 +00001186 if ((x + width) > VIDEO_VISIBLE_COLS)
1187 width = VIDEO_VISIBLE_COLS - x;
1188 if ((y + height) > VIDEO_VISIBLE_ROWS)
1189 height = VIDEO_VISIBLE_ROWS - y;
1190
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001191 bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
wdenk4b248f32004-03-14 16:51:43 +00001192 fb = (uchar *) (video_fb_address +
1193 ((y + height - 1) * VIDEO_COLS * VIDEO_PIXEL_SIZE) +
1194 x * VIDEO_PIXEL_SIZE);
1195
Anatolij Gustschind5011762010-03-15 14:50:25 +01001196#ifdef CONFIG_VIDEO_BMP_RLE8
1197 if (compression == BMP_BI_RLE8) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001198 return display_rle8_bitmap(bmp, x, y, width, height);
Anatolij Gustschind5011762010-03-15 14:50:25 +01001199 }
1200#endif
1201
Timur Tabi68f66182010-08-23 16:58:00 -05001202 /* We handle only 4, 8, or 24 bpp bitmaps */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001203 switch (le16_to_cpu(bmp->header.bit_count)) {
Timur Tabi68f66182010-08-23 16:58:00 -05001204 case 4:
1205 padded_line -= width / 2;
1206 ycount = height;
1207
1208 switch (VIDEO_DATA_FORMAT) {
1209 case GDF_32BIT_X888RGB:
1210 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001211 WATCHDOG_RESET();
Timur Tabi68f66182010-08-23 16:58:00 -05001212 /*
1213 * Don't assume that 'width' is an
1214 * even number
1215 */
1216 for (xcount = 0; xcount < width; xcount++) {
1217 uchar idx;
1218
1219 if (xcount & 1) {
1220 idx = *bmap & 0xF;
1221 bmap++;
1222 } else
1223 idx = *bmap >> 4;
1224 cte = bmp->color_table[idx];
1225 FILL_32BIT_X888RGB(cte.red, cte.green,
1226 cte.blue);
1227 }
1228 bmap += padded_line;
1229 fb -= (VIDEO_VISIBLE_COLS + width) *
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001230 VIDEO_PIXEL_SIZE;
Timur Tabi68f66182010-08-23 16:58:00 -05001231 }
1232 break;
1233 default:
1234 puts("4bpp bitmap unsupported with current "
1235 "video mode\n");
1236 break;
1237 }
1238 break;
1239
wdenk4b248f32004-03-14 16:51:43 +00001240 case 8:
1241 padded_line -= width;
1242 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001243 /* Copy colormap */
wdenk4b248f32004-03-14 16:51:43 +00001244 for (xcount = 0; xcount < colors; ++xcount) {
1245 cte = bmp->color_table[xcount];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001246 video_set_lut(xcount, cte.red, cte.green,
1247 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001248 }
1249 }
1250 ycount = height;
1251 switch (VIDEO_DATA_FORMAT) {
1252 case GDF__8BIT_INDEX:
1253 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001254 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001255 xcount = width;
1256 while (xcount--) {
1257 *fb++ = *bmap++;
1258 }
1259 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001260 fb -= (VIDEO_VISIBLE_COLS + width) *
1261 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001262 }
1263 break;
1264 case GDF__8BIT_332RGB:
1265 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001266 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001267 xcount = width;
1268 while (xcount--) {
1269 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001270 FILL_8BIT_332RGB(cte.red, cte.green,
1271 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001272 }
1273 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001274 fb -= (VIDEO_VISIBLE_COLS + width) *
1275 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001276 }
1277 break;
1278 case GDF_15BIT_555RGB:
1279 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001280#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1281 int xpos = x;
1282#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001283 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001284 xcount = width;
1285 while (xcount--) {
1286 cte = bmp->color_table[*bmap++];
Andrew Dyercc347802008-08-29 12:30:39 -05001287#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001288 fill_555rgb_pswap(fb, xpos++, cte.red,
1289 cte.green,
1290 cte.blue);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001291 fb += 2;
Andrew Dyercc347802008-08-29 12:30:39 -05001292#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001293 FILL_15BIT_555RGB(cte.red, cte.green,
1294 cte.blue);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001295#endif
wdenk4b248f32004-03-14 16:51:43 +00001296 }
1297 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001298 fb -= (VIDEO_VISIBLE_COLS + width) *
1299 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001300 }
1301 break;
1302 case GDF_16BIT_565RGB:
1303 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001304 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001305 xcount = width;
1306 while (xcount--) {
1307 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001308 FILL_16BIT_565RGB(cte.red, cte.green,
1309 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001310 }
1311 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001312 fb -= (VIDEO_VISIBLE_COLS + width) *
1313 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001314 }
1315 break;
1316 case GDF_32BIT_X888RGB:
1317 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001318 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001319 xcount = width;
1320 while (xcount--) {
1321 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001322 FILL_32BIT_X888RGB(cte.red, cte.green,
1323 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001324 }
1325 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001326 fb -= (VIDEO_VISIBLE_COLS + width) *
1327 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001328 }
1329 break;
1330 case GDF_24BIT_888RGB:
1331 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001332 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001333 xcount = width;
1334 while (xcount--) {
1335 cte = bmp->color_table[*bmap++];
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001336 FILL_24BIT_888RGB(cte.red, cte.green,
1337 cte.blue);
wdenk4b248f32004-03-14 16:51:43 +00001338 }
1339 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001340 fb -= (VIDEO_VISIBLE_COLS + width) *
1341 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001342 }
1343 break;
1344 }
1345 break;
1346 case 24:
1347 padded_line -= 3 * width;
1348 ycount = height;
1349 switch (VIDEO_DATA_FORMAT) {
1350 case GDF__8BIT_332RGB:
1351 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001352 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001353 xcount = width;
1354 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001355 FILL_8BIT_332RGB(bmap[2], bmap[1],
1356 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001357 bmap += 3;
1358 }
1359 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001360 fb -= (VIDEO_VISIBLE_COLS + width) *
1361 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001362 }
1363 break;
1364 case GDF_15BIT_555RGB:
1365 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001366#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1367 int xpos = x;
1368#endif
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001369 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001370 xcount = width;
1371 while (xcount--) {
Andrew Dyercc347802008-08-29 12:30:39 -05001372#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001373 fill_555rgb_pswap(fb, xpos++, bmap[2],
1374 bmap[1], bmap[0]);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001375 fb += 2;
Andrew Dyercc347802008-08-29 12:30:39 -05001376#else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001377 FILL_15BIT_555RGB(bmap[2], bmap[1],
1378 bmap[0]);
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001379#endif
wdenk4b248f32004-03-14 16:51:43 +00001380 bmap += 3;
1381 }
1382 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001383 fb -= (VIDEO_VISIBLE_COLS + width) *
1384 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001385 }
1386 break;
1387 case GDF_16BIT_565RGB:
1388 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001389 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001390 xcount = width;
1391 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001392 FILL_16BIT_565RGB(bmap[2], bmap[1],
1393 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001394 bmap += 3;
1395 }
1396 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001397 fb -= (VIDEO_VISIBLE_COLS + width) *
1398 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001399 }
1400 break;
1401 case GDF_32BIT_X888RGB:
1402 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001403 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001404 xcount = width;
1405 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001406 FILL_32BIT_X888RGB(bmap[2], bmap[1],
1407 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001408 bmap += 3;
1409 }
1410 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001411 fb -= (VIDEO_VISIBLE_COLS + width) *
1412 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001413 }
1414 break;
1415 case GDF_24BIT_888RGB:
1416 while (ycount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001417 WATCHDOG_RESET();
wdenk4b248f32004-03-14 16:51:43 +00001418 xcount = width;
1419 while (xcount--) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001420 FILL_24BIT_888RGB(bmap[2], bmap[1],
1421 bmap[0]);
wdenk4b248f32004-03-14 16:51:43 +00001422 bmap += 3;
1423 }
1424 bmap += padded_line;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001425 fb -= (VIDEO_VISIBLE_COLS + width) *
1426 VIDEO_PIXEL_SIZE;
wdenk4b248f32004-03-14 16:51:43 +00001427 }
1428 break;
1429 default:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001430 printf("Error: 24 bits/pixel bitmap incompatible "
1431 "with current video mode\n");
wdenk4b248f32004-03-14 16:51:43 +00001432 break;
1433 }
1434 break;
1435 default:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001436 printf("Error: %d bit/pixel bitmaps not supported by U-Boot\n",
1437 le16_to_cpu(bmp->header.bit_count));
wdenk4b248f32004-03-14 16:51:43 +00001438 break;
1439 }
Stefan Roese98f4a3d2005-09-22 09:04:17 +02001440
1441#ifdef CONFIG_VIDEO_BMP_GZIP
1442 if (dst) {
1443 free(dst);
1444 }
1445#endif
1446
wdenk4b248f32004-03-14 16:51:43 +00001447 return (0);
1448}
Jon Loeliger07d38a12007-07-09 17:30:01 -05001449#endif
wdenk4b248f32004-03-14 16:51:43 +00001450
wdenk4b248f32004-03-14 16:51:43 +00001451
wdenkc6097192002-11-03 00:24:07 +00001452#ifdef CONFIG_VIDEO_LOGO
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001453void logo_plot(void *screen, int width, int x, int y)
wdenkc6097192002-11-03 00:24:07 +00001454{
wdenkc6097192002-11-03 00:24:07 +00001455
wdenk4b248f32004-03-14 16:51:43 +00001456 int xcount, i;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001457 int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
Matthias Weisserbe129aa2010-01-12 12:06:31 +01001458 int ycount = video_logo_height;
wdenk4b248f32004-03-14 16:51:43 +00001459 unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1460 unsigned char *source;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001461 unsigned char *dest = (unsigned char *) screen +
1462 ((y * width * VIDEO_PIXEL_SIZE) + x * VIDEO_PIXEL_SIZE);
wdenka6c7ad22002-12-03 21:28:10 +00001463
1464#ifdef CONFIG_VIDEO_BMP_LOGO
wdenk4b248f32004-03-14 16:51:43 +00001465 source = bmp_logo_bitmap;
wdenk8bde7f72003-06-27 21:31:46 +00001466
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001467 /* Allocate temporary space for computing colormap */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001468 logo_red = malloc(BMP_LOGO_COLORS);
1469 logo_green = malloc(BMP_LOGO_COLORS);
1470 logo_blue = malloc(BMP_LOGO_COLORS);
Anatolij Gustschin7c050f82010-06-19 20:41:56 +02001471 /* Compute color map */
wdenk4b248f32004-03-14 16:51:43 +00001472 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
1473 logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
1474 logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
1475 logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
1476 }
wdenka6c7ad22002-12-03 21:28:10 +00001477#else
wdenk4b248f32004-03-14 16:51:43 +00001478 source = linux_logo;
1479 logo_red = linux_logo_red;
1480 logo_green = linux_logo_green;
1481 logo_blue = linux_logo_blue;
wdenka6c7ad22002-12-03 21:28:10 +00001482#endif
wdenk8bde7f72003-06-27 21:31:46 +00001483
wdenk4b248f32004-03-14 16:51:43 +00001484 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1485 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001486 video_set_lut(i + VIDEO_LOGO_LUT_OFFSET,
1487 logo_red[i], logo_green[i],
1488 logo_blue[i]);
wdenk4b248f32004-03-14 16:51:43 +00001489 }
wdenk8bde7f72003-06-27 21:31:46 +00001490 }
wdenkc6097192002-11-03 00:24:07 +00001491
wdenk4b248f32004-03-14 16:51:43 +00001492 while (ycount--) {
Anatolij Gustschine84d5682008-08-08 18:00:40 +02001493#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1494 int xpos = x;
1495#endif
wdenk4b248f32004-03-14 16:51:43 +00001496 xcount = VIDEO_LOGO_WIDTH;
1497 while (xcount--) {
1498 r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
1499 g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
1500 b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
wdenk8bde7f72003-06-27 21:31:46 +00001501
wdenk4b248f32004-03-14 16:51:43 +00001502 switch (VIDEO_DATA_FORMAT) {
1503 case GDF__8BIT_INDEX:
1504 *dest = *source;
1505 break;
1506 case GDF__8BIT_332RGB:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001507 *dest = ((r >> 5) << 5) |
1508 ((g >> 5) << 2) |
1509 (b >> 6);
wdenk4b248f32004-03-14 16:51:43 +00001510 break;
1511 case GDF_15BIT_555RGB:
Andrew Dyercc347802008-08-29 12:30:39 -05001512#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001513 fill_555rgb_pswap(dest, xpos++, r, g, b);
Andrew Dyercc347802008-08-29 12:30:39 -05001514#else
wdenk4b248f32004-03-14 16:51:43 +00001515 *(unsigned short *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001516 SWAP16((unsigned short) (
1517 ((r >> 3) << 10) |
1518 ((g >> 3) << 5) |
1519 (b >> 3)));
Anatolij Gustschinbed53752008-01-11 14:30:01 +01001520#endif
wdenk4b248f32004-03-14 16:51:43 +00001521 break;
1522 case GDF_16BIT_565RGB:
1523 *(unsigned short *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001524 SWAP16((unsigned short) (
1525 ((r >> 3) << 11) |
1526 ((g >> 2) << 5) |
1527 (b >> 3)));
wdenk4b248f32004-03-14 16:51:43 +00001528 break;
1529 case GDF_32BIT_X888RGB:
1530 *(unsigned long *) dest =
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001531 SWAP32((unsigned long) (
1532 (r << 16) |
1533 (g << 8) |
1534 b));
wdenk4b248f32004-03-14 16:51:43 +00001535 break;
1536 case GDF_24BIT_888RGB:
wdenkc6097192002-11-03 00:24:07 +00001537#ifdef VIDEO_FB_LITTLE_ENDIAN
wdenk4b248f32004-03-14 16:51:43 +00001538 dest[0] = b;
1539 dest[1] = g;
1540 dest[2] = r;
wdenkc6097192002-11-03 00:24:07 +00001541#else
wdenk4b248f32004-03-14 16:51:43 +00001542 dest[0] = r;
1543 dest[1] = g;
1544 dest[2] = b;
wdenkc6097192002-11-03 00:24:07 +00001545#endif
wdenk4b248f32004-03-14 16:51:43 +00001546 break;
1547 }
1548 source++;
1549 dest += VIDEO_PIXEL_SIZE;
1550 }
1551 dest += skip;
wdenk8bde7f72003-06-27 21:31:46 +00001552 }
wdenka6c7ad22002-12-03 21:28:10 +00001553#ifdef CONFIG_VIDEO_BMP_LOGO
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001554 free(logo_red);
1555 free(logo_green);
1556 free(logo_blue);
wdenka6c7ad22002-12-03 21:28:10 +00001557#endif
wdenkc6097192002-11-03 00:24:07 +00001558}
1559
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001560static void *video_logo(void)
wdenkc6097192002-11-03 00:24:07 +00001561{
wdenk4b248f32004-03-14 16:51:43 +00001562 char info[128];
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001563 int space, len, y_off = 0;
wdenkc6097192002-11-03 00:24:07 +00001564
wdenk4b248f32004-03-14 16:51:43 +00001565#ifdef CONFIG_SPLASH_SCREEN
1566 char *s;
1567 ulong addr;
wdenkc6097192002-11-03 00:24:07 +00001568
Wolfgang Denk57912932011-07-30 12:48:09 +00001569 s = getenv("splashimage");
1570 if (s != NULL) {
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001571 int x = 0, y = 0;
wdenk4b248f32004-03-14 16:51:43 +00001572
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001573 addr = simple_strtoul(s, NULL, 16);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001574#ifdef CONFIG_SPLASH_SCREEN_ALIGN
Wolfgang Denk57912932011-07-30 12:48:09 +00001575 s = getenv("splashpos");
1576 if (s != NULL) {
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001577 if (s[0] == 'm')
1578 x = BMP_ALIGN_CENTER;
1579 else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001580 x = simple_strtol(s, NULL, 0);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001581
Wolfgang Denk57912932011-07-30 12:48:09 +00001582 s = strchr(s + 1, ',');
1583 if (s != NULL) {
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001584 if (s[1] == 'm')
1585 y = BMP_ALIGN_CENTER;
1586 else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001587 y = simple_strtol(s + 1, NULL, 0);
Matthias Weisser1ca298c2009-07-09 16:07:30 +02001588 }
1589 }
1590#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
1591
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001592 if (video_display_bitmap(addr, x, y) == 0) {
Matthias Weisserbe129aa2010-01-12 12:06:31 +01001593 video_logo_height = 0;
wdenk4b248f32004-03-14 16:51:43 +00001594 return ((void *) (video_fb_address));
1595 }
1596 }
1597#endif /* CONFIG_SPLASH_SCREEN */
1598
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001599 logo_plot(video_fb_address, VIDEO_COLS, 0, 0);
wdenk4b248f32004-03-14 16:51:43 +00001600
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001601 sprintf(info, " %s", version_string);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001602
1603 space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1604 len = strlen(info);
1605
1606 if (len > space) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001607 video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1608 (uchar *) info, space);
1609 video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1610 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
1611 (uchar *) info + space, len - space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001612 y_off = 1;
1613 } else
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001614 video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
wdenkc6097192002-11-03 00:24:07 +00001615
1616#ifdef CONFIG_CONSOLE_EXTRA_INFO
wdenk4b248f32004-03-14 16:51:43 +00001617 {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001618 int i, n =
1619 ((video_logo_height -
1620 VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00001621
wdenk4b248f32004-03-14 16:51:43 +00001622 for (i = 1; i < n; i++) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001623 video_get_info_str(i, info);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001624 if (!*info)
1625 continue;
1626
1627 len = strlen(info);
1628 if (len > space) {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001629 video_drawchars(VIDEO_INFO_X,
1630 VIDEO_INFO_Y +
1631 (i + y_off) *
1632 VIDEO_FONT_HEIGHT,
1633 (uchar *) info, space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001634 y_off++;
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001635 video_drawchars(VIDEO_INFO_X +
1636 VIDEO_FONT_WIDTH,
1637 VIDEO_INFO_Y +
1638 (i + y_off) *
1639 VIDEO_FONT_HEIGHT,
1640 (uchar *) info + space,
1641 len - space);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001642 } else {
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001643 video_drawstring(VIDEO_INFO_X,
1644 VIDEO_INFO_Y +
1645 (i + y_off) *
1646 VIDEO_FONT_HEIGHT,
1647 (uchar *) info);
Anatolij Gustschin3dcbe622009-04-23 12:35:22 +02001648 }
wdenk4b248f32004-03-14 16:51:43 +00001649 }
1650 }
wdenkc6097192002-11-03 00:24:07 +00001651#endif
1652
Matthias Weisserbe129aa2010-01-12 12:06:31 +01001653 return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
wdenkc6097192002-11-03 00:24:07 +00001654}
1655#endif
1656
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001657static int video_init(void)
wdenkc6097192002-11-03 00:24:07 +00001658{
wdenk4b248f32004-03-14 16:51:43 +00001659 unsigned char color8;
wdenkc6097192002-11-03 00:24:07 +00001660
Wolfgang Denk57912932011-07-30 12:48:09 +00001661 pGD = video_hw_init();
1662 if (pGD == NULL)
wdenk4b248f32004-03-14 16:51:43 +00001663 return -1;
wdenkc6097192002-11-03 00:24:07 +00001664
wdenk4b248f32004-03-14 16:51:43 +00001665 video_fb_address = (void *) VIDEO_FB_ADRS;
wdenkc6097192002-11-03 00:24:07 +00001666#ifdef CONFIG_VIDEO_HW_CURSOR
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001667 video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00001668#endif
1669
wdenk4b248f32004-03-14 16:51:43 +00001670 /* Init drawing pats */
1671 switch (VIDEO_DATA_FORMAT) {
1672 case GDF__8BIT_INDEX:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001673 video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL,
1674 CONSOLE_FG_COL);
1675 video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL,
1676 CONSOLE_BG_COL);
wdenk4b248f32004-03-14 16:51:43 +00001677 fgx = 0x01010101;
1678 bgx = 0x00000000;
1679 break;
1680 case GDF__8BIT_332RGB:
1681 color8 = ((CONSOLE_FG_COL & 0xe0) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001682 ((CONSOLE_FG_COL >> 3) & 0x1c) |
1683 CONSOLE_FG_COL >> 6);
1684 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1685 color8;
wdenk4b248f32004-03-14 16:51:43 +00001686 color8 = ((CONSOLE_BG_COL & 0xe0) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001687 ((CONSOLE_BG_COL >> 3) & 0x1c) |
1688 CONSOLE_BG_COL >> 6);
1689 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1690 color8;
wdenk4b248f32004-03-14 16:51:43 +00001691 break;
1692 case GDF_15BIT_555RGB:
1693 fgx = (((CONSOLE_FG_COL >> 3) << 26) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001694 ((CONSOLE_FG_COL >> 3) << 21) |
1695 ((CONSOLE_FG_COL >> 3) << 16) |
1696 ((CONSOLE_FG_COL >> 3) << 10) |
1697 ((CONSOLE_FG_COL >> 3) << 5) |
1698 (CONSOLE_FG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00001699 bgx = (((CONSOLE_BG_COL >> 3) << 26) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001700 ((CONSOLE_BG_COL >> 3) << 21) |
1701 ((CONSOLE_BG_COL >> 3) << 16) |
1702 ((CONSOLE_BG_COL >> 3) << 10) |
1703 ((CONSOLE_BG_COL >> 3) << 5) |
1704 (CONSOLE_BG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00001705 break;
1706 case GDF_16BIT_565RGB:
1707 fgx = (((CONSOLE_FG_COL >> 3) << 27) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001708 ((CONSOLE_FG_COL >> 2) << 21) |
1709 ((CONSOLE_FG_COL >> 3) << 16) |
1710 ((CONSOLE_FG_COL >> 3) << 11) |
1711 ((CONSOLE_FG_COL >> 2) << 5) |
1712 (CONSOLE_FG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00001713 bgx = (((CONSOLE_BG_COL >> 3) << 27) |
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001714 ((CONSOLE_BG_COL >> 2) << 21) |
1715 ((CONSOLE_BG_COL >> 3) << 16) |
1716 ((CONSOLE_BG_COL >> 3) << 11) |
1717 ((CONSOLE_BG_COL >> 2) << 5) |
1718 (CONSOLE_BG_COL >> 3));
wdenk4b248f32004-03-14 16:51:43 +00001719 break;
1720 case GDF_32BIT_X888RGB:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001721 fgx = (CONSOLE_FG_COL << 16) |
1722 (CONSOLE_FG_COL << 8) |
1723 CONSOLE_FG_COL;
1724 bgx = (CONSOLE_BG_COL << 16) |
1725 (CONSOLE_BG_COL << 8) |
1726 CONSOLE_BG_COL;
wdenk4b248f32004-03-14 16:51:43 +00001727 break;
1728 case GDF_24BIT_888RGB:
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001729 fgx = (CONSOLE_FG_COL << 24) |
1730 (CONSOLE_FG_COL << 16) |
1731 (CONSOLE_FG_COL << 8) |
1732 CONSOLE_FG_COL;
1733 bgx = (CONSOLE_BG_COL << 24) |
1734 (CONSOLE_BG_COL << 16) |
1735 (CONSOLE_BG_COL << 8) |
1736 CONSOLE_BG_COL;
wdenk4b248f32004-03-14 16:51:43 +00001737 break;
1738 }
1739 eorx = fgx ^ bgx;
wdenkc6097192002-11-03 00:24:07 +00001740
1741#ifdef CONFIG_VIDEO_LOGO
wdenk4b248f32004-03-14 16:51:43 +00001742 /* Plot the logo and get start point of console */
Wolfgang Denk72c65f62011-07-29 09:55:28 +00001743 debug("Video: Drawing the logo ...\n");
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001744 video_console_address = video_logo();
wdenkc6097192002-11-03 00:24:07 +00001745#else
wdenk4b248f32004-03-14 16:51:43 +00001746 video_console_address = video_fb_address;
wdenkc6097192002-11-03 00:24:07 +00001747#endif
1748
wdenk4b248f32004-03-14 16:51:43 +00001749 /* Initialize the console */
1750 console_col = 0;
1751 console_row = 0;
wdenkc6097192002-11-03 00:24:07 +00001752
wdenk4b248f32004-03-14 16:51:43 +00001753 return 0;
wdenkc6097192002-11-03 00:24:07 +00001754}
1755
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02001756/*
1757 * Implement a weak default function for boards that optionally
1758 * need to skip the video initialization.
1759 */
1760int __board_video_skip(void)
1761{
1762 /* As default, don't skip test */
1763 return 0;
1764}
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02001765
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001766int board_video_skip(void)
1767 __attribute__ ((weak, alias("__board_video_skip")));
1768
1769int drv_video_init(void)
wdenkc6097192002-11-03 00:24:07 +00001770{
wdenk4b248f32004-03-14 16:51:43 +00001771 int skip_dev_init;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02001772 struct stdio_dev console_dev;
wdenkc6097192002-11-03 00:24:07 +00001773
Wolfgang Denk6cc7ba92009-05-15 10:07:43 +02001774 /* Check if video initialization should be skipped */
1775 if (board_video_skip())
1776 return 0;
1777
wdenk81050922004-07-11 20:04:51 +00001778 /* Init video chip - returns with framebuffer cleared */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001779 skip_dev_init = (video_init() == -1);
wdenk81050922004-07-11 20:04:51 +00001780
Wolfgang Denkf62f6462009-05-15 10:07:42 +02001781#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
Wolfgang Denk72c65f62011-07-29 09:55:28 +00001782 debug("KBD: Keyboard init ...\n");
Wolfgang Denkf62f6462009-05-15 10:07:42 +02001783 skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
1784#endif
wdenkc6097192002-11-03 00:24:07 +00001785
Wolfgang Denkf62f6462009-05-15 10:07:42 +02001786 if (skip_dev_init)
1787 return 0;
wdenkc6097192002-11-03 00:24:07 +00001788
Wolfgang Denkf62f6462009-05-15 10:07:42 +02001789 /* Init vga device */
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001790 memset(&console_dev, 0, sizeof(console_dev));
1791 strcpy(console_dev.name, "vga");
Wolfgang Denkf62f6462009-05-15 10:07:42 +02001792 console_dev.ext = DEV_EXT_VIDEO; /* Video extensions */
1793 console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
1794 console_dev.putc = video_putc; /* 'putc' function */
1795 console_dev.puts = video_puts; /* 'puts' function */
1796 console_dev.tstc = NULL; /* 'tstc' function */
1797 console_dev.getc = NULL; /* 'getc' function */
1798
1799#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1800 /* Also init console device */
1801 console_dev.flags |= DEV_FLAGS_INPUT;
1802 console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */
1803 console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */
wdenkc6097192002-11-03 00:24:07 +00001804#endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
Wolfgang Denkf62f6462009-05-15 10:07:42 +02001805
Wolfgang Denk64e40d72011-07-29 09:55:27 +00001806 if (stdio_register(&console_dev) != 0)
Wolfgang Denkf62f6462009-05-15 10:07:42 +02001807 return 0;
1808
1809 /* Return success */
1810 return 1;
wdenkc6097192002-11-03 00:24:07 +00001811}