corebootfb.c
1 /* 2 * 3 * Copyright (C) 2008 Advanced Micro Devices, Inc. 4 * Copyright (C) 2010 coresystems GmbH 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 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <libpayload.h> 31 #include <coreboot_tables.h> 32 #include <pci.h> 33 #include <video_console.h> 34 #include "font.h" 35 36 struct video_console coreboot_video_console; 37 38 static unsigned int cursor_x = 0, cursor_y = 0, cursor_en = 0; 39 40 /* color definitions for the 16 standard colors */ 41 42 #define VGA_COLOR_DEFAULT 7 43 static const u32 vga_colors[] = { 44 // BLUE | GREEN | RED 45 (0x00 << 16) | (0x00 << 8) | 0x00, 46 (0xAA << 16) | (0x00 << 8) | 0x00, 47 (0x00 << 16) | (0xAA << 8) | 0x00, 48 (0xAA << 16) | (0x55 << 8) | 0x00, 49 (0x00 << 16) | (0x00 << 8) | 0xAA, 50 (0xAA << 16) | (0x00 << 8) | 0xAA, 51 (0x00 << 16) | (0xAA << 8) | 0xAA, 52 (0xAA << 16) | (0xAA << 8) | 0xAA, 53 (0x55 << 16) | (0x55 << 8) | 0x55, 54 (0xFF << 16) | (0x55 << 8) | 0x55, 55 (0x55 << 16) | (0xFF << 8) | 0x55, 56 (0xFF << 16) | (0xFF << 8) | 0x55, 57 (0x55 << 16) | (0x55 << 8) | 0xFF, 58 (0xFF << 16) | (0x55 << 8) | 0xFF, 59 (0x55 << 16) | (0xFF << 8) | 0xFF, 60 (0xFF << 16) | (0xFF << 8) | 0xFF, 61 }; 62 63 static struct cb_framebuffer fbinfo; 64 static unsigned short *chars; 65 66 /* Shorthand for up-to-date virtual framebuffer address */ 67 #define FB ((unsigned char *)phys_to_virt(fbinfo.physical_address)) 68 69 static void corebootfb_scroll_up(void) 70 { 71 unsigned char *dst = FB; 72 unsigned char *src = FB + (fbinfo.bytes_per_line * font_height); 73 int y; 74 75 /* Scroll all lines up */ 76 for (y = 0; y < fbinfo.y_resolution - font_height; y++) { 77 memcpy(dst, src, fbinfo.x_resolution * (fbinfo.bits_per_pixel >> 3)); 78 79 dst += fbinfo.bytes_per_line; 80 src += fbinfo.bytes_per_line; 81 } 82 83 /* Erase last line */ 84 dst = FB + (fbinfo.y_resolution - font_height) * fbinfo.bytes_per_line; 85 86 for (; y < fbinfo.y_resolution; y++) { 87 memset(dst, 0, fbinfo.x_resolution * (fbinfo.bits_per_pixel >> 3)); 88 dst += fbinfo.bytes_per_line; 89 } 90 91 /* And update the char buffer */ 92 dst = (unsigned char *)chars; 93 src = (unsigned char *)(chars + coreboot_video_console.columns); 94 memcpy(dst, src, coreboot_video_console.columns * 95 (coreboot_video_console.rows - 1) * 2); 96 int column; 97 for (column = 0; column < coreboot_video_console.columns; column++) 98 chars[(coreboot_video_console.rows - 1) * coreboot_video_console.columns + column] = (VGA_COLOR_DEFAULT << 8); 99 100 cursor_y--; 101 } 102 103 static void corebootfb_clear(void) 104 { 105 int row, column; 106 unsigned char *ptr = FB; 107 108 /* Clear the screen */ 109 for (row = 0; row < fbinfo.y_resolution; row++) { 110 memset(ptr, 0, fbinfo.x_resolution * (fbinfo.bits_per_pixel >> 3)); 111 ptr += fbinfo.bytes_per_line; 112 } 113 114 /* And update the char buffer */ 115 for(row = 0; row < coreboot_video_console.rows; row++) 116 for (column = 0; column < coreboot_video_console.columns; column++) 117 chars[row * coreboot_video_console.columns + column] = (VGA_COLOR_DEFAULT << 8); 118 } 119 120 static void corebootfb_putchar(u8 row, u8 col, unsigned int ch) 121 { 122 unsigned char *dst; 123 124 unsigned char bg = (ch >> 12) & 0xF; 125 unsigned char fg = (ch >> 8) & 0xF; 126 u32 fgval = 0, bgval = 0; 127 u16 *dst16; 128 u32 *dst32; 129 130 int x, y; 131 132 if (fbinfo.bits_per_pixel > 8) { 133 bgval = ((((vga_colors[bg] >> 0) & 0xff) >> (8 - fbinfo.blue_mask_size)) << fbinfo.blue_mask_pos) | 134 ((((vga_colors[bg] >> 8) & 0xff) >> (8 - fbinfo.green_mask_size)) << fbinfo.green_mask_pos) | 135 ((((vga_colors[bg] >> 16) & 0xff) >> (8 - fbinfo.red_mask_size)) << fbinfo.red_mask_pos); 136 fgval = ((((vga_colors[fg] >> 0) & 0xff) >> (8 - fbinfo.blue_mask_size)) << fbinfo.blue_mask_pos) | 137 ((((vga_colors[fg] >> 8) & 0xff) >> (8 - fbinfo.green_mask_size)) << fbinfo.green_mask_pos) | 138 ((((vga_colors[fg] >> 16) & 0xff) >> (8 - fbinfo.red_mask_size)) << fbinfo.red_mask_pos); 139 } 140 141 dst = FB + ((row * font_height) * fbinfo.bytes_per_line); 142 dst += (col * font_width * (fbinfo.bits_per_pixel >> 3)); 143 144 for(y = 0; y < font_height; y++) { 145 for(x = font_width - 1; x >= 0; x--) { 146 147 switch (fbinfo.bits_per_pixel) { 148 case 8: /* Indexed */ 149 dst[(font_width - x) * (fbinfo.bits_per_pixel >> 3)] = font_glyph_filled(ch, x, y) ? fg : bg; 150 break; 151 case 16: /* 16 bpp */ 152 dst16 = (u16 *)(dst + (font_width - x) * (fbinfo.bits_per_pixel >> 3)); 153 *dst16 = font_glyph_filled(ch, x, y) ? fgval : bgval; 154 break; 155 case 24: /* 24 bpp */ 156 if (font_glyph_filled(ch, x, y)) { 157 dst[(font_width - x) * (fbinfo.bits_per_pixel >> 3) + 0] = fgval & 0xff; 158 dst[(font_width - x) * (fbinfo.bits_per_pixel >> 3) + 1] = (fgval >> 8) & 0xff; 159 dst[(font_width - x) * (fbinfo.bits_per_pixel >> 3) + 2] = (fgval >> 16) & 0xff; 160 } else { 161 dst[(font_width - x) * (fbinfo.bits_per_pixel >> 3) + 0] = bgval & 0xff; 162 dst[(font_width - x) * (fbinfo.bits_per_pixel >> 3) + 1] = (bgval >> 8) & 0xff; 163 dst[(font_width - x) * (fbinfo.bits_per_pixel >> 3) + 2] = (bgval >> 16) & 0xff; 164 } 165 break; 166 case 32: /* 32 bpp */ 167 dst32 = (u32 *)(dst + (font_width - x) * (fbinfo.bits_per_pixel >> 3)); 168 *dst32 = font_glyph_filled(ch, x, y) ? fgval : bgval; 169 break; 170 } 171 } 172 173 dst += fbinfo.bytes_per_line; 174 } 175 } 176 177 static void corebootfb_putc(u8 row, u8 col, unsigned int ch) 178 { 179 chars[row * coreboot_video_console.columns + col] = ch; 180 corebootfb_putchar(row, col, ch); 181 } 182 183 static void corebootfb_update_cursor(void) 184 { 185 int ch, paint; 186 if(cursor_en) { 187 ch = chars[cursor_y * coreboot_video_console.columns + cursor_x]; 188 paint = (ch & 0xff) | ((ch << 4) & 0xf000) | ((ch >> 4) & 0x0f00); 189 } else { 190 paint = chars[cursor_y * coreboot_video_console.columns + cursor_x]; 191 } 192 193 if (cursor_y < coreboot_video_console.rows) 194 corebootfb_putchar(cursor_y, cursor_x, paint); 195 } 196 197 static void corebootfb_enable_cursor(int state) 198 { 199 cursor_en = state; 200 corebootfb_update_cursor(); 201 } 202 203 static void corebootfb_get_cursor(unsigned int *x, unsigned int *y, unsigned int *en) 204 { 205 *x = cursor_x; 206 *y = cursor_y; 207 *en = cursor_en; 208 } 209 210 static void corebootfb_set_cursor(unsigned int x, unsigned int y) 211 { 212 int cursor_remember = cursor_en; 213 if (cursor_remember) 214 corebootfb_enable_cursor(0); 215 216 cursor_x = x; 217 cursor_y = y; 218 219 if (cursor_remember) 220 corebootfb_enable_cursor(1); 221 } 222 223 static int corebootfb_init(void) 224 { 225 if (!lib_sysinfo.framebuffer.physical_address) 226 return -1; 227 228 fbinfo = lib_sysinfo.framebuffer; 229 230 font_init(fbinfo.x_resolution); 231 232 /* Draw centered on the framebuffer if requested and feasible, */ 233 const int center = 234 IS_ENABLED(CONFIG_LP_COREBOOT_VIDEO_CENTERED) 235 && coreboot_video_console.columns * font_width <= fbinfo.x_resolution 236 && coreboot_video_console.rows * font_height <= fbinfo.y_resolution; 237 /* adapt to the framebuffer size, otherwise. */ 238 if (!center) { 239 coreboot_video_console.columns = fbinfo.x_resolution / font_width; 240 coreboot_video_console.rows = fbinfo.y_resolution / font_height; 241 } 242 243 chars = malloc(coreboot_video_console.rows * 244 coreboot_video_console.columns * 2); 245 if (!chars) 246 return -1; 247 248 // clear boot splash screen if there is one. 249 corebootfb_clear(); 250 251 if (center) { 252 fbinfo.physical_address += 253 (fbinfo.x_resolution - coreboot_video_console.columns * font_width) 254 / 2 * fbinfo.bits_per_pixel / 8 255 + (fbinfo.y_resolution - coreboot_video_console.rows * font_height) 256 / 2 * fbinfo.bytes_per_line; 257 fbinfo.x_resolution = coreboot_video_console.columns * font_width; 258 fbinfo.y_resolution = coreboot_video_console.rows * font_height; 259 } 260 261 return 0; 262 } 263 264 struct video_console coreboot_video_console = { 265 .init = corebootfb_init, 266 .putc = corebootfb_putc, 267 .clear = corebootfb_clear, 268 .scroll_up = corebootfb_scroll_up, 269 270 .get_cursor = corebootfb_get_cursor, 271 .set_cursor = corebootfb_set_cursor, 272 .enable_cursor = corebootfb_enable_cursor, 273 274 .columns = 80, 275 .rows = 25 276 };