1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Miniature VGA driver for bootstrap.
29 */
30
31 #include <sys/archsystm.h>
32 #include <sys/vgareg.h>
33 #include <sys/framebuffer.h>
34 #include <sys/boot_console.h>
35 #include <sys/tem_impl.h>
36 #include "boot_console_impl.h"
37
38 #include "boot_vga.h"
39
40 #if defined(_BOOT)
41 #include "../dboot/dboot_asm.h"
42 #include "../dboot/dboot_xboot.h"
43 #endif
44
45 #if defined(__xpv) && defined(_BOOT)
46
47 /*
48 * Device memory address
49 *
50 * In dboot under the hypervisor we don't have any memory mappings
51 * for the first meg of low memory so we can't access devices there.
52 * Intead we've mapped the device memory that we need to access into
53 * a local variable within dboot so we can access the device memory
54 * there.
55 */
56 extern unsigned short *video_fb;
57 #define VGA_SCREEN (video_fb)
58
59 #else /* __xpv && _BOOT */
60
61 /* Device memory address */
62 #define VGA_SCREEN ((unsigned short *)0xb8000)
63
64 #endif /* __xpv && _BOOT */
65
66 static int cons_color = CONS_COLOR;
67
68 static void vga_init(void);
69 static void vga_drawc(int);
70 static void vga_setpos(int, int);
71 static void vga_getpos(int *, int *);
72 static void vga_scroll(int);
73 static void vga_clear(int);
74 static void vga_shiftline(int);
75 static void vga_eraseline(void);
76 static void vga_cursor_display(boolean_t);
77
78 static void vga_set_crtc(int index, unsigned char val);
79 static unsigned char vga_get_crtc(int index);
80 static void vga_set_atr(int index, unsigned char val);
81 static unsigned char vga_get_atr(int index);
82
83 static int
84 set_vga_color(void)
85 {
86 int color;
87 uint8_t tmp;
88
89 /*
90 * Now we have two principal cases, black on white and white on black.
91 * And we have possible inverse to switch them, and we want to
92 * follow the tem logic.. to set VGA TEXT color. FB will take care
93 * of itself in boot_fb.c
94 */
95 if (fb_info.inverse == B_TRUE ||
96 fb_info.inverse_screen == B_TRUE) {
97 tmp = dim_xlate[fb_info.fg_color];
98 color = solaris_color_to_pc_color[tmp] << 4;
99 tmp = brt_xlate[fb_info.bg_color];
100 color |= solaris_color_to_pc_color[tmp];
101 return (color);
102 }
103
104 /* use bright white for background */
105 if (fb_info.bg_color == 7)
106 tmp = brt_xlate[fb_info.bg_color];
107 else
108 tmp = dim_xlate[fb_info.bg_color];
109
110 color = solaris_color_to_pc_color[tmp] << 4;
111 tmp = dim_xlate[fb_info.fg_color];
112 color |= solaris_color_to_pc_color[tmp];
113 return (color);
114 }
115
116 void
117 boot_vga_init(bcons_dev_t *bcons_dev)
118 {
119 fb_info.terminal.x = VGA_TEXT_COLS;
120 fb_info.terminal.y = VGA_TEXT_ROWS;
121 cons_color = set_vga_color();
122
123 #if defined(_BOOT)
124 /* Note that we have to enable the cursor before clearing the
125 * screen since the cursor position is dependant upon the cursor
126 * skew, which is initialized by vga_cursor_display()
127 */
128 vga_init();
129 fb_info.cursor.visible = B_FALSE;
130 vga_cursor_display(B_TRUE);
131
132 if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0)
133 vga_clear(cons_color);
134 #endif /* _BOOT */
135
136 bcons_dev->bd_putchar = vga_drawc;
137 bcons_dev->bd_eraseline = vga_eraseline;
138 bcons_dev->bd_cursor = vga_cursor_display;
139 bcons_dev->bd_setpos = vga_setpos;
140 bcons_dev->bd_shift = vga_shiftline;
141 }
142
143 static void
144 vga_init(void)
145 {
146 unsigned char val;
147
148 /* set 16bit colors */
149 val = vga_get_atr(VGA_ATR_MODE);
150 val &= ~VGA_ATR_MODE_BLINK;
151 val &= ~VGA_ATR_MODE_9WIDE;
152 vga_set_atr(VGA_ATR_MODE, val);
153 }
154
155 void
156 vga_cursor_display(boolean_t visible)
157 {
158 unsigned char val, msl;
159
160 if (fb_info.cursor.visible == visible)
161 return;
162
163 /*
164 * Figure out the maximum scan line value. We need this to set the
165 * cursor size.
166 */
167 msl = vga_get_crtc(VGA_CRTC_MAX_S_LN) & 0x1f;
168
169 /*
170 * Enable the cursor and set it's size. Preserve the upper two
171 * bits of the control register.
172 * - Bits 0-4 are the starting scan line of the cursor.
173 * Scanning is done from top-to-bottom. The top-most scan
174 * line is 0 and the bottom most scan line is the maximum scan
175 * line value.
176 * - Bit 5 is the cursor disable bit.
177 */
178 val = vga_get_crtc(VGA_CRTC_CSSL) & 0xc0;
179
180 if (visible == B_FALSE)
181 val |= (1 << 5);
182
183 vga_set_crtc(VGA_CRTC_CSSL, val);
184
185 /*
186 * Continue setting the cursors size.
187 * - Bits 0-4 are the ending scan line of the cursor.
188 * Scanning is done from top-to-bottom. The top-most scan
189 * line is 0 and the bottom most scan line is the maximum scan
190 * line value.
191 * - Bits 5-6 are the cursor skew.
192 */
193 vga_set_crtc(VGA_CRTC_CESL, msl);
194 }
195
196 static void
197 vga_eraseline_impl(int x, int y, int color)
198 {
199 unsigned short val, *buf;
200 int i;
201
202 buf = VGA_SCREEN + x + y * VGA_TEXT_COLS;
203 val = (color << 8) | ' ';
204 for (i = x; i < VGA_TEXT_COLS; i++)
205 buf[i] = val;
206 }
207
208 static void
209 vga_eraseline(void)
210 {
211 int x, y;
212
213 x = fb_info.cursor.pos.x;
214 y = fb_info.cursor.pos.y;
215 vga_eraseline_impl(x, y, cons_color);
216 }
217
218 static void
219 vga_shiftline(int chars)
220 {
221 unsigned short *src, *dst;
222 int x, y, len;
223
224 x = fb_info.cursor.pos.x;
225 y = fb_info.cursor.pos.y;
226 len = VGA_TEXT_COLS - x - chars;
227
228 src = VGA_SCREEN + x + y * VGA_TEXT_COLS;
229 dst = src + chars;
230 if (dst <= src) {
231 do {
232 *dst++ = *src++;
233 } while (--len != 0);
234 } else {
235 dst += len;
236 src += len;
237 do {
238 *--dst = *--src;
239 } while (--len != 0);
240 }
241 }
242
243 static void
244 vga_clear(int color)
245 {
246 int i;
247
248 for (i = 0; i < VGA_TEXT_ROWS; i++)
249 vga_eraseline_impl(0, i, color);
250 }
251
252 static void
253 vga_drawc(int c)
254 {
255 int row;
256 int col;
257
258 vga_getpos(&row, &col);
259
260 if (c == '\n') {
261 if (row < fb_info.terminal.y - 1)
262 vga_setpos(row + 1, col);
263 else
264 vga_scroll(cons_color);
265 return;
266 }
267
268 VGA_SCREEN[row*VGA_TEXT_COLS + col] = (cons_color << 8) | c;
269
270 if (col < VGA_TEXT_COLS - 1)
271 vga_setpos(row, col + 1);
272 else if (row < VGA_TEXT_ROWS - 1)
273 vga_setpos(row + 1, 0);
274 else {
275 vga_setpos(row, 0);
276 vga_scroll(cons_color);
277 }
278 }
279
280 static void
281 vga_scroll(int color)
282 {
283 int i;
284
285 for (i = 0; i < (VGA_TEXT_ROWS - 1) * VGA_TEXT_COLS; i++) {
286 VGA_SCREEN[i] = VGA_SCREEN[i + VGA_TEXT_COLS];
287 }
288 vga_eraseline_impl(0, VGA_TEXT_ROWS - 1, color);
289 }
290
291 static void
292 vga_setpos(int row, int col)
293 {
294 int off;
295
296 if (row < 0)
297 row = 0;
298 if (row >= fb_info.terminal.y)
299 row = fb_info.terminal.y - 1;
300 if (col < 0)
301 col = 0;
302 if (col >= fb_info.terminal.x)
303 col = fb_info.terminal.x - 1;
304
305 off = row * VGA_TEXT_COLS + col;
306 vga_set_crtc(VGA_CRTC_CLAH, off >> 8);
307 vga_set_crtc(VGA_CRTC_CLAL, off & 0xff);
308
309 fb_info.cursor.pos.y = row;
310 fb_info.cursor.pos.x = col;
311 }
312
313 static void
314 vga_getpos(int *row, int *col)
315 {
316 int off;
317
318 off = (vga_get_crtc(VGA_CRTC_CLAH) << 8) + vga_get_crtc(VGA_CRTC_CLAL);
319 *row = off / VGA_TEXT_COLS;
320 *col = off % VGA_TEXT_COLS;
321 }
322
323 static void
324 vga_set_atr(int index, unsigned char val)
325 {
326 (void) inb(VGA_REG_ADDR + CGA_STAT);
327 outb(VGA_REG_ADDR + VGA_ATR_AD, index);
328 outb(VGA_REG_ADDR + VGA_ATR_AD, val);
329
330 (void) inb(VGA_REG_ADDR + CGA_STAT);
331 outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT);
332 }
333
334 static unsigned char
335 vga_get_atr(int index)
336 {
337 unsigned char val;
338
339 (void) inb(VGA_REG_ADDR + CGA_STAT);
340 outb(VGA_REG_ADDR + VGA_ATR_AD, index);
341 val = inb(VGA_REG_ADDR + VGA_ATR_DATA);
342
343 (void) inb(VGA_REG_ADDR + CGA_STAT);
344 outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT);
345
346 return (val);
347 }
348
349 static void
350 vga_set_crtc(int index, unsigned char val)
351 {
352 outb(VGA_REG_ADDR + VGA_CRTC_ADR, index);
353 outb(VGA_REG_ADDR + VGA_CRTC_DATA, val);
354 }
355
356 static unsigned char
357 vga_get_crtc(int index)
358 {
359 outb(VGA_REG_ADDR + VGA_CRTC_ADR, index);
360 return (inb(VGA_REG_ADDR + VGA_CRTC_DATA));
361 }