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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f245145 was 24a44ec, checked in by Jiri Svoboda <jirik.svoboda@…>, 17 years ago

Another memmove() instead of memcpy().

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