xref: /illumos-gate/usr/src/uts/i86pc/boot/boot_vga.c (revision 8549f3a1b574354ace01065ded5d1da81c2b91aa)
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 
35 #include "boot_console_impl.h"
36 #if defined(_BOOT)
37 #include "../dboot/dboot_asm.h"
38 #include "../dboot/dboot_xboot.h"
39 #endif
40 
41 #if defined(__xpv) && defined(_BOOT)
42 
43 /*
44  * Device memory address
45  *
46  * In dboot under the hypervisor we don't have any memory mappings
47  * for the first meg of low memory so we can't access devices there.
48  * Intead we've mapped the device memory that we need to access into
49  * a local variable within dboot so we can access the device memory
50  * there.
51  */
52 extern unsigned short *video_fb;
53 #define	VGA_SCREEN		((unsigned short *)video_fb)
54 
55 #else /* __xpv && _BOOT */
56 
57 /* Device memory address */
58 #define	VGA_SCREEN	((uint16_t *)(VGA_MEM_ADDR + VGA_COLOR_BASE))
59 
60 #endif /* __xpv && _BOOT */
61 
62 
63 static void vga_init(void);
64 static void vga_cursor_display(void);
65 static void vga_clear(int);
66 static void vga_set_crtc(int index, unsigned char val);
67 static unsigned char vga_get_crtc(int index);
68 static void vga_set_atr(int index, unsigned char val);
69 static unsigned char vga_get_atr(int index);
70 
71 void
72 boot_vga_init(int cons_color)
73 {
74 	fb_info.terminal.x = VGA_TEXT_COLS;
75 	fb_info.terminal.y = VGA_TEXT_ROWS;
76 
77 #if defined(_BOOT)
78 	/*
79 	 * Note that we have to enable the cursor before clearing the
80 	 * screen since the cursor position is dependant upon the cursor
81 	 * skew, which is initialized by vga_cursor_display()
82 	 */
83 	vga_init();
84 	fb_info.cursor.visible = B_FALSE;
85 	vga_cursor_display();
86 
87 	/*
88 	 * In general we should avoid resetting the display during the boot,
89 	 * we may have valueable messages there, this why the "native" loader
90 	 * boot does pass the console state down to kernel and we do try to
91 	 * pick the state. However, the loader is not the only way to boot.
92 	 * The non-native boot loaders do not implement the smooth console.
93 	 * If we have no information about cursor location, we will get value
94 	 * (0, 0) and that means we better clear the screen.
95 	 */
96 	if (fb_info.cursor.pos.x == 0 && fb_info.cursor.pos.y == 0)
97 		vga_clear(cons_color);
98 	vga_setpos(fb_info.cursor.pos.y, fb_info.cursor.pos.x);
99 #endif /* _BOOT */
100 }
101 
102 static void
103 vga_init(void)
104 {
105 	unsigned char val;
106 
107 	/* set 16bit colors */
108 	val = vga_get_atr(VGA_ATR_MODE);
109 	val &= ~VGA_ATR_MODE_BLINK;
110 	val &= ~VGA_ATR_MODE_9WIDE;
111 	vga_set_atr(VGA_ATR_MODE, val);
112 }
113 
114 static void
115 vga_cursor_display(void)
116 {
117 	unsigned char val, msl;
118 
119 	/*
120 	 * Figure out the maximum scan line value.  We need this to set the
121 	 * cursor size.
122 	 */
123 	msl = vga_get_crtc(VGA_CRTC_MAX_S_LN) & 0x1f;
124 
125 	/*
126 	 * Enable the cursor and set it's size.  Preserve the upper two
127 	 * bits of the control register.
128 	 * - Bits 0-4 are the starting scan line of the cursor.
129 	 *   Scanning is done from top-to-bottom.  The top-most scan
130 	 *   line is 0 and the bottom most scan line is the maximum scan
131 	 *   line value.
132 	 * - Bit 5 is the cursor disable bit.
133 	 */
134 	val = vga_get_crtc(VGA_CRTC_CSSL) & 0xc0;
135 	vga_set_crtc(VGA_CRTC_CSSL, val);
136 
137 	/*
138 	 * Continue setting the cursors size.
139 	 * - Bits 0-4 are the ending scan line of the cursor.
140 	 *   Scanning is done from top-to-bottom.  The top-most scan
141 	 *   line is 0 and the bottom most scan line is the maximum scan
142 	 *   line value.
143 	 * - Bits 5-6 are the cursor skew.
144 	 */
145 	vga_set_crtc(VGA_CRTC_CESL, msl);
146 }
147 
148 
149 static void
150 vga_clear(int color)
151 {
152 	unsigned short val;
153 	int i;
154 
155 	val = (color << 8) | ' ';
156 
157 	for (i = 0; i < VGA_TEXT_ROWS * VGA_TEXT_COLS; i++) {
158 		VGA_SCREEN[i] = val;
159 	}
160 }
161 
162 void
163 vga_drawc(int c, int color)
164 {
165 	int row;
166 	int col;
167 
168 	vga_getpos(&row, &col);
169 	VGA_SCREEN[row*VGA_TEXT_COLS + col] = (color << 8) | c;
170 }
171 
172 void
173 vga_scroll(int color)
174 {
175 	unsigned short val;
176 	int i;
177 
178 	val = (color << 8) | ' ';
179 
180 	for (i = 0; i < (VGA_TEXT_ROWS-1)*VGA_TEXT_COLS; i++) {
181 		VGA_SCREEN[i] = VGA_SCREEN[i + VGA_TEXT_COLS];
182 	}
183 	for (; i < VGA_TEXT_ROWS * VGA_TEXT_COLS; i++) {
184 		VGA_SCREEN[i] = val;
185 	}
186 }
187 
188 void
189 vga_setpos(int row, int col)
190 {
191 	int off;
192 
193 	off = row * VGA_TEXT_COLS + col;
194 	vga_set_crtc(VGA_CRTC_CLAH, off >> 8);
195 	vga_set_crtc(VGA_CRTC_CLAL, off & 0xff);
196 
197 	fb_info.cursor.pos.y = row;
198 	fb_info.cursor.pos.x = col;
199 }
200 
201 void
202 vga_getpos(int *row, int *col)
203 {
204 	int off;
205 
206 	off = (vga_get_crtc(VGA_CRTC_CLAH) << 8) + vga_get_crtc(VGA_CRTC_CLAL);
207 	*row = off / VGA_TEXT_COLS;
208 	*col = off % VGA_TEXT_COLS;
209 }
210 
211 static void
212 vga_set_atr(int index, unsigned char val)
213 {
214 	(void) inb(VGA_REG_ADDR + CGA_STAT);
215 	outb(VGA_REG_ADDR + VGA_ATR_AD, index);
216 	outb(VGA_REG_ADDR + VGA_ATR_AD, val);
217 
218 	(void) inb(VGA_REG_ADDR + CGA_STAT);
219 	outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT);
220 }
221 
222 static unsigned char
223 vga_get_atr(int index)
224 {
225 	unsigned char val;
226 
227 	(void) inb(VGA_REG_ADDR + CGA_STAT);
228 	outb(VGA_REG_ADDR + VGA_ATR_AD, index);
229 	val = inb(VGA_REG_ADDR + VGA_ATR_DATA);
230 
231 	(void) inb(VGA_REG_ADDR + CGA_STAT);
232 	outb(VGA_REG_ADDR + VGA_ATR_AD, VGA_ATR_ENB_PLT);
233 
234 	return (val);
235 }
236 
237 static void
238 vga_set_crtc(int index, unsigned char val)
239 {
240 	outb(VGA_REG_ADDR + VGA_CRTC_ADR, index);
241 	outb(VGA_REG_ADDR + VGA_CRTC_DATA, val);
242 }
243 
244 static unsigned char
245 vga_get_crtc(int index)
246 {
247 	outb(VGA_REG_ADDR + VGA_CRTC_ADR, index);
248 	return (inb(VGA_REG_ADDR + VGA_CRTC_DATA));
249 }
250