libpayload: The initial chunk of code writen by AMD
[coreboot.git] / payloads / libpayload / drivers / vga.c
1 /*
2  * This file is part of the libpayload project.
3  *
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
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 <arch/types.h>
31 #include <libpayload.h>
32
33 #define WIDTH 80
34 #define HEIGHT 25
35
36 #define VGA_COLOR_WHITE 7
37
38 #define CRTC_INDEX      0x3d4
39 #define CRTC_DATA       0x3d5
40
41 #define VIDEO(_r, _c)\
42   ((uint16_t *) (0xB8000 + ((_r) * (WIDTH * 2)) + ((_c) * 2)))
43
44 static int cursor_enabled;
45 static int cursorx;
46 static int cursory;
47
48 static void vga_scroll_up(void);
49
50 static inline uint8_t crtc_read(uint8_t index)
51 {
52         outb(index, CRTC_INDEX);
53         return inb(CRTC_DATA);
54 }
55
56 static inline void crtc_write(uint8_t data, uint8_t index)
57 {
58         outb(index, CRTC_INDEX);
59         outb(data, CRTC_DATA);
60 }
61
62 static void vga_get_cursor_pos(void)
63 {
64         unsigned int addr;
65         addr = ((unsigned int) crtc_read(0x0E)) << 8;
66         addr += crtc_read(0x0E);
67
68         cursorx = addr % WIDTH;
69         cursory = addr / WIDTH;       
70 }
71
72 static void vga_fixup_cursor(void)
73 {
74         unsigned int addr;
75
76         if (!cursor_enabled)
77                 return;
78
79         if (cursorx < 0)
80                 cursorx = 0;
81         
82         if (cursory < 0)
83                 cursory = 0;
84         
85         if (cursorx >= WIDTH) {
86                 cursorx = 0;
87                 cursory++;
88         }
89
90         while(cursory >= HEIGHT)
91                 vga_scroll_up();
92
93         addr = cursorx + (WIDTH * cursory);
94         crtc_write(addr >> 8, 0x0E);
95         crtc_write(addr, 0x0E);
96 }
97
98 void vga_cursor_enable(int state)
99 {
100         unsigned char tmp = crtc_read(0x0a);
101
102         if (state == 0) {
103                 tmp |= (1 << 5);
104                 cursor_enabled = 0;
105         }
106         else {
107                 tmp &= ~(1 << 5);
108                 cursor_enabled = 1;
109                 vga_fixup_cursor();
110         }
111
112         crtc_write(tmp, 0x0a);
113 }
114
115 void vga_clear_line(uint8_t row, uint8_t ch, uint8_t attr)
116 {
117         int col;
118         uint16_t *ptr = VIDEO(0, row);
119
120         for(col = 0; col < WIDTH; col++)
121                 ptr[col] = ((attr & 0xFF) << 8) | (ch & 0xFF);
122 }
123         
124 static void vga_scroll_up(void)
125 {
126         uint16_t *src = VIDEO(0,1);
127         uint16_t *dst = VIDEO(0,0);
128         int i;
129
130         for(i = 0; i < (HEIGHT - 1) * WIDTH; i++)
131                 *dst++ = *src++;
132         
133         vga_clear_line(HEIGHT - 1, ' ', VGA_COLOR_WHITE);
134         cursory--;
135 }
136
137 void vga_fill(uint8_t ch, uint8_t attr)
138 {
139         uint8_t row;
140         for(row = 0; row < HEIGHT; row++)
141                 vga_clear_line(row, ch, attr);
142 }
143
144 void vga_clear(void)
145 {
146         vga_fill(' ', VGA_COLOR_WHITE);
147         vga_move_cursor(0, 0);
148 }
149
150 void vga_putc(uint8_t row, uint8_t col, unsigned int c)
151 {
152         uint16_t *ptr = VIDEO(row, col);
153         *ptr = (uint16_t) (c & 0xFFFF);
154 }
155
156 void vga_putchar(unsigned int ch) {
157         
158         uint16_t *ptr;
159
160         switch(ch & 0xFF) {
161         case '\r':
162                 cursorx = 0;
163                 break;
164         case '\n':
165                 cursory++;
166                 break;
167         case '\b':
168                 cursorx--;
169                 ptr = VIDEO(cursory, cursorx);
170                 *ptr = (*ptr & 0xFF00) | ' ';
171                 break;
172         case '\t':
173                 cursorx = (cursorx + 8) & ~7;
174                 break;
175
176         default:
177                 ptr = VIDEO(cursory, cursorx);
178                 *ptr = (uint16_t) (ch & 0xFFFF);
179                 cursorx++;
180                 break;
181         }
182
183         vga_fixup_cursor();
184 }
185
186 int vga_move_cursor(int x, int y)
187 {
188         cursorx = x;
189         cursory = y;
190         
191         vga_fixup_cursor();
192 }
193
194 void vga_init(void)
195 {
196         /* Get the position of the cursor */
197         vga_get_cursor_pos();
198
199         /* See if it us currently enabled or not */
200         cursor_enabled = !(crtc_read(0x0A) & (1 << 5));
201
202         /* If the cursor is enabled, get us to a sane point */
203
204         if (cursor_enabled) {
205
206                 /* Go to the next line */
207
208                 if (cursorx) {
209                         cursorx = 0;
210                         cursory++;
211                 }
212
213                 vga_fixup_cursor();
214         }
215 }
216