source: mainline/kernel/genarch/src/fb/fb.c@ e49b57b2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e49b57b2 was 19490ce, checked in by Jakub Jermar <jakub@…>, 17 years ago

Fix 16bpp modes.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*
2 * Copyright (c) 2008 Martin Decky
3 * Copyright (c) 2006 Ondrej Palkovsky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup genarch
31 * @{
32 */
33/** @file
34 */
35
36#include <genarch/fb/font-8x16.h>
37#include <genarch/fb/logo-196x66.h>
38#include <genarch/fb/visuals.h>
39#include <genarch/fb/fb.h>
40#include <console/chardev.h>
41#include <console/console.h>
42#include <sysinfo/sysinfo.h>
43#include <mm/slab.h>
44#include <align.h>
45#include <panic.h>
46#include <memstr.h>
47#include <config.h>
48#include <bitops.h>
49#include <print.h>
50#include <string.h>
51#include <ddi/ddi.h>
52#include <arch/types.h>
53#include <byteorder.h>
54
55SPINLOCK_INITIALIZE(fb_lock);
56
57static uint8_t *fb_addr;
58static uint16_t *backbuf;
59static uint8_t *glyphs;
60static uint8_t *bgscan;
61
62static unsigned int xres;
63static unsigned int yres;
64
65static unsigned int ylogo;
66static unsigned int ytrim;
67static unsigned int rowtrim;
68
69static unsigned int scanline;
70static unsigned int glyphscanline;
71
72static unsigned int pixelbytes;
73static unsigned int glyphbytes;
74static unsigned int bgscanbytes;
75
76static unsigned int cols;
77static unsigned int rows;
78static unsigned int position = 0;
79
80#define BG_COLOR 0x000080
81#define FG_COLOR 0xffff00
82#define INV_COLOR 0xaaaaaa
83
84#define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
85#define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
86#define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
87
88#define COL2X(col) ((col) * FONT_WIDTH)
89#define ROW2Y(row) ((row) * FONT_SCANLINES)
90
91#define X2COL(x) ((x) / FONT_WIDTH)
92#define Y2ROW(y) ((y) / FONT_SCANLINES)
93
94#define FB_POS(x, y) ((y) * scanline + (x) * pixelbytes)
95#define BB_POS(col, row) ((row) * cols + (col))
96#define GLYPH_POS(glyph, y) ((glyph) * glyphbytes + (y) * glyphscanline)
97
98
99static void (*rgb_conv)(void *, uint32_t);
100
101/*
102 * RGB conversion functions.
103 *
104 * These functions write an RGB value to some memory in some predefined format.
105 * The naming convention corresponds to the format created by these functions.
106 * The functions use the so called network order (i.e. big endian) with respect
107 * to their names.
108 */
109
110static void rgb_0888(void *dst, uint32_t rgb)
111{
112 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
113 (RED(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (BLUE(rgb, 8)));
114}
115
116static void bgr_0888(void *dst, uint32_t rgb)
117{
118 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
119 (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (RED(rgb, 8)));
120}
121
122static void rgb_8880(void *dst, uint32_t rgb)
123{
124 *((uint32_t *) dst) = host2uint32_t_be((RED(rgb, 8) << 24) |
125 (GREEN(rgb, 8) << 16) | (BLUE(rgb, 8) << 8) | 0);
126}
127
128static void bgr_8880(void *dst, uint32_t rgb)
129{
130 *((uint32_t *) dst) = host2uint32_t_be((BLUE(rgb, 8) << 24) |
131 (GREEN(rgb, 8) << 16) | (RED(rgb, 8) << 8) | 0);
132}
133
134static void rgb_888(void *dst, uint32_t rgb)
135{
136 ((uint8_t *) dst)[0] = RED(rgb, 8);
137 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
138 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
139}
140
141static void bgr_888(void *dst, uint32_t rgb)
142{
143 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
144 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
145 ((uint8_t *) dst)[2] = RED(rgb, 8);
146}
147
148static void rgb_555_be(void *dst, uint32_t rgb)
149{
150 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 10 |
151 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
152}
153
154static void rgb_555_le(void *dst, uint32_t rgb)
155{
156 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 10 |
157 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
158}
159
160static void rgb_565_be(void *dst, uint32_t rgb)
161{
162 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 11 |
163 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
164}
165
166static void rgb_565_le(void *dst, uint32_t rgb)
167{
168 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 11 |
169 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
170}
171
172
173/** BGR 3:2:3
174 *
175 * Even though we try 3:2:3 color scheme here, an 8-bit framebuffer
176 * will most likely use a color palette. The color appearance
177 * will be pretty random and depend on the default installed
178 * palette. This could be fixed by supporting custom palette
179 * and setting it to simulate the 8-bit truecolor.
180 *
181 * Currently we set the palette on the ia32, amd64 and sparc64 port.
182 *
183 * Note that the byte is being inverted by this function. The reason is
184 * that we would like to use a color palette where the white color code
185 * is 0 and the black color code is 255, as some machines (Sun Blade 1500)
186 * use these codes for black and white and prevent to set codes
187 * 0 and 255 to other colors.
188 *
189 */
190static void bgr_323(void *dst, uint32_t rgb)
191{
192 *((uint8_t *) dst)
193 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
194}
195
196
197/** Hide logo and refresh screen
198 *
199 */
200static void logo_hide(bool silent)
201{
202 ylogo = 0;
203 ytrim = yres;
204 rowtrim = rows;
205 if (!silent)
206 fb_redraw();
207}
208
209
210/** Draw character at given position
211 *
212 */
213static void glyph_draw(uint16_t glyph, unsigned int col, unsigned int row, bool silent, bool overlay)
214{
215 unsigned int x = COL2X(col);
216 unsigned int y = ROW2Y(row);
217 unsigned int yd;
218
219 if (y >= ytrim)
220 logo_hide(silent);
221
222 if (!overlay)
223 backbuf[BB_POS(col, row)] = glyph;
224
225 if (!silent) {
226 for (yd = 0; yd < FONT_SCANLINES; yd++)
227 memcpy(&fb_addr[FB_POS(x, y + yd + ylogo)],
228 &glyphs[GLYPH_POS(glyph, yd)], glyphscanline);
229 }
230}
231
232
233/** Scroll screen down by one row
234 *
235 *
236 */
237static void screen_scroll(bool silent)
238{
239 if (ylogo > 0) {
240 logo_hide(silent);
241 return;
242 }
243
244 if (!silent) {
245 unsigned int row;
246
247 for (row = 0; row < rows; row++) {
248 unsigned int y = ROW2Y(row);
249 unsigned int yd;
250
251 for (yd = 0; yd < FONT_SCANLINES; yd++) {
252 unsigned int x;
253 unsigned int col;
254
255 for (col = 0, x = 0; col < cols; col++,
256 x += FONT_WIDTH) {
257 uint16_t glyph;
258
259 if (row < rows - 1) {
260 if (backbuf[BB_POS(col, row)] ==
261 backbuf[BB_POS(col, row + 1)])
262 continue;
263
264 glyph = backbuf[BB_POS(col, row + 1)];
265 } else
266 glyph = 0;
267
268 memcpy(&fb_addr[FB_POS(x, y + yd)],
269 &glyphs[GLYPH_POS(glyph, yd)],
270 glyphscanline);
271 }
272 }
273 }
274 }
275
276 memmove(backbuf, &backbuf[BB_POS(0, 1)], cols * (rows - 1) * sizeof(uint16_t));
277 memsetw(&backbuf[BB_POS(0, rows - 1)], cols, 0);
278}
279
280
281static void cursor_put(bool silent)
282{
283 unsigned int col = position % cols;
284 unsigned int row = position / cols;
285
286 glyph_draw(fb_font_glyph(U_CURSOR), col, row, silent, true);
287}
288
289
290static void cursor_remove(bool silent)
291{
292 unsigned int col = position % cols;
293 unsigned int row = position / cols;
294
295 glyph_draw(backbuf[BB_POS(col, row)], col, row, silent, true);
296}
297
298
299/** Print character to screen
300 *
301 * Emulate basic terminal commands.
302 *
303 */
304static void fb_putchar(outdev_t *dev, wchar_t ch, bool silent)
305{
306 spinlock_lock(&fb_lock);
307
308 switch (ch) {
309 case '\n':
310 cursor_remove(silent);
311 position += cols;
312 position -= position % cols;
313 break;
314 case '\r':
315 cursor_remove(silent);
316 position -= position % cols;
317 break;
318 case '\b':
319 cursor_remove(silent);
320 if (position % cols)
321 position--;
322 break;
323 case '\t':
324 cursor_remove(silent);
325 do {
326 glyph_draw(fb_font_glyph(' '), position % cols,
327 position / cols, silent, false);
328 position++;
329 } while ((position % 8) && (position < cols * rows));
330 break;
331 default:
332 glyph_draw(fb_font_glyph(ch), position % cols,
333 position / cols, silent, false);
334 position++;
335 }
336
337 if (position >= cols * rows) {
338 position -= cols;
339 screen_scroll(silent);
340 }
341
342 cursor_put(silent);
343
344 spinlock_unlock(&fb_lock);
345}
346
347static outdev_t fb_console;
348static outdev_operations_t fb_ops = {
349 .write = fb_putchar
350};
351
352
353/** Render glyphs
354 *
355 * Convert glyphs from device independent font
356 * description to current visual representation.
357 *
358 */
359static void glyphs_render(void)
360{
361 /* Prerender glyphs */
362 uint16_t glyph;
363
364 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
365 uint32_t fg_color;
366
367 if (glyph == FONT_GLYPHS - 1)
368 fg_color = INV_COLOR;
369 else
370 fg_color = FG_COLOR;
371
372 unsigned int y;
373
374 for (y = 0; y < FONT_SCANLINES; y++) {
375 unsigned int x;
376
377 for (x = 0; x < FONT_WIDTH; x++) {
378 void *dst = &glyphs[GLYPH_POS(glyph, y) +
379 x * pixelbytes];
380 uint32_t rgb = (fb_font[glyph][y] &
381 (1 << (7 - x))) ? fg_color : BG_COLOR;
382 rgb_conv(dst, rgb);
383 }
384 }
385 }
386
387 /* Prerender background scanline */
388 unsigned int x;
389
390 for (x = 0; x < xres; x++)
391 rgb_conv(&bgscan[x * pixelbytes], BG_COLOR);
392}
393
394
395/** Refresh the screen
396 *
397 */
398void fb_redraw(void)
399{
400 if (ylogo > 0) {
401 unsigned int y;
402
403 for (y = 0; y < LOGO_HEIGHT; y++) {
404 unsigned int x;
405
406 for (x = 0; x < xres; x++)
407 rgb_conv(&fb_addr[FB_POS(x, y)],
408 (x < LOGO_WIDTH) ?
409 fb_logo[y * LOGO_WIDTH + x] :
410 LOGO_COLOR);
411 }
412 }
413
414 unsigned int row;
415
416 for (row = 0; row < rowtrim; row++) {
417 unsigned int y = ylogo + ROW2Y(row);
418 unsigned int yd;
419
420 for (yd = 0; yd < FONT_SCANLINES; yd++) {
421 unsigned int x;
422 unsigned int col;
423
424 for (col = 0, x = 0; col < cols;
425 col++, x += FONT_WIDTH) {
426 uint16_t glyph = backbuf[BB_POS(col, row)];
427 void *dst = &fb_addr[FB_POS(x, y + yd)];
428 void *src = &glyphs[GLYPH_POS(glyph, yd)];
429 memcpy(dst, src, glyphscanline);
430 }
431 }
432 }
433
434 if (COL2X(cols) < xres) {
435 unsigned int y;
436 unsigned int size = (xres - COL2X(cols)) * pixelbytes;
437
438 for (y = ylogo; y < yres; y++)
439 memcpy(&fb_addr[FB_POS(COL2X(cols), y)], bgscan, size);
440 }
441
442 if (ROW2Y(rowtrim) + ylogo < yres) {
443 unsigned int y;
444
445 for (y = ROW2Y(rowtrim) + ylogo; y < yres; y++)
446 memcpy(&fb_addr[FB_POS(0, y)], bgscan, bgscanbytes);
447 }
448}
449
450
451/** Initialize framebuffer as a output character device
452 *
453 * @param addr Physical address of the framebuffer
454 * @param x Screen width in pixels
455 * @param y Screen height in pixels
456 * @param scan Bytes per one scanline
457 * @param visual Color model
458 *
459 */
460void fb_init(fb_properties_t *props)
461{
462 switch (props->visual) {
463 case VISUAL_INDIRECT_8:
464 rgb_conv = bgr_323;
465 pixelbytes = 1;
466 break;
467 case VISUAL_RGB_5_5_5_LE:
468 rgb_conv = rgb_555_le;
469 pixelbytes = 2;
470 break;
471 case VISUAL_RGB_5_5_5_BE:
472 rgb_conv = rgb_555_be;
473 pixelbytes = 2;
474 break;
475 case VISUAL_RGB_5_6_5_LE:
476 rgb_conv = rgb_565_le;
477 pixelbytes = 2;
478 break;
479 case VISUAL_RGB_5_6_5_BE:
480 rgb_conv = rgb_565_be;
481 pixelbytes = 2;
482 break;
483 case VISUAL_RGB_8_8_8:
484 rgb_conv = rgb_888;
485 pixelbytes = 3;
486 break;
487 case VISUAL_BGR_8_8_8:
488 rgb_conv = bgr_888;
489 pixelbytes = 3;
490 break;
491 case VISUAL_RGB_8_8_8_0:
492 rgb_conv = rgb_8880;
493 pixelbytes = 4;
494 break;
495 case VISUAL_RGB_0_8_8_8:
496 rgb_conv = rgb_0888;
497 pixelbytes = 4;
498 break;
499 case VISUAL_BGR_0_8_8_8:
500 rgb_conv = bgr_0888;
501 pixelbytes = 4;
502 break;
503 case VISUAL_BGR_8_8_8_0:
504 rgb_conv = bgr_8880;
505 pixelbytes = 4;
506 break;
507 default:
508 panic("Unsupported visual.");
509 }
510
511 xres = props->x;
512 yres = props->y;
513 scanline = props->scan;
514
515 cols = X2COL(xres);
516 rows = Y2ROW(yres);
517
518 if (yres > ylogo) {
519 ylogo = LOGO_HEIGHT;
520 rowtrim = rows - Y2ROW(ylogo);
521 if (ylogo % FONT_SCANLINES > 0)
522 rowtrim--;
523 ytrim = ROW2Y(rowtrim);
524 } else {
525 ylogo = 0;
526 ytrim = yres;
527 rowtrim = rows;
528 }
529
530 glyphscanline = FONT_WIDTH * pixelbytes;
531 glyphbytes = ROW2Y(glyphscanline);
532 bgscanbytes = xres * pixelbytes;
533
534 size_t fbsize = scanline * yres;
535 size_t bbsize = cols * rows * sizeof(uint16_t);
536 size_t glyphsize = FONT_GLYPHS * glyphbytes;
537
538 backbuf = (uint16_t *) malloc(bbsize, 0);
539 if (!backbuf)
540 panic("Unable to allocate backbuffer.");
541
542 glyphs = (uint8_t *) malloc(glyphsize, 0);
543 if (!glyphs)
544 panic("Unable to allocate glyphs.");
545
546 bgscan = malloc(bgscanbytes, 0);
547 if (!bgscan)
548 panic("Unable to allocate background pixel.");
549
550 memsetw(backbuf, cols * rows, 0);
551
552 glyphs_render();
553
554 fb_addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
555
556 sysinfo_set_item_val("fb", NULL, true);
557 sysinfo_set_item_val("fb.kind", NULL, 1);
558 sysinfo_set_item_val("fb.width", NULL, xres);
559 sysinfo_set_item_val("fb.height", NULL, yres);
560 sysinfo_set_item_val("fb.scanline", NULL, scanline);
561 sysinfo_set_item_val("fb.visual", NULL, props->visual);
562 sysinfo_set_item_val("fb.address.physical", NULL, props->addr);
563
564 fb_redraw();
565
566 outdev_initialize("fb", &fb_console, &fb_ops);
567 stdout = &fb_console;
568}
569
570/** @}
571 */
Note: See TracBrowser for help on using the repository browser.