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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c43b1db2 was ae318d3, checked in by Martin Decky <martin@…>, 16 years ago

overhaul pareas: use one single physical area for the physical address space not belonging to physical memory

  • Property mode set to 100644
File size: 11.8 KB
RevLine 
[bbf5657]1/*
[76fca31]2 * Copyright (c) 2008 Martin Decky
[df4ed85]3 * Copyright (c) 2006 Ondrej Palkovsky
[bbf5657]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
[76fca31]30/** @addtogroup genarch
[b45c443]31 * @{
32 */
33/** @file
34 */
35
[fe050b7]36#include <genarch/fb/font-8x16.h>
[6e71a9d8]37#include <genarch/fb/logo-196x66.h>
[2bc137c2]38#include <genarch/fb/visuals.h>
[fe050b7]39#include <genarch/fb/fb.h>
[bbf5657]40#include <console/chardev.h>
41#include <console/console.h>
[2666daa]42#include <sysinfo/sysinfo.h>
[74d1d66]43#include <mm/slab.h>
[76fca31]44#include <align.h>
[fcbca14f]45#include <panic.h>
[d87c3f3]46#include <memstr.h>
[74d1d66]47#include <config.h>
[6eb96fce]48#include <bitops.h>
49#include <print.h>
[f8ddd17]50#include <ddi/ddi.h>
[730376d]51#include <arch/types.h>
[bbf5657]52
[76fca31]53SPINLOCK_INITIALIZE(fb_lock);
[c2942d8]54
[76fca31]55static uint8_t *fb_addr;
56static uint8_t *backbuf;
57static uint8_t *glyphs;
[6e71a9d8]58static uint8_t *bgscan;
[bbf5657]59
[76fca31]60static unsigned int xres;
61static unsigned int yres;
[74d1d66]62
[6e71a9d8]63static unsigned int ylogo;
64static unsigned int ytrim;
65static unsigned int rowtrim;
66
[76fca31]67static unsigned int scanline;
68static unsigned int glyphscanline;
69
70static unsigned int pixelbytes;
71static unsigned int glyphbytes;
[6e71a9d8]72static unsigned int bgscanbytes;
[bbf5657]73
[76fca31]74static unsigned int cols;
75static unsigned int rows;
[a2c4445]76static unsigned int position = 0;
[bbf5657]77
[76fca31]78#define BG_COLOR 0x000080
79#define FG_COLOR 0xffff00
[a2c4445]80
[76fca31]81#define CURSOR 219
[a2c4445]82
[76fca31]83#define RED(x, bits) ((x >> (8 + 8 + 8 - bits)) & ((1 << bits) - 1))
84#define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
85#define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
[a2c4445]86
[76fca31]87#define COL2X(col) ((col) * FONT_WIDTH)
88#define ROW2Y(row) ((row) * FONT_SCANLINES)
[95c7526]89
[76fca31]90#define X2COL(x) ((x) / FONT_WIDTH)
91#define Y2ROW(y) ((y) / FONT_SCANLINES)
[bbf5657]92
[76fca31]93#define FB_POS(x, y) ((y) * scanline + (x) * pixelbytes)
94#define BB_POS(col, row) ((row) * cols + (col))
95#define GLYPH_POS(glyph, y) ((glyph) * glyphbytes + (y) * glyphscanline)
[fcbca14f]96
[253f35a1]97
[76fca31]98static void (*rgb_conv)(void *, uint32_t);
[95c7526]99
[fcbca14f]100
[76fca31]101/** ARGB 8:8:8:8 conversion
102 *
103 */
104static void rgb_0888(void *dst, uint32_t rgb)
[ccb0cbc]105{
[76fca31]106 *((uint32_t *) dst) = rgb & 0xffffff;
[ccb0cbc]107}
108
[76fca31]109
110/** ABGR 8:8:8:8 conversion
111 *
112 */
113static void bgr_0888(void *dst, uint32_t rgb)
[ccb0cbc]114{
[76fca31]115 *((uint32_t *) dst)
116 = (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | RED(rgb, 8);
[ccb0cbc]117}
118
[76fca31]119
[95b9963]120/** RGB 8:8:8 conversion
[76fca31]121 *
122 */
123static void rgb_888(void *dst, uint32_t rgb)
[fcbca14f]124{
[6e71a9d8]125 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
126 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
127 ((uint8_t *) dst)[2] = RED(rgb, 8);
[95b9963]128}
129
130
131/** BGR 8:8:8 conversion
132 *
133 */
134static void bgr_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);
[fcbca14f]139}
140
[95c7526]141
[76fca31]142/** RGB 5:5:5 conversion
143 *
144 */
145static void rgb_555(void *dst, uint32_t rgb)
[2bc137c2]146{
[76fca31]147 *((uint16_t *) dst)
148 = (RED(rgb, 5) << 10) | (GREEN(rgb, 5) << 5) | BLUE(rgb, 5);
[2bc137c2]149}
150
151
[76fca31]152/** RGB 5:6:5 conversion
153 *
154 */
155static void rgb_565(void *dst, uint32_t rgb)
[fcbca14f]156{
[76fca31]157 *((uint16_t *) dst)
158 = (RED(rgb, 5) << 11) | (GREEN(rgb, 6) << 5) | BLUE(rgb, 5);
[fcbca14f]159}
160
161
[76fca31]162/** RGB 3:2:3
[b4fa652]163 *
164 * Even though we try 3:2:3 color scheme here, an 8-bit framebuffer
165 * will most likely use a color palette. The color appearance
166 * will be pretty random and depend on the default installed
167 * palette. This could be fixed by supporting custom palette
168 * and setting it to simulate the 8-bit truecolor.
[925fdd7]169 *
[882d7a8]170 * Currently we set the palette on the ia32, amd64 and sparc64 port.
[925fdd7]171 *
172 * Note that the byte is being inverted by this function. The reason is
173 * that we would like to use a color palette where the white color code
[882d7a8]174 * is 0 and the black color code is 255, as some machines (Sun Blade 1500)
[925fdd7]175 * use these codes for black and white and prevent to set codes
176 * 0 and 255 to other colors.
[882d7a8]177 *
[b4fa652]178 */
[76fca31]179static void rgb_323(void *dst, uint32_t rgb)
[fcbca14f]180{
[76fca31]181 *((uint8_t *) dst)
182 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
[fcbca14f]183}
184
[76fca31]185
[6e71a9d8]186/** Hide logo and refresh screen
187 *
188 */
[516ff92]189static void logo_hide(bool silent)
[6e71a9d8]190{
191 ylogo = 0;
192 ytrim = yres;
193 rowtrim = rows;
[516ff92]194 if (!silent)
195 fb_redraw();
[6e71a9d8]196}
197
198
[76fca31]199/** Draw character at given position
[b4fa652]200 *
201 */
[516ff92]202static void glyph_draw(uint8_t glyph, unsigned int col, unsigned int row, bool silent)
[bbf5657]203{
[76fca31]204 unsigned int x = COL2X(col);
205 unsigned int y = ROW2Y(row);
206 unsigned int yd;
207
[6e71a9d8]208 if (y >= ytrim)
[516ff92]209 logo_hide(silent);
[6e71a9d8]210
[76fca31]211 backbuf[BB_POS(col, row)] = glyph;
212
[516ff92]213 if (!silent) {
214 for (yd = 0; yd < FONT_SCANLINES; yd++)
215 memcpy(&fb_addr[FB_POS(x, y + yd + ylogo)],
216 &glyphs[GLYPH_POS(glyph, yd)], glyphscanline);
217 }
[bbf5657]218}
219
[a2c4445]220
[76fca31]221/** Scroll screen down by one row
222 *
223 *
224 */
[516ff92]225static void screen_scroll(bool silent)
[bbf5657]226{
[6c0adbc]227 if (ylogo > 0) {
[516ff92]228 logo_hide(silent);
[6c0adbc]229 return;
230 }
[6e71a9d8]231
[516ff92]232 if (!silent) {
233 unsigned int row;
[730376d]234
[516ff92]235 for (row = 0; row < rows; row++) {
236 unsigned int y = ROW2Y(row);
237 unsigned int yd;
[76fca31]238
[516ff92]239 for (yd = 0; yd < FONT_SCANLINES; yd++) {
240 unsigned int x;
241 unsigned int col;
[76fca31]242
[516ff92]243 for (col = 0, x = 0; col < cols; col++,
244 x += FONT_WIDTH) {
245 uint8_t glyph;
[76fca31]246
[516ff92]247 if (row < rows - 1) {
248 if (backbuf[BB_POS(col, row)] ==
249 backbuf[BB_POS(col, row + 1)])
250 continue;
251
252 glyph = backbuf[BB_POS(col, row + 1)];
253 } else
254 glyph = 0;
255
256 memcpy(&fb_addr[FB_POS(x, y + yd)],
257 &glyphs[GLYPH_POS(glyph, yd)],
258 glyphscanline);
259 }
[76fca31]260 }
[51baa8a]261 }
[6eb96fce]262 }
[76fca31]263
[24a44ec]264 memmove(backbuf, backbuf + cols, cols * (rows - 1));
[76fca31]265 memsetb(&backbuf[BB_POS(0, rows - 1)], cols, 0);
[a2c4445]266}
267
268
[516ff92]269static void cursor_put(bool silent)
[bbf5657]270{
[516ff92]271 glyph_draw(CURSOR, position % cols, position / cols, silent);
[bbf5657]272}
273
274
[516ff92]275static void cursor_remove(bool silent)
[bbf5657]276{
[516ff92]277 glyph_draw(0, position % cols, position / cols, silent);
[bbf5657]278}
279
280
281/** Print character to screen
282 *
[76fca31]283 * Emulate basic terminal commands.
284 *
[bbf5657]285 */
[516ff92]286static void fb_putchar(chardev_t *dev, char ch, bool silent)
[bbf5657]287{
[22cf454d]288 spinlock_lock(&fb_lock);
[a2c4445]289
290 switch (ch) {
[06e1e95]291 case '\n':
[516ff92]292 cursor_remove(silent);
[76fca31]293 position += cols;
294 position -= position % cols;
[06e1e95]295 break;
296 case '\r':
[516ff92]297 cursor_remove(silent);
[76fca31]298 position -= position % cols;
[06e1e95]299 break;
300 case '\b':
[516ff92]301 cursor_remove(silent);
[76fca31]302 if (position % cols)
[06e1e95]303 position--;
304 break;
305 case '\t':
[516ff92]306 cursor_remove(silent);
[06e1e95]307 do {
[edf5774]308 glyph_draw((uint8_t) ' ', position % cols,
[516ff92]309 position / cols, silent);
[95c7526]310 position++;
[76fca31]311 } while ((position % 8) && (position < cols * rows));
[06e1e95]312 break;
313 default:
[516ff92]314 glyph_draw((uint8_t) ch, position % cols,
315 position / cols, silent);
[06e1e95]316 position++;
[bbf5657]317 }
[a2c4445]318
[76fca31]319 if (position >= cols * rows) {
320 position -= cols;
[516ff92]321 screen_scroll(silent);
[bbf5657]322 }
[a2c4445]323
[516ff92]324 cursor_put(silent);
[a2c4445]325
[22cf454d]326 spinlock_unlock(&fb_lock);
[bbf5657]327}
328
329static chardev_t framebuffer;
330static chardev_operations_t fb_ops = {
331 .write = fb_putchar,
332};
333
334
[76fca31]335/** Render glyphs
336 *
337 * Convert glyphs from device independent font
338 * description to current visual representation.
339 *
340 */
[6e71a9d8]341static void glyphs_render(void)
[76fca31]342{
[6e71a9d8]343 /* Prerender glyphs */
[76fca31]344 unsigned int glyph;
345
346 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
347 unsigned int y;
348
349 for (y = 0; y < FONT_SCANLINES; y++) {
350 unsigned int x;
351
[edf5774]352 for (x = 0; x < FONT_WIDTH; x++) {
353 void *dst = &glyphs[GLYPH_POS(glyph, y) +
354 x * pixelbytes];
355 uint32_t rgb = (fb_font[ROW2Y(glyph) + y] &
356 (1 << (7 - x))) ? FG_COLOR : BG_COLOR;
357 rgb_conv(dst, rgb);
358 }
[76fca31]359 }
360 }
361
[6e71a9d8]362 /* Prerender background scanline */
363 unsigned int x;
364
365 for (x = 0; x < xres; x++)
366 rgb_conv(&bgscan[x * pixelbytes], BG_COLOR);
[76fca31]367}
368
369
370/** Refresh the screen
371 *
372 */
373void fb_redraw(void)
374{
[6e71a9d8]375 if (ylogo > 0) {
376 unsigned int y;
377
378 for (y = 0; y < LOGO_HEIGHT; y++) {
379 unsigned int x;
380
381 for (x = 0; x < xres; x++)
382 rgb_conv(&fb_addr[FB_POS(x, y)],
[edf5774]383 (x < LOGO_WIDTH) ?
384 fb_logo[y * LOGO_WIDTH + x] :
385 LOGO_COLOR);
[6e71a9d8]386 }
387 }
388
[76fca31]389 unsigned int row;
390
[6e71a9d8]391 for (row = 0; row < rowtrim; row++) {
392 unsigned int y = ylogo + ROW2Y(row);
[76fca31]393 unsigned int yd;
394
395 for (yd = 0; yd < FONT_SCANLINES; yd++) {
396 unsigned int x;
397 unsigned int col;
398
[edf5774]399 for (col = 0, x = 0; col < cols;
400 col++, x += FONT_WIDTH) {
401 void *d = &fb_addr[FB_POS(x, y + yd)];
402 void *s = &glyphs[GLYPH_POS(backbuf[BB_POS(col,
403 row)], yd)];
404 memcpy(d, s, glyphscanline);
405 }
[76fca31]406 }
407 }
408
409 if (COL2X(cols) < xres) {
410 unsigned int y;
[6e71a9d8]411 unsigned int size = (xres - COL2X(cols)) * pixelbytes;
[76fca31]412
[6e71a9d8]413 for (y = ylogo; y < yres; y++)
414 memcpy(&fb_addr[FB_POS(COL2X(cols), y)], bgscan, size);
[76fca31]415 }
416
[6c0adbc]417 if (ROW2Y(rowtrim) + ylogo < yres) {
[76fca31]418 unsigned int y;
419
[6c0adbc]420 for (y = ROW2Y(rowtrim) + ylogo; y < yres; y++)
[6e71a9d8]421 memcpy(&fb_addr[FB_POS(0, y)], bgscan, bgscanbytes);
[76fca31]422 }
423}
424
425
[bbf5657]426/** Initialize framebuffer as a chardev output device
427 *
[76fca31]428 * @param addr Physical address of the framebuffer
429 * @param x Screen width in pixels
430 * @param y Screen height in pixels
431 * @param scan Bytes per one scanline
432 * @param visual Color model
433 *
[bbf5657]434 */
[965dc18]435void fb_init(fb_properties_t *props)
[bbf5657]436{
[965dc18]437 switch (props->visual) {
[2bc137c2]438 case VISUAL_INDIRECT_8:
[76fca31]439 rgb_conv = rgb_323;
[d6f270f]440 pixelbytes = 1;
441 break;
[2bc137c2]442 case VISUAL_RGB_5_5_5:
[76fca31]443 rgb_conv = rgb_555;
[2bc137c2]444 pixelbytes = 2;
445 break;
446 case VISUAL_RGB_5_6_5:
[76fca31]447 rgb_conv = rgb_565;
[d6f270f]448 pixelbytes = 2;
449 break;
[2bc137c2]450 case VISUAL_RGB_8_8_8:
[76fca31]451 rgb_conv = rgb_888;
[2bc137c2]452 pixelbytes = 3;
453 break;
[95b9963]454 case VISUAL_BGR_8_8_8:
455 rgb_conv = bgr_888;
456 pixelbytes = 3;
457 break;
[2bc137c2]458 case VISUAL_RGB_8_8_8_0:
[76fca31]459 rgb_conv = rgb_888;
[2bc137c2]460 pixelbytes = 4;
[d6f270f]461 break;
[2bc137c2]462 case VISUAL_RGB_0_8_8_8:
[76fca31]463 rgb_conv = rgb_0888;
[d6f270f]464 pixelbytes = 4;
465 break;
[ccb0cbc]466 case VISUAL_BGR_0_8_8_8:
[76fca31]467 rgb_conv = bgr_0888;
[ccb0cbc]468 pixelbytes = 4;
469 break;
[d6f270f]470 default:
[f651e80]471 panic("Unsupported visual.");
[fcbca14f]472 }
[8424198]473
[965dc18]474 xres = props->x;
475 yres = props->y;
476 scanline = props->scan;
[bbf5657]477
[6e71a9d8]478 cols = X2COL(xres);
479 rows = Y2ROW(yres);
480
481 if (yres > ylogo) {
482 ylogo = LOGO_HEIGHT;
483 rowtrim = rows - Y2ROW(ylogo);
484 if (ylogo % FONT_SCANLINES > 0)
485 rowtrim--;
486 ytrim = ROW2Y(rowtrim);
487 } else {
488 ylogo = 0;
489 ytrim = yres;
490 rowtrim = rows;
491 }
[76fca31]492
493 glyphscanline = FONT_WIDTH * pixelbytes;
[6e71a9d8]494 glyphbytes = ROW2Y(glyphscanline);
495 bgscanbytes = xres * pixelbytes;
[76fca31]496
497 unsigned int fbsize = scanline * yres;
498 unsigned int bbsize = cols * rows;
499 unsigned int glyphsize = FONT_GLYPHS * glyphbytes;
500
501 backbuf = (uint8_t *) malloc(bbsize, 0);
502 if (!backbuf)
[f651e80]503 panic("Unable to allocate backbuffer.");
[76fca31]504
505 glyphs = (uint8_t *) malloc(glyphsize, 0);
506 if (!glyphs)
[f651e80]507 panic("Unable to allocate glyphs.");
[76fca31]508
[6e71a9d8]509 bgscan = malloc(bgscanbytes, 0);
510 if (!bgscan)
[f651e80]511 panic("Unable to allocate background pixel.");
[76fca31]512
513 memsetb(backbuf, bbsize, 0);
514
[6e71a9d8]515 glyphs_render();
[76fca31]516
517 fb_addr = (uint8_t *) hw_map((uintptr_t) props->addr, fbsize);
518
[8060a24c]519 sysinfo_set_item_val("fb", NULL, true);
520 sysinfo_set_item_val("fb.kind", NULL, 1);
521 sysinfo_set_item_val("fb.width", NULL, xres);
522 sysinfo_set_item_val("fb.height", NULL, yres);
[76fca31]523 sysinfo_set_item_val("fb.scanline", NULL, scanline);
[965dc18]524 sysinfo_set_item_val("fb.visual", NULL, props->visual);
525 sysinfo_set_item_val("fb.address.physical", NULL, props->addr);
[800eaf5]526
[76fca31]527 fb_redraw();
528
[bbf5657]529 chardev_initialize("fb", &framebuffer, &fb_ops);
530 stdout = &framebuffer;
531}
[b45c443]532
[94d614e]533/** @}
[b45c443]534 */
Note: See TracBrowser for help on using the repository browser.