blob: 917bba6398507528ffcac2f9212bde055207b5d8 [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
wdenke55402c2004-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 Denk0b4b56e2011-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 Denk0b4b56e2011-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ßmann61d01952011-07-18 20:24:04 +0200102#include <version.h>
wdenk9dd2b882002-12-03 21:28:10 +0000103#include <malloc.h>
104
Wolfgang Denk0b4b56e2011-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
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000117/*
118 * Defines for the CT69000 driver
119 */
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000127/*
128 * Defines for the SED13806 driver
129 */
wdenk9dd2b882002-12-03 21:28:10 +0000130#ifdef CONFIG_VIDEO_SED13806
131
wdenkda54bc92004-08-04 21:56:49 +0000132#ifndef CONFIG_TOTAL5200
wdenk9dd2b882002-12-03 21:28:10 +0000133#define VIDEO_FB_LITTLE_ENDIAN
wdenkda54bc92004-08-04 21:56:49 +0000134#endif
wdenk9dd2b882002-12-03 21:28:10 +0000135#define VIDEO_HW_RECTFILL
136#define VIDEO_HW_BITBLT
137#endif
138
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000139/*
140 * Defines for the SED13806 driver
141 */
Stefan Roesed9d97742005-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 Denk0b4b56e2011-07-29 09:55:27 +0000149/*
150 * Defines for the MB862xx driver
151 */
Anatolij Gustschin3545f592008-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 Gustschine7e44a02009-10-23 12:03:14 +0200157#ifdef CONFIG_VIDEO_MB862xx_ACCEL
Anatolij Gustschin3545f592008-01-11 14:30:01 +0100158#define VIDEO_HW_RECTFILL
159#define VIDEO_HW_BITBLT
160#endif
Anatolij Gustschine7e44a02009-10-23 12:03:14 +0200161#endif
Anatolij Gustschin3545f592008-01-11 14:30:01 +0100162
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000163/*
164 * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc.
165 */
wdenkc6097192002-11-03 00:24:07 +0000166#include <video_fb.h>
167
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000168/*
169 * some Macros
170 */
wdenke55402c2004-03-14 16:51:43 +0000171#define VIDEO_VISIBLE_COLS (pGD->winSizeX)
172#define VIDEO_VISIBLE_ROWS (pGD->winSizeY)
173#define VIDEO_PIXEL_SIZE (pGD->gdfBytesPP)
174#define VIDEO_DATA_FORMAT (pGD->gdfIndex)
175#define VIDEO_FB_ADRS (pGD->frameAdrs)
wdenkc6097192002-11-03 00:24:07 +0000176
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000177/*
178 * Console device defines with i8042 keyboard controller
179 * Any other keyboard controller must change this section
180 */
wdenkc6097192002-11-03 00:24:07 +0000181
wdenke55402c2004-03-14 16:51:43 +0000182#ifdef CONFIG_I8042_KBD
wdenkc6097192002-11-03 00:24:07 +0000183#include <i8042.h>
184
wdenke55402c2004-03-14 16:51:43 +0000185#define VIDEO_KBD_INIT_FCT i8042_kbd_init()
186#define VIDEO_TSTC_FCT i8042_tstc
187#define VIDEO_GETC_FCT i8042_getc
wdenkc6097192002-11-03 00:24:07 +0000188#endif
189
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000190/*
191 * Console device
192 */
wdenkc6097192002-11-03 00:24:07 +0000193
194#include <version.h>
195#include <linux/types.h>
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200196#include <stdio_dev.h>
wdenkc6097192002-11-03 00:24:07 +0000197#include <video_font.h>
wdenkc6097192002-11-03 00:24:07 +0000198
Jon Loeliger30c2f242007-07-10 11:13:21 -0500199#if defined(CONFIG_CMD_DATE)
200#include <rtc.h>
wdenkc6097192002-11-03 00:24:07 +0000201#endif
202
Jon Loeligerb1d408a2007-07-09 17:30:01 -0500203#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenke55402c2004-03-14 16:51:43 +0000204#include <watchdog.h>
205#include <bmp_layout.h>
Matthias Weisser53884182009-07-09 16:07:30 +0200206
207#ifdef CONFIG_SPLASH_SCREEN_ALIGN
208#define BMP_ALIGN_CENTER 0x7FFF
209#endif
210
Jon Loeligerb1d408a2007-07-09 17:30:01 -0500211#endif
wdenke55402c2004-03-14 16:51:43 +0000212
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000213/*
214 * Cursor definition:
215 * CONFIG_CONSOLE_CURSOR: Uses a timer function (see drivers/input/i8042.c)
216 * to let the cursor blink. Uses the macros
217 * CURSOR_OFF and CURSOR_ON.
218 * CONFIG_VIDEO_SW_CURSOR: Draws a cursor after the last character. No
219 * blinking is provided. Uses the macros CURSOR_SET
220 * and CURSOR_OFF.
221 * CONFIG_VIDEO_HW_CURSOR: Uses the hardware cursor capability of the
222 * graphic chip. Uses the macro CURSOR_SET.
223 * ATTENTION: If booting an OS, the display driver
224 * must disable the hardware register of the graphic
225 * chip. Otherwise a blinking field is displayed
226 */
wdenkc6097192002-11-03 00:24:07 +0000227#if !defined(CONFIG_CONSOLE_CURSOR) && \
228 !defined(CONFIG_VIDEO_SW_CURSOR) && \
229 !defined(CONFIG_VIDEO_HW_CURSOR)
230/* no Cursor defined */
231#define CURSOR_ON
232#define CURSOR_OFF
233#define CURSOR_SET
234#endif
235
wdenke55402c2004-03-14 16:51:43 +0000236#ifdef CONFIG_CONSOLE_CURSOR
237#ifdef CURSOR_ON
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000238#error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
239 or CONFIG_VIDEO_HW_CURSOR can be defined
wdenkc6097192002-11-03 00:24:07 +0000240#endif
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000241void console_cursor(int state);
242
Timur Tabibe0c74e2010-08-27 15:45:47 -0500243#define CURSOR_ON console_cursor(1)
244#define CURSOR_OFF console_cursor(0)
wdenkc6097192002-11-03 00:24:07 +0000245#define CURSOR_SET
246#ifndef CONFIG_I8042_KBD
Marcel Ziswileraea68562007-12-30 03:30:46 +0100247#warning Cursor drawing on/off needs timer function s.a. drivers/input/i8042.c
wdenkc6097192002-11-03 00:24:07 +0000248#endif
249#else
wdenke55402c2004-03-14 16:51:43 +0000250#ifdef CONFIG_CONSOLE_TIME
251#error CONFIG_CONSOLE_CURSOR must be defined for CONFIG_CONSOLE_TIME
wdenkc6097192002-11-03 00:24:07 +0000252#endif
253#endif /* CONFIG_CONSOLE_CURSOR */
254
wdenke55402c2004-03-14 16:51:43 +0000255#ifdef CONFIG_VIDEO_SW_CURSOR
256#ifdef CURSOR_ON
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000257#error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
258 or CONFIG_VIDEO_HW_CURSOR can be defined
wdenkc6097192002-11-03 00:24:07 +0000259#endif
260#define CURSOR_ON
261#define CURSOR_OFF video_putchar(console_col * VIDEO_FONT_WIDTH,\
Timur Tabibe0c74e2010-08-27 15:45:47 -0500262 console_row * VIDEO_FONT_HEIGHT, ' ')
263#define CURSOR_SET video_set_cursor()
wdenkc6097192002-11-03 00:24:07 +0000264#endif /* CONFIG_VIDEO_SW_CURSOR */
265
266
267#ifdef CONFIG_VIDEO_HW_CURSOR
wdenke55402c2004-03-14 16:51:43 +0000268#ifdef CURSOR_ON
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000269#error only one of CONFIG_CONSOLE_CURSOR, CONFIG_VIDEO_SW_CURSOR, \
270 or CONFIG_VIDEO_HW_CURSOR can be defined
wdenkc6097192002-11-03 00:24:07 +0000271#endif
272#define CURSOR_ON
273#define CURSOR_OFF
274#define CURSOR_SET video_set_hw_cursor(console_col * VIDEO_FONT_WIDTH, \
Timur Tabibe0c74e2010-08-27 15:45:47 -0500275 (console_row * VIDEO_FONT_HEIGHT) + video_logo_height)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000276#endif /* CONFIG_VIDEO_HW_CURSOR */
wdenkc6097192002-11-03 00:24:07 +0000277
wdenke55402c2004-03-14 16:51:43 +0000278#ifdef CONFIG_VIDEO_LOGO
279#ifdef CONFIG_VIDEO_BMP_LOGO
wdenk9dd2b882002-12-03 21:28:10 +0000280#include <bmp_logo.h>
wdenke55402c2004-03-14 16:51:43 +0000281#define VIDEO_LOGO_WIDTH BMP_LOGO_WIDTH
282#define VIDEO_LOGO_HEIGHT BMP_LOGO_HEIGHT
283#define VIDEO_LOGO_LUT_OFFSET BMP_LOGO_OFFSET
284#define VIDEO_LOGO_COLORS BMP_LOGO_COLORS
wdenk9dd2b882002-12-03 21:28:10 +0000285
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000286#else /* CONFIG_VIDEO_BMP_LOGO */
wdenke55402c2004-03-14 16:51:43 +0000287#define LINUX_LOGO_WIDTH 80
288#define LINUX_LOGO_HEIGHT 80
289#define LINUX_LOGO_COLORS 214
290#define LINUX_LOGO_LUT_OFFSET 0x20
wdenkc6097192002-11-03 00:24:07 +0000291#define __initdata
292#include <linux_logo.h>
wdenke55402c2004-03-14 16:51:43 +0000293#define VIDEO_LOGO_WIDTH LINUX_LOGO_WIDTH
294#define VIDEO_LOGO_HEIGHT LINUX_LOGO_HEIGHT
295#define VIDEO_LOGO_LUT_OFFSET LINUX_LOGO_LUT_OFFSET
296#define VIDEO_LOGO_COLORS LINUX_LOGO_COLORS
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000297#endif /* CONFIG_VIDEO_BMP_LOGO */
wdenke55402c2004-03-14 16:51:43 +0000298#define VIDEO_INFO_X (VIDEO_LOGO_WIDTH)
299#define VIDEO_INFO_Y (VIDEO_FONT_HEIGHT/2)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000300#else /* CONFIG_VIDEO_LOGO */
wdenke55402c2004-03-14 16:51:43 +0000301#define VIDEO_LOGO_WIDTH 0
302#define VIDEO_LOGO_HEIGHT 0
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000303#endif /* CONFIG_VIDEO_LOGO */
wdenkc6097192002-11-03 00:24:07 +0000304
wdenke55402c2004-03-14 16:51:43 +0000305#define VIDEO_COLS VIDEO_VISIBLE_COLS
306#define VIDEO_ROWS VIDEO_VISIBLE_ROWS
307#define VIDEO_SIZE (VIDEO_ROWS*VIDEO_COLS*VIDEO_PIXEL_SIZE)
308#define VIDEO_PIX_BLOCKS (VIDEO_SIZE >> 2)
309#define VIDEO_LINE_LEN (VIDEO_COLS*VIDEO_PIXEL_SIZE)
310#define VIDEO_BURST_LEN (VIDEO_COLS/8)
wdenkc6097192002-11-03 00:24:07 +0000311
wdenke55402c2004-03-14 16:51:43 +0000312#ifdef CONFIG_VIDEO_LOGO
Matthias Weisser76d70862010-01-12 12:06:31 +0100313#define CONSOLE_ROWS ((VIDEO_ROWS - video_logo_height) / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000314#else
wdenke55402c2004-03-14 16:51:43 +0000315#define CONSOLE_ROWS (VIDEO_ROWS / VIDEO_FONT_HEIGHT)
wdenkc6097192002-11-03 00:24:07 +0000316#endif
317
wdenke55402c2004-03-14 16:51:43 +0000318#define CONSOLE_COLS (VIDEO_COLS / VIDEO_FONT_WIDTH)
319#define CONSOLE_ROW_SIZE (VIDEO_FONT_HEIGHT * VIDEO_LINE_LEN)
320#define CONSOLE_ROW_FIRST (video_console_address)
321#define CONSOLE_ROW_SECOND (video_console_address + CONSOLE_ROW_SIZE)
322#define CONSOLE_ROW_LAST (video_console_address + CONSOLE_SIZE - CONSOLE_ROW_SIZE)
323#define CONSOLE_SIZE (CONSOLE_ROW_SIZE * CONSOLE_ROWS)
324#define CONSOLE_SCROLL_SIZE (CONSOLE_SIZE - CONSOLE_ROW_SIZE)
wdenkc6097192002-11-03 00:24:07 +0000325
326/* Macros */
wdenke55402c2004-03-14 16:51:43 +0000327#ifdef VIDEO_FB_LITTLE_ENDIAN
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000328#define SWAP16(x) ((((x) & 0x00ff) << 8) | \
329 ((x) >> 8) \
330 )
331#define SWAP32(x) ((((x) & 0x000000ff) << 24) | \
332 (((x) & 0x0000ff00) << 8) | \
333 (((x) & 0x00ff0000) >> 8) | \
334 (((x) & 0xff000000) >> 24) \
335 )
336#define SHORTSWAP32(x) ((((x) & 0x000000ff) << 8) | \
337 (((x) & 0x0000ff00) >> 8) | \
338 (((x) & 0x00ff0000) << 8) | \
339 (((x) & 0xff000000) >> 8) \
340 )
wdenkc6097192002-11-03 00:24:07 +0000341#else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000342#define SWAP16(x) (x)
343#define SWAP32(x) (x)
Wolfgang Grandeggere1b05842009-10-23 12:03:15 +0200344#if defined(VIDEO_FB_16BPP_WORD_SWAP)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000345#define SHORTSWAP32(x) (((x) >> 16) | ((x) << 16))
Andrew Dyer5601c612008-08-29 12:30:39 -0500346#else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000347#define SHORTSWAP32(x) (x)
Anatolij Gustschin3545f592008-01-11 14:30:01 +0100348#endif
wdenkc6097192002-11-03 00:24:07 +0000349#endif
350
351#if defined(DEBUG) || defined(DEBUG_CFB_CONSOLE)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000352#define PRINTD(x) printf(x)
wdenkc6097192002-11-03 00:24:07 +0000353#else
354#define PRINTD(x)
355#endif
356
357
358#ifdef CONFIG_CONSOLE_EXTRA_INFO
Wolfgang Denk0b4b56e2011-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 Denk0b4b56e2011-07-29 09:55:27 +0000371static void *video_fb_address; /* frame buffer address */
wdenke55402c2004-03-14 16:51:43 +0000372static void *video_console_address; /* console buffer start address */
wdenkc6097192002-11-03 00:24:07 +0000373
Matthias Weisser76d70862010-01-12 12:06:31 +0100374static int video_logo_height = VIDEO_LOGO_HEIGHT;
375
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000376static int console_col = 0; /* cursor col */
377static int console_row = 0; /* cursor row */
wdenkc6097192002-11-03 00:24:07 +0000378
Wolfgang Denk0b4b56e2011-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 Denk0b4b56e2011-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 Denk0b4b56e2011-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 Denk0b4b56e2011-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 Denk0b4b56e2011-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 Denk0b4b56e2011-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
wdenkc6097192002-11-03 00:24:07 +0000434
Wolfgang Denk0b4b56e2011-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{
wdenke55402c2004-03-14 16:51:43 +0000437 u8 *cdat, *dest, *dest0;
438 int rows, offset, c;
wdenkc6097192002-11-03 00:24:07 +0000439
wdenke55402c2004-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
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000450 rows--; dest += VIDEO_LINE_LEN) {
wdenke55402c2004-03-14 16:51:43 +0000451 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000452
Wolfgang Denk0b4b56e2011-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;
wdenke55402c2004-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
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000470 rows--; dest += VIDEO_LINE_LEN) {
wdenke55402c2004-03-14 16:51:43 +0000471 u8 bits = *cdat++;
wdenkc6097192002-11-03 00:24:07 +0000472
Wolfgang Denk0b4b56e2011-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);
wdenke55402c2004-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
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000500 rows--; dest += VIDEO_LINE_LEN) {
wdenke55402c2004-03-14 16:51:43 +0000501 u8 bits = *cdat++;
502
Wolfgang Denk0b4b56e2011-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);
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000530 rows--; dest += VIDEO_LINE_LEN) {
wdenke55402c2004-03-14 16:51:43 +0000531 u8 bits = *cdat++;
532
Wolfgang Denk0b4b56e2011-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);
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000568 rows--; dest += VIDEO_LINE_LEN) {
wdenke55402c2004-03-14 16:51:43 +0000569 u8 bits = *cdat++;
570
Wolfgang Denk0b4b56e2011-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;
wdenke55402c2004-03-14 16:51:43 +0000589 }
590 dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
591 s++;
592 }
593 break;
wdenk57b2d802003-06-27 21:31:46 +0000594 }
wdenkc6097192002-11-03 00:24:07 +0000595}
596
Wolfgang Denk0b4b56e2011-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 Denk0b4b56e2011-07-29 09:55:27 +0000599 video_drawchars(xx, yy, s, strlen((char *) s));
wdenkc6097192002-11-03 00:24:07 +0000600}
601
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000602static void video_putchar(int xx, int yy, unsigned char c)
wdenkc6097192002-11-03 00:24:07 +0000603{
Wolfgang Denk0b4b56e2011-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 Denk0b4b56e2011-07-29 09:55:27 +0000608static void video_set_cursor(void)
wdenkc6097192002-11-03 00:24:07 +0000609{
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000616 video_putchar(console_col * VIDEO_FONT_WIDTH,
617 console_row * VIDEO_FONT_HEIGHT, ' ');
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000625
wdenkc6097192002-11-03 00:24:07 +0000626#ifdef CONFIG_CONSOLE_CURSOR
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000627void console_cursor(int state)
wdenkc6097192002-11-03 00:24:07 +0000628{
wdenke55402c2004-03-14 16:51:43 +0000629 static int last_state = 0;
630
wdenkc6097192002-11-03 00:24:07 +0000631#ifdef CONFIG_CONSOLE_TIME
wdenke55402c2004-03-14 16:51:43 +0000632 struct rtc_time tm;
633 char info[16];
wdenkc6097192002-11-03 00:24:07 +0000634
wdenke55402c2004-03-14 16:51:43 +0000635 /* time update only if cursor is on (faster scroll) */
636 if (state) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000637 rtc_get(&tm);
wdenkc6097192002-11-03 00:24:07 +0000638
Wolfgang Denk0b4b56e2011-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 Denk0b4b56e2011-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);
wdenke55402c2004-03-14 16:51:43 +0000649 }
wdenkc6097192002-11-03 00:24:07 +0000650#endif
651
wdenke55402c2004-03-14 16:51:43 +0000652 if (state && (last_state != state)) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000653 video_set_cursor();
wdenke55402c2004-03-14 16:51:43 +0000654 }
wdenkc6097192002-11-03 00:24:07 +0000655
wdenke55402c2004-03-14 16:51:43 +0000656 if (!state && (last_state != state)) {
657 /* clear cursor */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000658 video_putchar(console_col * VIDEO_FONT_WIDTH,
659 console_row * VIDEO_FONT_HEIGHT, ' ');
wdenke55402c2004-03-14 16:51:43 +0000660 }
wdenkc6097192002-11-03 00:24:07 +0000661
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000667static void memsetl(int *p, int c, int v)
wdenkc6097192002-11-03 00:24:07 +0000668{
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000675static void memcpyl(int *d, int *s, int c)
wdenkc6097192002-11-03 00:24:07 +0000676{
wdenke55402c2004-03-14 16:51:43 +0000677 while (c--)
678 *(d++) = *(s++);
wdenkc6097192002-11-03 00:24:07 +0000679}
680#endif
681
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000682static void console_scrollup(void)
wdenkc6097192002-11-03 00:24:07 +0000683{
wdenke55402c2004-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 Denk0b4b56e2011-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 */
wdenke55402c2004-03-14 16:51:43 +0000697 );
wdenkc6097192002-11-03 00:24:07 +0000698#else
Wolfgang Denk0b4b56e2011-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
wdenke55402c2004-03-14 16:51:43 +0000703 /* clear the last one */
wdenkc6097192002-11-03 00:24:07 +0000704#ifdef VIDEO_HW_RECTFILL
Wolfgang Denk0b4b56e2011-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 */
wdenke55402c2004-03-14 16:51:43 +0000712 );
wdenkc6097192002-11-03 00:24:07 +0000713#else
Wolfgang Denk0b4b56e2011-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 Denk0b4b56e2011-07-29 09:55:27 +0000718static void console_back(void)
wdenkc6097192002-11-03 00:24:07 +0000719{
Timur Tabibe0c74e2010-08-27 15:45:47 -0500720 CURSOR_OFF;
721 console_col--;
wdenkc6097192002-11-03 00:24:07 +0000722
wdenke55402c2004-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 Denk0b4b56e2011-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 Denk0b4b56e2011-07-29 09:55:27 +0000733static void console_newline(void)
wdenkc6097192002-11-03 00:24:07 +0000734{
Anatolij Gustschin938db912008-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 Tabibe0c74e2010-08-27 15:45:47 -0500741 CURSOR_OFF;
Anatolij Gustschin938db912008-01-11 02:39:47 +0100742 console_row++;
wdenke55402c2004-03-14 16:51:43 +0000743 console_col = 0;
wdenkc6097192002-11-03 00:24:07 +0000744
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000748 console_scrollup();
wdenkc6097192002-11-03 00:24:07 +0000749
wdenke55402c2004-03-14 16:51:43 +0000750 /* Decrement row number */
751 console_row--;
752 }
wdenkc6097192002-11-03 00:24:07 +0000753}
754
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000755static void console_cr(void)
Anatolij Gustschin938db912008-01-11 02:39:47 +0100756{
Timur Tabibe0c74e2010-08-27 15:45:47 -0500757 CURSOR_OFF;
758 console_col = 0;
Anatolij Gustschin938db912008-01-11 02:39:47 +0100759}
760
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000761void video_putc(const char c)
wdenkc6097192002-11-03 00:24:07 +0000762{
Anatolij Gustschin938db912008-01-11 02:39:47 +0100763 static int nl = 1;
764
wdenke55402c2004-03-14 16:51:43 +0000765 switch (c) {
Anatolij Gustschin938db912008-01-11 02:39:47 +0100766 case 13: /* back to first column */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000767 console_cr();
wdenke55402c2004-03-14 16:51:43 +0000768 break;
wdenkc6097192002-11-03 00:24:07 +0000769
wdenke55402c2004-03-14 16:51:43 +0000770 case '\n': /* next line */
Anatolij Gustschin938db912008-01-11 02:39:47 +0100771 if (console_col || (!console_col && nl))
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000772 console_newline();
Anatolij Gustschin938db912008-01-11 02:39:47 +0100773 nl = 1;
wdenke55402c2004-03-14 16:51:43 +0000774 break;
wdenkc6097192002-11-03 00:24:07 +0000775
wdenke55402c2004-03-14 16:51:43 +0000776 case 9: /* tab 8 */
Timur Tabibe0c74e2010-08-27 15:45:47 -0500777 CURSOR_OFF;
778 console_col |= 0x0008;
wdenke55402c2004-03-14 16:51:43 +0000779 console_col &= ~0x0007;
wdenkc6097192002-11-03 00:24:07 +0000780
wdenke55402c2004-03-14 16:51:43 +0000781 if (console_col >= CONSOLE_COLS)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000782 console_newline();
wdenke55402c2004-03-14 16:51:43 +0000783 break;
wdenkc6097192002-11-03 00:24:07 +0000784
wdenke55402c2004-03-14 16:51:43 +0000785 case 8: /* backspace */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000786 console_back();
wdenke55402c2004-03-14 16:51:43 +0000787 break;
wdenkc6097192002-11-03 00:24:07 +0000788
wdenke55402c2004-03-14 16:51:43 +0000789 default: /* draw the char */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000790 video_putchar(console_col * VIDEO_FONT_WIDTH,
791 console_row * VIDEO_FONT_HEIGHT, c);
wdenke55402c2004-03-14 16:51:43 +0000792 console_col++;
wdenkc6097192002-11-03 00:24:07 +0000793
wdenke55402c2004-03-14 16:51:43 +0000794 /* check for newline */
Anatolij Gustschin938db912008-01-11 02:39:47 +0100795 if (console_col >= CONSOLE_COLS) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000796 console_newline();
Anatolij Gustschin938db912008-01-11 02:39:47 +0100797 nl = 0;
798 }
wdenke55402c2004-03-14 16:51:43 +0000799 }
Timur Tabibe0c74e2010-08-27 15:45:47 -0500800 CURSOR_SET;
801}
wdenkc6097192002-11-03 00:24:07 +0000802
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000803void video_puts(const char *s)
wdenkc6097192002-11-03 00:24:07 +0000804{
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000805 int count = strlen(s);
wdenke55402c2004-03-14 16:51:43 +0000806
807 while (count--)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000808 video_putc(*s++);
wdenke55402c2004-03-14 16:51:43 +0000809}
810
Anatolij Gustschina043c342010-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 Denk0b4b56e2011-07-29 09:55:27 +0000816void __video_set_lut(unsigned int index, unsigned char r,
817 unsigned char g, unsigned char b)
Anatolij Gustschina043c342010-05-01 22:21:09 +0200818{
819}
Wolfgang Denk0b4b56e2011-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 Gustschina043c342010-05-01 22:21:09 +0200823
Jon Loeligerb1d408a2007-07-09 17:30:01 -0500824#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +0000832 *(unsigned short *)fb = \
833 SWAP16((unsigned short)(((r>>3)<<10) | \
834 ((g>>3)<<5) | \
835 (b>>3))); \
wdenke55402c2004-03-14 16:51:43 +0000836 fb += 2; \
837}
838
839#define FILL_16BIT_565RGB(r,g,b) { \
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000840 *(unsigned short *)fb = \
841 SWAP16((unsigned short)((((r)>>3)<<11)| \
842 (((g)>>2)<<5) | \
843 ((b)>>3))); \
wdenke55402c2004-03-14 16:51:43 +0000844 fb += 2; \
845}
846
847#define FILL_32BIT_X888RGB(r,g,b) { \
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000848 *(unsigned long *)fb = \
849 SWAP32((unsigned long)(((r<<16) | \
850 (g<<8) | \
851 b))); \
wdenke55402c2004-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 Gustschin18b80362008-08-08 18:00:40 +0200871#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000872static inline void fill_555rgb_pswap(uchar *fb, int x, u8 r, u8 g, u8 b)
Anatolij Gustschin18b80362008-08-08 18:00:40 +0200873{
Wolfgang Denk0b4b56e2011-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 Gustschin18b80362008-08-08 18:00:40 +0200878 if (x & 1)
879 *(--dst) = color;
880 else
881 *(++dst) = color;
882}
883#endif
wdenke55402c2004-03-14 16:51:43 +0000884
885/*
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +0000893 unsigned short w; /* word */
894 unsigned int dw; /* double word */
895 } ce; /* color entry */
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +0100896};
897
898/*
899 * Helper to draw encoded/unencoded run.
900 */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000901static void draw_bitmap(uchar **fb, uchar *bm, struct palette *p,
902 int cnt, int enc)
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +0100903{
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000904 ulong addr = (ulong) *fb;
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +0000918 *(unsigned char *) addr++ = bm[*off];
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +0000924 *(unsigned short *) addr = p[bm[*off]].ce.w;
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +0100925 addr += 2;
926 }
927 break;
928 case GDF_32BIT_X888RGB:
929 for (i = 0; i < cnt; i++) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000930 *(unsigned long *) addr = p[bm[*off]].ce.dw;
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +0100931 addr += 4;
932 }
933 break;
934 }
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000935 *fb = (uchar *) addr; /* return modified address */
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +0100936}
937
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000938static int display_rle8_bitmap(bmp_image_t *img, int xoff, int yoff,
939 int width, int height)
Anatolij Gustschin6b4e4fc2010-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 Gustschince5f8df2011-02-21 21:33:29 +0100949 int limit = VIDEO_COLS * VIDEO_ROWS;
950 int pixels = 0;
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +0000956 fbp = (unsigned char *) ((unsigned int) video_fb_address +
957 (((y + yoff) * VIDEO_COLS) + xoff) * bpp);
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +0100958
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +0000959 bm = (uchar *) img + __le32_to_cpu(img->header.data_offset);
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +0000966 video_set_lut(i, cte.red, cte.green, cte.blue);
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +0000989 p[i].ce.dw = SWAP32((cte.red << 16) |
990 (cte.green << 8) |
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +0000996 VIDEO_DATA_FORMAT);
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +00001010 ((unsigned int) video_fb_address +
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +00001023 ((unsigned int) video_fb_address +
Anatolij Gustschin6b4e4fc2010-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 Gustschince5f8df2011-02-21 21:33:29 +01001032 pixels += cnt;
1033 if (pixels > limit)
1034 goto error;
1035
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +00001044 draw_bitmap(&fbp, bm, p, cnt, 0);
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +01001045 x += runlen;
1046 }
1047next_run:
1048 bm += runlen;
1049 if (runlen & 1)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001050 bm++; /* 0 padding if length is odd */
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +01001051 }
1052 break;
1053 default:
1054 /* encoded run */
Anatolij Gustschince5f8df2011-02-21 21:33:29 +01001055 cnt = bm[0];
1056 runlen = cnt;
1057 pixels += cnt;
1058 if (pixels > limit)
1059 goto error;
1060
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001061 if (y < height) { /* only draw into visible area */
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +00001069 draw_bitmap(&fbp, bm, p, cnt, 1);
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +01001070 x += runlen;
1071 }
1072 bm += 2;
1073 break;
1074 }
1075 }
1076 return 0;
Anatolij Gustschince5f8df2011-02-21 21:33:29 +01001077error:
1078 printf("Error: Too much encoded pixel data, validate your bitmap\n");
1079 return -1;
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +01001080}
1081#endif
1082
1083/*
wdenke55402c2004-03-14 16:51:43 +00001084 * Display the BMP file located at address bmp_image.
wdenke55402c2004-03-14 16:51:43 +00001085 */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001086int video_display_bitmap(ulong bmp_image, int x, int y)
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +00001097
Stefan Roesed9d97742005-09-22 09:04:17 +02001098#ifdef CONFIG_VIDEO_BMP_GZIP
1099 unsigned char *dst = NULL;
1100 ulong len;
1101#endif
wdenkc6097192002-11-03 00:24:07 +00001102
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001103 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001104
1105 if (!((bmp->header.signature[0] == 'B') &&
1106 (bmp->header.signature[1] == 'M'))) {
Stefan Roesed9d97742005-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-VILLARD03836942008-10-16 15:01:15 +02001112 len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
1113 dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
Stefan Roese13b93692005-10-08 10:19:07 +02001114 if (dst == NULL) {
1115 printf("Error: malloc in gunzip failed!\n");
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001116 return 1;
Stefan Roese13b93692005-10-08 10:19:07 +02001117 }
Wolfgang Denk0b4b56e2011-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 Roesed9d97742005-09-22 09:04:17 +02001123 free(dst);
1124 return 1;
1125 }
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +02001126 if (len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001127 printf("Image could be truncated "
1128 "(increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
Stefan Roese13b93692005-10-08 10:19:07 +02001129 }
Stefan Roesed9d97742005-09-22 09:04:17 +02001130
1131 /*
1132 * Set addr to decompressed image
1133 */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001134 bmp = (bmp_image_t *) dst;
Stefan Roesed9d97742005-09-22 09:04:17 +02001135
1136 if (!((bmp->header.signature[0] == 'B') &&
1137 (bmp->header.signature[1] == 'M'))) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001138 printf("Error: no valid bmp.gz image at %lx\n",
1139 bmp_image);
Matthias Fuchsa7c5a592008-04-21 11:19:04 +02001140 free(dst);
Stefan Roesed9d97742005-09-22 09:04:17 +02001141 return 1;
1142 }
1143#else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001144 printf("Error: no valid bmp image at %lx\n", bmp_image);
wdenke55402c2004-03-14 16:51:43 +00001145 return 1;
Stefan Roesed9d97742005-09-22 09:04:17 +02001146#endif /* CONFIG_VIDEO_BMP_GZIP */
wdenke55402c2004-03-14 16:51:43 +00001147 }
1148
Wolfgang Denk0b4b56e2011-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);
wdenke55402c2004-03-14 16:51:43 +00001154
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001155 debug("Display-bmp: %d x %d with %d colors\n",
1156 width, height, colors);
wdenke55402c2004-03-14 16:51:43 +00001157
Anatolij Gustschin6b4e4fc2010-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 Denk0b4b56e2011-07-29 09:55:27 +00001162 ) {
1163 printf("Error: compression type %ld not supported\n",
1164 compression);
Matthias Fuchsa7c5a592008-04-21 11:19:04 +02001165#ifdef CONFIG_VIDEO_BMP_GZIP
1166 if (dst)
1167 free(dst);
1168#endif
wdenke55402c2004-03-14 16:51:43 +00001169 return 1;
1170 }
1171
1172 padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3;
1173
Matthias Weisser53884182009-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
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +00001191 bmap = (uchar *) bmp + le32_to_cpu(bmp->header.data_offset);
wdenke55402c2004-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 Gustschin6b4e4fc2010-03-15 14:50:25 +01001196#ifdef CONFIG_VIDEO_BMP_RLE8
1197 if (compression == BMP_BI_RLE8) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001198 return display_rle8_bitmap(bmp, x, y, width, height);
Anatolij Gustschin6b4e4fc2010-03-15 14:50:25 +01001199 }
1200#endif
1201
Timur Tabi0fce9922010-08-23 16:58:00 -05001202 /* We handle only 4, 8, or 24 bpp bitmaps */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001203 switch (le16_to_cpu(bmp->header.bit_count)) {
Timur Tabi0fce9922010-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 Denk0b4b56e2011-07-29 09:55:27 +00001211 WATCHDOG_RESET();
Timur Tabi0fce9922010-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 Denk0b4b56e2011-07-29 09:55:27 +00001230 VIDEO_PIXEL_SIZE;
Timur Tabi0fce9922010-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
wdenke55402c2004-03-14 16:51:43 +00001240 case 8:
1241 padded_line -= width;
1242 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
Anatolij Gustschin794b25c2010-06-19 20:41:56 +02001243 /* Copy colormap */
wdenke55402c2004-03-14 16:51:43 +00001244 for (xcount = 0; xcount < colors; ++xcount) {
1245 cte = bmp->color_table[xcount];
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001246 video_set_lut(xcount, cte.red, cte.green,
1247 cte.blue);
wdenke55402c2004-03-14 16:51:43 +00001248 }
1249 }
1250 ycount = height;
1251 switch (VIDEO_DATA_FORMAT) {
1252 case GDF__8BIT_INDEX:
1253 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001254 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001255 xcount = width;
1256 while (xcount--) {
1257 *fb++ = *bmap++;
1258 }
1259 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001260 fb -= (VIDEO_VISIBLE_COLS + width) *
1261 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001262 }
1263 break;
1264 case GDF__8BIT_332RGB:
1265 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001266 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001267 xcount = width;
1268 while (xcount--) {
1269 cte = bmp->color_table[*bmap++];
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001270 FILL_8BIT_332RGB(cte.red, cte.green,
1271 cte.blue);
wdenke55402c2004-03-14 16:51:43 +00001272 }
1273 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001274 fb -= (VIDEO_VISIBLE_COLS + width) *
1275 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001276 }
1277 break;
1278 case GDF_15BIT_555RGB:
1279 while (ycount--) {
Anatolij Gustschin18b80362008-08-08 18:00:40 +02001280#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1281 int xpos = x;
1282#endif
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001283 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001284 xcount = width;
1285 while (xcount--) {
1286 cte = bmp->color_table[*bmap++];
Andrew Dyer5601c612008-08-29 12:30:39 -05001287#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001288 fill_555rgb_pswap(fb, xpos++, cte.red,
1289 cte.green,
1290 cte.blue);
Anatolij Gustschin18b80362008-08-08 18:00:40 +02001291 fb += 2;
Andrew Dyer5601c612008-08-29 12:30:39 -05001292#else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001293 FILL_15BIT_555RGB(cte.red, cte.green,
1294 cte.blue);
Anatolij Gustschin18b80362008-08-08 18:00:40 +02001295#endif
wdenke55402c2004-03-14 16:51:43 +00001296 }
1297 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001298 fb -= (VIDEO_VISIBLE_COLS + width) *
1299 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001300 }
1301 break;
1302 case GDF_16BIT_565RGB:
1303 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001304 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001305 xcount = width;
1306 while (xcount--) {
1307 cte = bmp->color_table[*bmap++];
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001308 FILL_16BIT_565RGB(cte.red, cte.green,
1309 cte.blue);
wdenke55402c2004-03-14 16:51:43 +00001310 }
1311 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001312 fb -= (VIDEO_VISIBLE_COLS + width) *
1313 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001314 }
1315 break;
1316 case GDF_32BIT_X888RGB:
1317 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001318 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001319 xcount = width;
1320 while (xcount--) {
1321 cte = bmp->color_table[*bmap++];
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001322 FILL_32BIT_X888RGB(cte.red, cte.green,
1323 cte.blue);
wdenke55402c2004-03-14 16:51:43 +00001324 }
1325 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001326 fb -= (VIDEO_VISIBLE_COLS + width) *
1327 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001328 }
1329 break;
1330 case GDF_24BIT_888RGB:
1331 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001332 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001333 xcount = width;
1334 while (xcount--) {
1335 cte = bmp->color_table[*bmap++];
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001336 FILL_24BIT_888RGB(cte.red, cte.green,
1337 cte.blue);
wdenke55402c2004-03-14 16:51:43 +00001338 }
1339 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001340 fb -= (VIDEO_VISIBLE_COLS + width) *
1341 VIDEO_PIXEL_SIZE;
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +00001352 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001353 xcount = width;
1354 while (xcount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001355 FILL_8BIT_332RGB(bmap[2], bmap[1],
1356 bmap[0]);
wdenke55402c2004-03-14 16:51:43 +00001357 bmap += 3;
1358 }
1359 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001360 fb -= (VIDEO_VISIBLE_COLS + width) *
1361 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001362 }
1363 break;
1364 case GDF_15BIT_555RGB:
1365 while (ycount--) {
Anatolij Gustschin18b80362008-08-08 18:00:40 +02001366#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1367 int xpos = x;
1368#endif
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001369 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001370 xcount = width;
1371 while (xcount--) {
Andrew Dyer5601c612008-08-29 12:30:39 -05001372#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001373 fill_555rgb_pswap(fb, xpos++, bmap[2],
1374 bmap[1], bmap[0]);
Anatolij Gustschin18b80362008-08-08 18:00:40 +02001375 fb += 2;
Andrew Dyer5601c612008-08-29 12:30:39 -05001376#else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001377 FILL_15BIT_555RGB(bmap[2], bmap[1],
1378 bmap[0]);
Anatolij Gustschin18b80362008-08-08 18:00:40 +02001379#endif
wdenke55402c2004-03-14 16:51:43 +00001380 bmap += 3;
1381 }
1382 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001383 fb -= (VIDEO_VISIBLE_COLS + width) *
1384 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001385 }
1386 break;
1387 case GDF_16BIT_565RGB:
1388 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001389 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001390 xcount = width;
1391 while (xcount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001392 FILL_16BIT_565RGB(bmap[2], bmap[1],
1393 bmap[0]);
wdenke55402c2004-03-14 16:51:43 +00001394 bmap += 3;
1395 }
1396 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001397 fb -= (VIDEO_VISIBLE_COLS + width) *
1398 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001399 }
1400 break;
1401 case GDF_32BIT_X888RGB:
1402 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001403 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001404 xcount = width;
1405 while (xcount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001406 FILL_32BIT_X888RGB(bmap[2], bmap[1],
1407 bmap[0]);
wdenke55402c2004-03-14 16:51:43 +00001408 bmap += 3;
1409 }
1410 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001411 fb -= (VIDEO_VISIBLE_COLS + width) *
1412 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001413 }
1414 break;
1415 case GDF_24BIT_888RGB:
1416 while (ycount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001417 WATCHDOG_RESET();
wdenke55402c2004-03-14 16:51:43 +00001418 xcount = width;
1419 while (xcount--) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001420 FILL_24BIT_888RGB(bmap[2], bmap[1],
1421 bmap[0]);
wdenke55402c2004-03-14 16:51:43 +00001422 bmap += 3;
1423 }
1424 bmap += padded_line;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001425 fb -= (VIDEO_VISIBLE_COLS + width) *
1426 VIDEO_PIXEL_SIZE;
wdenke55402c2004-03-14 16:51:43 +00001427 }
1428 break;
1429 default:
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001430 printf("Error: 24 bits/pixel bitmap incompatible "
1431 "with current video mode\n");
wdenke55402c2004-03-14 16:51:43 +00001432 break;
1433 }
1434 break;
1435 default:
Wolfgang Denk0b4b56e2011-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));
wdenke55402c2004-03-14 16:51:43 +00001438 break;
1439 }
Stefan Roesed9d97742005-09-22 09:04:17 +02001440
1441#ifdef CONFIG_VIDEO_BMP_GZIP
1442 if (dst) {
1443 free(dst);
1444 }
1445#endif
1446
wdenke55402c2004-03-14 16:51:43 +00001447 return (0);
wdenkc6097192002-11-03 00:24:07 +00001448}
Jon Loeligerb1d408a2007-07-09 17:30:01 -05001449#endif
wdenkc6097192002-11-03 00:24:07 +00001450
wdenkc6097192002-11-03 00:24:07 +00001451
1452#ifdef CONFIG_VIDEO_LOGO
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001453void logo_plot(void *screen, int width, int x, int y)
wdenkc6097192002-11-03 00:24:07 +00001454{
wdenk9dd2b882002-12-03 21:28:10 +00001455
wdenke55402c2004-03-14 16:51:43 +00001456 int xcount, i;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001457 int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
Matthias Weisser76d70862010-01-12 12:06:31 +01001458 int ycount = video_logo_height;
wdenke55402c2004-03-14 16:51:43 +00001459 unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
1460 unsigned char *source;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001461 unsigned char *dest = (unsigned char *) screen +
1462 ((y * width * VIDEO_PIXEL_SIZE) + x * VIDEO_PIXEL_SIZE);
wdenkc6097192002-11-03 00:24:07 +00001463
wdenk9dd2b882002-12-03 21:28:10 +00001464#ifdef CONFIG_VIDEO_BMP_LOGO
wdenke55402c2004-03-14 16:51:43 +00001465 source = bmp_logo_bitmap;
wdenk57b2d802003-06-27 21:31:46 +00001466
Anatolij Gustschin794b25c2010-06-19 20:41:56 +02001467 /* Allocate temporary space for computing colormap */
Wolfgang Denk0b4b56e2011-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 Gustschin794b25c2010-06-19 20:41:56 +02001471 /* Compute color map */
wdenke55402c2004-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 }
wdenk9dd2b882002-12-03 21:28:10 +00001477#else
wdenke55402c2004-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;
wdenk9dd2b882002-12-03 21:28:10 +00001482#endif
wdenk57b2d802003-06-27 21:31:46 +00001483
wdenke55402c2004-03-14 16:51:43 +00001484 if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
1485 for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
Wolfgang Denk0b4b56e2011-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]);
wdenke55402c2004-03-14 16:51:43 +00001489 }
wdenk57b2d802003-06-27 21:31:46 +00001490 }
wdenkc6097192002-11-03 00:24:07 +00001491
wdenke55402c2004-03-14 16:51:43 +00001492 while (ycount--) {
Anatolij Gustschin18b80362008-08-08 18:00:40 +02001493#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
1494 int xpos = x;
1495#endif
wdenke55402c2004-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];
wdenk57b2d802003-06-27 21:31:46 +00001501
wdenke55402c2004-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 Denk0b4b56e2011-07-29 09:55:27 +00001507 *dest = ((r >> 5) << 5) |
1508 ((g >> 5) << 2) |
1509 (b >> 6);
wdenke55402c2004-03-14 16:51:43 +00001510 break;
1511 case GDF_15BIT_555RGB:
Andrew Dyer5601c612008-08-29 12:30:39 -05001512#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001513 fill_555rgb_pswap(dest, xpos++, r, g, b);
Andrew Dyer5601c612008-08-29 12:30:39 -05001514#else
wdenke55402c2004-03-14 16:51:43 +00001515 *(unsigned short *) dest =
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001516 SWAP16((unsigned short) (
1517 ((r >> 3) << 10) |
1518 ((g >> 3) << 5) |
1519 (b >> 3)));
Anatolij Gustschin3545f592008-01-11 14:30:01 +01001520#endif
wdenke55402c2004-03-14 16:51:43 +00001521 break;
1522 case GDF_16BIT_565RGB:
1523 *(unsigned short *) dest =
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001524 SWAP16((unsigned short) (
1525 ((r >> 3) << 11) |
1526 ((g >> 2) << 5) |
1527 (b >> 3)));
wdenke55402c2004-03-14 16:51:43 +00001528 break;
1529 case GDF_32BIT_X888RGB:
1530 *(unsigned long *) dest =
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001531 SWAP32((unsigned long) (
1532 (r << 16) |
1533 (g << 8) |
1534 b));
wdenke55402c2004-03-14 16:51:43 +00001535 break;
1536 case GDF_24BIT_888RGB:
wdenkc6097192002-11-03 00:24:07 +00001537#ifdef VIDEO_FB_LITTLE_ENDIAN
wdenke55402c2004-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
wdenke55402c2004-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
wdenke55402c2004-03-14 16:51:43 +00001546 break;
1547 }
1548 source++;
1549 dest += VIDEO_PIXEL_SIZE;
1550 }
1551 dest += skip;
wdenk57b2d802003-06-27 21:31:46 +00001552 }
wdenk9dd2b882002-12-03 21:28:10 +00001553#ifdef CONFIG_VIDEO_BMP_LOGO
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001554 free(logo_red);
1555 free(logo_green);
1556 free(logo_blue);
wdenk9dd2b882002-12-03 21:28:10 +00001557#endif
wdenkc6097192002-11-03 00:24:07 +00001558}
1559
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001560static void *video_logo(void)
wdenkc6097192002-11-03 00:24:07 +00001561{
wdenke55402c2004-03-14 16:51:43 +00001562 char info[128];
Anatolij Gustschine6e98b22009-04-23 12:35:22 +02001563 int space, len, y_off = 0;
wdenke55402c2004-03-14 16:51:43 +00001564
1565#ifdef CONFIG_SPLASH_SCREEN
1566 char *s;
1567 ulong addr;
1568
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001569 if ((s = getenv("splashimage")) != NULL) {
Matthias Weisser53884182009-07-09 16:07:30 +02001570 int x = 0, y = 0;
1571
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001572 addr = simple_strtoul(s, NULL, 16);
Matthias Weisser53884182009-07-09 16:07:30 +02001573#ifdef CONFIG_SPLASH_SCREEN_ALIGN
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001574 if ((s = getenv("splashpos")) != NULL) {
Matthias Weisser53884182009-07-09 16:07:30 +02001575 if (s[0] == 'm')
1576 x = BMP_ALIGN_CENTER;
1577 else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001578 x = simple_strtol(s, NULL, 0);
Matthias Weisser53884182009-07-09 16:07:30 +02001579
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001580 if ((s = strchr(s + 1, ',')) != NULL) {
Matthias Weisser53884182009-07-09 16:07:30 +02001581 if (s[1] == 'm')
1582 y = BMP_ALIGN_CENTER;
1583 else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001584 y = simple_strtol(s + 1, NULL, 0);
Matthias Weisser53884182009-07-09 16:07:30 +02001585 }
1586 }
1587#endif /* CONFIG_SPLASH_SCREEN_ALIGN */
wdenke55402c2004-03-14 16:51:43 +00001588
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001589 if (video_display_bitmap(addr, x, y) == 0) {
Matthias Weisser76d70862010-01-12 12:06:31 +01001590 video_logo_height = 0;
wdenke55402c2004-03-14 16:51:43 +00001591 return ((void *) (video_fb_address));
1592 }
1593 }
1594#endif /* CONFIG_SPLASH_SCREEN */
1595
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001596 logo_plot(video_fb_address, VIDEO_COLS, 0, 0);
wdenkc6097192002-11-03 00:24:07 +00001597
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001598 sprintf(info, " %s", version_string);
Anatolij Gustschine6e98b22009-04-23 12:35:22 +02001599
1600 space = (VIDEO_LINE_LEN / 2 - VIDEO_INFO_X) / VIDEO_FONT_WIDTH;
1601 len = strlen(info);
1602
1603 if (len > space) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001604 video_drawchars(VIDEO_INFO_X, VIDEO_INFO_Y,
1605 (uchar *) info, space);
1606 video_drawchars(VIDEO_INFO_X + VIDEO_FONT_WIDTH,
1607 VIDEO_INFO_Y + VIDEO_FONT_HEIGHT,
1608 (uchar *) info + space, len - space);
Anatolij Gustschine6e98b22009-04-23 12:35:22 +02001609 y_off = 1;
1610 } else
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001611 video_drawstring(VIDEO_INFO_X, VIDEO_INFO_Y, (uchar *) info);
wdenkc6097192002-11-03 00:24:07 +00001612
1613#ifdef CONFIG_CONSOLE_EXTRA_INFO
wdenke55402c2004-03-14 16:51:43 +00001614 {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001615 int i, n =
1616 ((video_logo_height -
1617 VIDEO_FONT_HEIGHT) / VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00001618
wdenke55402c2004-03-14 16:51:43 +00001619 for (i = 1; i < n; i++) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001620 video_get_info_str(i, info);
Anatolij Gustschine6e98b22009-04-23 12:35:22 +02001621 if (!*info)
1622 continue;
1623
1624 len = strlen(info);
1625 if (len > space) {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001626 video_drawchars(VIDEO_INFO_X,
1627 VIDEO_INFO_Y +
1628 (i + y_off) *
1629 VIDEO_FONT_HEIGHT,
1630 (uchar *) info, space);
Anatolij Gustschine6e98b22009-04-23 12:35:22 +02001631 y_off++;
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001632 video_drawchars(VIDEO_INFO_X +
1633 VIDEO_FONT_WIDTH,
1634 VIDEO_INFO_Y +
1635 (i + y_off) *
1636 VIDEO_FONT_HEIGHT,
1637 (uchar *) info + space,
1638 len - space);
Anatolij Gustschine6e98b22009-04-23 12:35:22 +02001639 } else {
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001640 video_drawstring(VIDEO_INFO_X,
1641 VIDEO_INFO_Y +
1642 (i + y_off) *
1643 VIDEO_FONT_HEIGHT,
1644 (uchar *) info);
Anatolij Gustschine6e98b22009-04-23 12:35:22 +02001645 }
wdenke55402c2004-03-14 16:51:43 +00001646 }
1647 }
wdenkc6097192002-11-03 00:24:07 +00001648#endif
1649
Matthias Weisser76d70862010-01-12 12:06:31 +01001650 return (video_fb_address + video_logo_height * VIDEO_LINE_LEN);
wdenkc6097192002-11-03 00:24:07 +00001651}
1652#endif
1653
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001654static int video_init(void)
wdenkc6097192002-11-03 00:24:07 +00001655{
wdenke55402c2004-03-14 16:51:43 +00001656 unsigned char color8;
wdenkc6097192002-11-03 00:24:07 +00001657
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001658 if ((pGD = video_hw_init()) == NULL)
wdenke55402c2004-03-14 16:51:43 +00001659 return -1;
wdenkc6097192002-11-03 00:24:07 +00001660
wdenke55402c2004-03-14 16:51:43 +00001661 video_fb_address = (void *) VIDEO_FB_ADRS;
wdenkc6097192002-11-03 00:24:07 +00001662#ifdef CONFIG_VIDEO_HW_CURSOR
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001663 video_init_hw_cursor(VIDEO_FONT_WIDTH, VIDEO_FONT_HEIGHT);
wdenkc6097192002-11-03 00:24:07 +00001664#endif
1665
wdenke55402c2004-03-14 16:51:43 +00001666 /* Init drawing pats */
1667 switch (VIDEO_DATA_FORMAT) {
1668 case GDF__8BIT_INDEX:
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001669 video_set_lut(0x01, CONSOLE_FG_COL, CONSOLE_FG_COL,
1670 CONSOLE_FG_COL);
1671 video_set_lut(0x00, CONSOLE_BG_COL, CONSOLE_BG_COL,
1672 CONSOLE_BG_COL);
wdenke55402c2004-03-14 16:51:43 +00001673 fgx = 0x01010101;
1674 bgx = 0x00000000;
1675 break;
1676 case GDF__8BIT_332RGB:
1677 color8 = ((CONSOLE_FG_COL & 0xe0) |
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001678 ((CONSOLE_FG_COL >> 3) & 0x1c) |
1679 CONSOLE_FG_COL >> 6);
1680 fgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1681 color8;
wdenke55402c2004-03-14 16:51:43 +00001682 color8 = ((CONSOLE_BG_COL & 0xe0) |
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001683 ((CONSOLE_BG_COL >> 3) & 0x1c) |
1684 CONSOLE_BG_COL >> 6);
1685 bgx = (color8 << 24) | (color8 << 16) | (color8 << 8) |
1686 color8;
wdenke55402c2004-03-14 16:51:43 +00001687 break;
1688 case GDF_15BIT_555RGB:
1689 fgx = (((CONSOLE_FG_COL >> 3) << 26) |
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001690 ((CONSOLE_FG_COL >> 3) << 21) |
1691 ((CONSOLE_FG_COL >> 3) << 16) |
1692 ((CONSOLE_FG_COL >> 3) << 10) |
1693 ((CONSOLE_FG_COL >> 3) << 5) |
1694 (CONSOLE_FG_COL >> 3));
wdenke55402c2004-03-14 16:51:43 +00001695 bgx = (((CONSOLE_BG_COL >> 3) << 26) |
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001696 ((CONSOLE_BG_COL >> 3) << 21) |
1697 ((CONSOLE_BG_COL >> 3) << 16) |
1698 ((CONSOLE_BG_COL >> 3) << 10) |
1699 ((CONSOLE_BG_COL >> 3) << 5) |
1700 (CONSOLE_BG_COL >> 3));
wdenke55402c2004-03-14 16:51:43 +00001701 break;
1702 case GDF_16BIT_565RGB:
1703 fgx = (((CONSOLE_FG_COL >> 3) << 27) |
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001704 ((CONSOLE_FG_COL >> 2) << 21) |
1705 ((CONSOLE_FG_COL >> 3) << 16) |
1706 ((CONSOLE_FG_COL >> 3) << 11) |
1707 ((CONSOLE_FG_COL >> 2) << 5) |
1708 (CONSOLE_FG_COL >> 3));
wdenke55402c2004-03-14 16:51:43 +00001709 bgx = (((CONSOLE_BG_COL >> 3) << 27) |
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001710 ((CONSOLE_BG_COL >> 2) << 21) |
1711 ((CONSOLE_BG_COL >> 3) << 16) |
1712 ((CONSOLE_BG_COL >> 3) << 11) |
1713 ((CONSOLE_BG_COL >> 2) << 5) |
1714 (CONSOLE_BG_COL >> 3));
wdenke55402c2004-03-14 16:51:43 +00001715 break;
1716 case GDF_32BIT_X888RGB:
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001717 fgx = (CONSOLE_FG_COL << 16) |
1718 (CONSOLE_FG_COL << 8) |
1719 CONSOLE_FG_COL;
1720 bgx = (CONSOLE_BG_COL << 16) |
1721 (CONSOLE_BG_COL << 8) |
1722 CONSOLE_BG_COL;
wdenke55402c2004-03-14 16:51:43 +00001723 break;
1724 case GDF_24BIT_888RGB:
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001725 fgx = (CONSOLE_FG_COL << 24) |
1726 (CONSOLE_FG_COL << 16) |
1727 (CONSOLE_FG_COL << 8) |
1728 CONSOLE_FG_COL;
1729 bgx = (CONSOLE_BG_COL << 24) |
1730 (CONSOLE_BG_COL << 16) |
1731 (CONSOLE_BG_COL << 8) |
1732 CONSOLE_BG_COL;
wdenke55402c2004-03-14 16:51:43 +00001733 break;
1734 }
1735 eorx = fgx ^ bgx;
wdenkc6097192002-11-03 00:24:07 +00001736
1737#ifdef CONFIG_VIDEO_LOGO
wdenke55402c2004-03-14 16:51:43 +00001738 /* Plot the logo and get start point of console */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001739 PRINTD("Video: Drawing the logo ...\n");
1740 video_console_address = video_logo();
wdenkc6097192002-11-03 00:24:07 +00001741#else
wdenke55402c2004-03-14 16:51:43 +00001742 video_console_address = video_fb_address;
wdenkc6097192002-11-03 00:24:07 +00001743#endif
1744
wdenke55402c2004-03-14 16:51:43 +00001745 /* Initialize the console */
1746 console_col = 0;
1747 console_row = 0;
wdenkc6097192002-11-03 00:24:07 +00001748
wdenke55402c2004-03-14 16:51:43 +00001749 return 0;
wdenkc6097192002-11-03 00:24:07 +00001750}
1751
Wolfgang Denkd0e4e2a2009-05-15 10:07:43 +02001752/*
1753 * Implement a weak default function for boards that optionally
1754 * need to skip the video initialization.
1755 */
1756int __board_video_skip(void)
1757{
1758 /* As default, don't skip test */
1759 return 0;
1760}
Wolfgang Denkd0e4e2a2009-05-15 10:07:43 +02001761
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001762int board_video_skip(void)
1763 __attribute__ ((weak, alias("__board_video_skip")));
1764
1765int drv_video_init(void)
wdenkc6097192002-11-03 00:24:07 +00001766{
wdenke55402c2004-03-14 16:51:43 +00001767 int skip_dev_init;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +02001768 struct stdio_dev console_dev;
wdenkc6097192002-11-03 00:24:07 +00001769
Wolfgang Denkd0e4e2a2009-05-15 10:07:43 +02001770 /* Check if video initialization should be skipped */
1771 if (board_video_skip())
1772 return 0;
1773
wdenk7dd13292004-07-11 20:04:51 +00001774 /* Init video chip - returns with framebuffer cleared */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001775 skip_dev_init = (video_init() == -1);
wdenkc6097192002-11-03 00:24:07 +00001776
Wolfgang Denk50bc99c2009-05-15 10:07:42 +02001777#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001778 PRINTD("KBD: Keyboard init ...\n");
Wolfgang Denk50bc99c2009-05-15 10:07:42 +02001779 skip_dev_init |= (VIDEO_KBD_INIT_FCT == -1);
1780#endif
wdenkc6097192002-11-03 00:24:07 +00001781
Wolfgang Denk50bc99c2009-05-15 10:07:42 +02001782 if (skip_dev_init)
1783 return 0;
wdenkc6097192002-11-03 00:24:07 +00001784
Wolfgang Denk50bc99c2009-05-15 10:07:42 +02001785 /* Init vga device */
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001786 memset(&console_dev, 0, sizeof(console_dev));
1787 strcpy(console_dev.name, "vga");
Wolfgang Denk50bc99c2009-05-15 10:07:42 +02001788 console_dev.ext = DEV_EXT_VIDEO; /* Video extensions */
1789 console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
1790 console_dev.putc = video_putc; /* 'putc' function */
1791 console_dev.puts = video_puts; /* 'puts' function */
1792 console_dev.tstc = NULL; /* 'tstc' function */
1793 console_dev.getc = NULL; /* 'getc' function */
1794
1795#if !defined(CONFIG_VGA_AS_SINGLE_DEVICE)
1796 /* Also init console device */
1797 console_dev.flags |= DEV_FLAGS_INPUT;
1798 console_dev.tstc = VIDEO_TSTC_FCT; /* 'tstc' function */
1799 console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */
wdenkc6097192002-11-03 00:24:07 +00001800#endif /* CONFIG_VGA_AS_SINGLE_DEVICE */
Wolfgang Denk50bc99c2009-05-15 10:07:42 +02001801
Wolfgang Denk0b4b56e2011-07-29 09:55:27 +00001802 if (stdio_register(&console_dev) != 0)
Wolfgang Denk50bc99c2009-05-15 10:07:42 +02001803 return 0;
1804
1805 /* Return success */
1806 return 1;
wdenkc6097192002-11-03 00:24:07 +00001807}