1 /******************************************************************************
2 * vesa.c
3 *
4 * VESA linear frame buffer handling.
5 */
6
7 #include <xen/init.h>
8 #include <xen/lib.h>
9 #include <xen/param.h>
10 #include <xen/xmalloc.h>
11 #include <xen/kernel.h>
12 #include <xen/mm.h>
13 #include <xen/vga.h>
14 #include <asm/io.h>
15 #include "font.h"
16 #include "lfb.h"
17
18 #define vlfb_info vga_console_info.u.vesa_lfb
19
20 static void cf_check lfb_flush(void);
21
22 static unsigned char *__read_mostly lfb;
23 static const struct font_desc *__initdata font;
24 static bool __initdata vga_compat;
25
26 static unsigned int __initdata vram_total;
27 integer_param("vesa-ram", vram_total);
28
29 static unsigned int __initdata vram_remap;
30
31 static unsigned int __initdata font_height;
parse_font_height(const char * s)32 static int __init cf_check parse_font_height(const char *s)
33 {
34 if ( simple_strtoul(s, &s, 10) == 8 && (*s++ == 'x') )
35 font_height = simple_strtoul(s, &s, 10);
36 if ( *s != '\0' )
37 font_height = 0;
38
39 return 0;
40 }
41 custom_param("font", parse_font_height);
42
lfb_base(void)43 static inline paddr_t lfb_base(void)
44 {
45 return ((paddr_t)vlfb_info.ext_lfb_base << 32) | vlfb_info.lfb_base;
46 }
47
vesa_early_init(void)48 void __init vesa_early_init(void)
49 {
50 unsigned int vram_vmode;
51
52 vga_compat = !(vlfb_info.gbl_caps & 2);
53
54 if ( (vlfb_info.bits_per_pixel < 8) || (vlfb_info.bits_per_pixel > 32) )
55 return;
56
57 if ( font_height == 0 ) /* choose a sensible default */
58 font = ((vlfb_info.height <= 600) ? &font_vga_8x8 :
59 (vlfb_info.height <= 768) ? &font_vga_8x14 : &font_vga_8x16);
60 else if ( font_height <= 8 )
61 font = &font_vga_8x8;
62 else if ( font_height <= 14 )
63 font = &font_vga_8x14;
64 else
65 font = &font_vga_8x16;
66
67 /* vram_vmode -- that is the amount of memory needed for the
68 * used video mode, i.e. the minimum amount of
69 * memory we need. */
70 vram_vmode = vlfb_info.height * vlfb_info.bytes_per_line;
71
72 /* vram_total -- all video memory we have. Used for mtrr
73 * entries. */
74 vram_total = vram_total ? (vram_total << 20) : (vlfb_info.lfb_size << 16);
75 vram_total = max_t(unsigned int, vram_total, vram_vmode);
76
77 /* vram_remap -- the amount of video memory we are going to
78 * use for vesafb. With modern cards it is no
79 * option to simply use vram_total as that
80 * wastes plenty of kernel address space. */
81 vram_remap = ROUNDUP(vram_vmode, 1 << L2_PAGETABLE_SHIFT);
82 vram_remap = min(vram_remap, vram_total);
83 }
84
vesa_init(void)85 void __init vesa_init(void)
86 {
87 struct lfb_prop lfbp;
88
89 if ( !font )
90 return;
91
92 lfbp.font = font;
93 lfbp.bits_per_pixel = vlfb_info.bits_per_pixel;
94 lfbp.bytes_per_line = vlfb_info.bytes_per_line;
95 lfbp.width = vlfb_info.width;
96 lfbp.height = vlfb_info.height;
97 lfbp.flush = lfb_flush;
98 lfbp.text_columns = vlfb_info.width / font->width;
99 lfbp.text_rows = vlfb_info.height / font->height;
100
101 lfbp.lfb = lfb = ioremap_wc(lfb_base(), vram_remap);
102 if ( !lfb )
103 return;
104
105 memset(lfb, 0, vram_remap);
106
107 printk(XENLOG_INFO "vesafb: framebuffer at 0x%" PRIpaddr ", mapped to 0x%p, using %uk, total %uk\n",
108 lfb_base(), lfb,
109 vram_remap >> 10, vram_total >> 10);
110 printk(XENLOG_INFO "vesafb: mode is %dx%dx%u, linelength=%d, font %ux%u\n",
111 vlfb_info.width, vlfb_info.height,
112 vlfb_info.bits_per_pixel, vlfb_info.bytes_per_line,
113 font->width, font->height);
114 printk(XENLOG_INFO "vesafb: %scolor: size=%d:%d:%d:%d, "
115 "shift=%d:%d:%d:%d\n",
116 vlfb_info.bits_per_pixel > 8 ? "True" :
117 vga_compat ? "Pseudo" : "Static Pseudo",
118 vlfb_info.rsvd_size, vlfb_info.red_size,
119 vlfb_info.green_size, vlfb_info.blue_size,
120 vlfb_info.rsvd_pos, vlfb_info.red_pos,
121 vlfb_info.green_pos, vlfb_info.blue_pos);
122
123 if ( vlfb_info.bits_per_pixel > 8 )
124 {
125 /* Light grey in truecolor. */
126 unsigned int grey = 0xaaaaaaaaU;
127 lfbp.pixel_on =
128 ((grey >> (32 - vlfb_info. red_size)) << vlfb_info. red_pos) |
129 ((grey >> (32 - vlfb_info.green_size)) << vlfb_info.green_pos) |
130 ((grey >> (32 - vlfb_info. blue_size)) << vlfb_info. blue_pos);
131 }
132 else
133 {
134 /* White(ish) in default pseudocolor palette. */
135 lfbp.pixel_on = 7;
136 }
137
138 if ( lfb_init(&lfbp) < 0 )
139 return;
140 video_puts = lfb_redraw_puts;
141 }
142
lfb_flush(void)143 static void cf_check lfb_flush(void)
144 {
145 __asm__ __volatile__ ("sfence" : : : "memory");
146 }
147
vesa_endboot(bool keep)148 void __init vesa_endboot(bool keep)
149 {
150 if ( keep )
151 {
152 video_puts = lfb_scroll_puts;
153 lfb_carriage_return();
154 }
155 else
156 {
157 unsigned int i, bpp = (vlfb_info.bits_per_pixel + 7) >> 3;
158 for ( i = 0; i < vlfb_info.height; i++ )
159 memset(lfb + i * vlfb_info.bytes_per_line, 0,
160 vlfb_info.width * bpp);
161 lfb_flush();
162 lfb_free();
163 iounmap(lfb);
164 lfb = ZERO_BLOCK_PTR;
165 }
166 }
167