/root/src/xen/xen/drivers/video/vesa.c
Line | Count | Source (jump to first uncovered line) |
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/xmalloc.h> |
10 | | #include <xen/kernel.h> |
11 | | #include <xen/vga.h> |
12 | | #include <asm/io.h> |
13 | | #include <asm/page.h> |
14 | | #include "font.h" |
15 | | #include "lfb.h" |
16 | | |
17 | 0 | #define vlfb_info vga_console_info.u.vesa_lfb |
18 | | |
19 | | static void lfb_flush(void); |
20 | | |
21 | | static unsigned char *lfb; |
22 | | static const struct font_desc *font; |
23 | | static bool_t vga_compat; |
24 | | |
25 | | static unsigned int vram_total; |
26 | | integer_param("vesa-ram", vram_total); |
27 | | |
28 | | static unsigned int vram_remap; |
29 | | integer_param("vesa-map", vram_remap); |
30 | | |
31 | | static int font_height; |
32 | | static int __init parse_font_height(const char *s) |
33 | 0 | { |
34 | 0 | if ( simple_strtoul(s, &s, 10) == 8 && (*s++ == 'x') ) |
35 | 0 | font_height = simple_strtoul(s, &s, 10); |
36 | 0 | if ( *s != '\0' ) |
37 | 0 | font_height = 0; |
38 | 0 |
|
39 | 0 | return 0; |
40 | 0 | } |
41 | | custom_param("font", parse_font_height); |
42 | | |
43 | | void __init vesa_early_init(void) |
44 | 0 | { |
45 | 0 | unsigned int vram_vmode; |
46 | 0 |
|
47 | 0 | vga_compat = !(vga_console_info.u.vesa_lfb.gbl_caps & 2); |
48 | 0 |
|
49 | 0 | if ( (vlfb_info.bits_per_pixel < 8) || (vlfb_info.bits_per_pixel > 32) ) |
50 | 0 | return; |
51 | 0 |
|
52 | 0 | if ( font_height == 0 ) /* choose a sensible default */ |
53 | 0 | font = ((vlfb_info.height <= 600) ? &font_vga_8x8 : |
54 | 0 | (vlfb_info.height <= 768) ? &font_vga_8x14 : &font_vga_8x16); |
55 | 0 | else if ( font_height <= 8 ) |
56 | 0 | font = &font_vga_8x8; |
57 | 0 | else if ( font_height <= 14 ) |
58 | 0 | font = &font_vga_8x14; |
59 | 0 | else |
60 | 0 | font = &font_vga_8x16; |
61 | 0 |
|
62 | 0 | /* vram_vmode -- that is the amount of memory needed for the |
63 | 0 | * used video mode, i.e. the minimum amount of |
64 | 0 | * memory we need. */ |
65 | 0 | vram_vmode = vlfb_info.height * vlfb_info.bytes_per_line; |
66 | 0 |
|
67 | 0 | /* vram_total -- all video memory we have. Used for mtrr |
68 | 0 | * entries. */ |
69 | 0 | vram_total = vram_total ? (vram_total << 20) : (vlfb_info.lfb_size << 16); |
70 | 0 | vram_total = max_t(unsigned int, vram_total, vram_vmode); |
71 | 0 |
|
72 | 0 | /* vram_remap -- the amount of video memory we are going to |
73 | 0 | * use for vesafb. With modern cards it is no |
74 | 0 | * option to simply use vram_total as that |
75 | 0 | * wastes plenty of kernel address space. */ |
76 | 0 | vram_remap = (vram_remap ? |
77 | 0 | (vram_remap << 20) : |
78 | 0 | ((vram_vmode + (1 << L2_PAGETABLE_SHIFT) - 1) & |
79 | 0 | ~((1 << L2_PAGETABLE_SHIFT) - 1))); |
80 | 0 | vram_remap = max_t(unsigned int, vram_remap, vram_vmode); |
81 | 0 | vram_remap = min_t(unsigned int, vram_remap, vram_total); |
82 | 0 | } |
83 | | |
84 | | void __init vesa_init(void) |
85 | 1 | { |
86 | 1 | struct lfb_prop lfbp; |
87 | 1 | |
88 | 1 | if ( !font ) |
89 | 1 | return; |
90 | 1 | |
91 | 0 | lfbp.font = font; |
92 | 0 | lfbp.bits_per_pixel = vlfb_info.bits_per_pixel; |
93 | 0 | lfbp.bytes_per_line = vlfb_info.bytes_per_line; |
94 | 0 | lfbp.width = vlfb_info.width; |
95 | 0 | lfbp.height = vlfb_info.height; |
96 | 0 | lfbp.flush = lfb_flush; |
97 | 0 | lfbp.text_columns = vlfb_info.width / font->width; |
98 | 0 | lfbp.text_rows = vlfb_info.height / font->height; |
99 | 0 |
|
100 | 0 | lfbp.lfb = lfb = ioremap(vlfb_info.lfb_base, vram_remap); |
101 | 0 | if ( !lfb ) |
102 | 0 | return; |
103 | 0 |
|
104 | 0 | memset(lfb, 0, vram_remap); |
105 | 0 |
|
106 | 0 | printk(XENLOG_INFO "vesafb: framebuffer at %#x, mapped to 0x%p, " |
107 | 0 | "using %uk, total %uk\n", |
108 | 0 | vlfb_info.lfb_base, lfb, |
109 | 0 | vram_remap >> 10, vram_total >> 10); |
110 | 0 | printk(XENLOG_INFO "vesafb: mode is %dx%dx%u, linelength=%d, font %ux%u\n", |
111 | 0 | vlfb_info.width, vlfb_info.height, |
112 | 0 | vlfb_info.bits_per_pixel, vlfb_info.bytes_per_line, |
113 | 0 | font->width, font->height); |
114 | 0 | printk(XENLOG_INFO "vesafb: %scolor: size=%d:%d:%d:%d, " |
115 | 0 | "shift=%d:%d:%d:%d\n", |
116 | 0 | vlfb_info.bits_per_pixel > 8 ? "True" : |
117 | 0 | vga_compat ? "Pseudo" : "Static Pseudo", |
118 | 0 | vlfb_info.rsvd_size, vlfb_info.red_size, |
119 | 0 | vlfb_info.green_size, vlfb_info.blue_size, |
120 | 0 | vlfb_info.rsvd_pos, vlfb_info.red_pos, |
121 | 0 | vlfb_info.green_pos, vlfb_info.blue_pos); |
122 | 0 |
|
123 | 0 | if ( vlfb_info.bits_per_pixel > 8 ) |
124 | 0 | { |
125 | 0 | /* Light grey in truecolor. */ |
126 | 0 | unsigned int grey = 0xaaaaaaaa; |
127 | 0 | lfbp.pixel_on = |
128 | 0 | ((grey >> (32 - vlfb_info. red_size)) << vlfb_info. red_pos) | |
129 | 0 | ((grey >> (32 - vlfb_info.green_size)) << vlfb_info.green_pos) | |
130 | 0 | ((grey >> (32 - vlfb_info. blue_size)) << vlfb_info. blue_pos); |
131 | 0 | } |
132 | 0 | else |
133 | 0 | { |
134 | 0 | /* White(ish) in default pseudocolor palette. */ |
135 | 0 | lfbp.pixel_on = 7; |
136 | 0 | } |
137 | 0 |
|
138 | 0 | if ( lfb_init(&lfbp) < 0 ) |
139 | 0 | return; |
140 | 0 | video_puts = lfb_redraw_puts; |
141 | 0 | } |
142 | | |
143 | | #include <asm/mtrr.h> |
144 | | |
145 | | static unsigned int vesa_mtrr; |
146 | | integer_param("vesa-mtrr", vesa_mtrr); |
147 | | |
148 | | void __init vesa_mtrr_init(void) |
149 | 1 | { |
150 | 1 | static const int mtrr_types[] = { |
151 | 1 | 0, MTRR_TYPE_UNCACHABLE, MTRR_TYPE_WRBACK, |
152 | 1 | MTRR_TYPE_WRCOMB, MTRR_TYPE_WRTHROUGH }; |
153 | 1 | unsigned int size_total; |
154 | 1 | int rc, type; |
155 | 1 | |
156 | 1 | if ( !lfb || (vesa_mtrr == 0) || (vesa_mtrr >= ARRAY_SIZE(mtrr_types)) ) |
157 | 1 | return; |
158 | 1 | |
159 | 0 | type = mtrr_types[vesa_mtrr]; |
160 | 0 | if ( !type ) |
161 | 0 | return; |
162 | 0 |
|
163 | 0 | /* Find the largest power-of-two */ |
164 | 0 | size_total = vram_total; |
165 | 0 | while ( size_total & (size_total - 1) ) |
166 | 0 | size_total &= size_total - 1; |
167 | 0 |
|
168 | 0 | /* Try and find a power of two to add */ |
169 | 0 | do { |
170 | 0 | rc = mtrr_add(vlfb_info.lfb_base, size_total, type, 1); |
171 | 0 | size_total >>= 1; |
172 | 0 | } while ( (size_total >= PAGE_SIZE) && (rc == -EINVAL) ); |
173 | 0 | } |
174 | | |
175 | | static void lfb_flush(void) |
176 | 0 | { |
177 | 0 | if ( vesa_mtrr == 3 ) |
178 | 0 | __asm__ __volatile__ ("sfence" : : : "memory"); |
179 | 0 | } |
180 | | |
181 | | void __init vesa_endboot(bool_t keep) |
182 | 0 | { |
183 | 0 | if ( keep ) |
184 | 0 | { |
185 | 0 | video_puts = lfb_scroll_puts; |
186 | 0 | lfb_carriage_return(); |
187 | 0 | } |
188 | 0 | else |
189 | 0 | { |
190 | 0 | unsigned int i, bpp = (vlfb_info.bits_per_pixel + 7) >> 3; |
191 | 0 | for ( i = 0; i < vlfb_info.height; i++ ) |
192 | 0 | memset(lfb + i * vlfb_info.bytes_per_line, 0, |
193 | 0 | vlfb_info.width * bpp); |
194 | 0 | lfb_flush(); |
195 | 0 | lfb_free(); |
196 | 0 | } |
197 | 0 | } |