* factor out serial hardware init
[coreboot.git] / payloads / libpayload / drivers / serial.c
1 /*
2  * This file is part of the libpayload project.
3  *
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
5  * Copyright (C) 2008 Ulf Jordan <jordan@chalmers.se>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <config.h>
32 #include <libpayload.h>
33
34 #define IOBASE lib_sysinfo.ser_ioport
35 #define DIVISOR(x) (115200 / x)
36
37 void serial_hardware_init(int port, int speed, int word_bits, int parity, int stop_bits)
38 {
39         unsigned char reg;
40
41         /* We will assume 8n1 for now. Does anyone use anything else these days? */
42
43         /* Disable interrupts. */
44         outb(0, port + 0x01);
45
46         /* Assert RTS and DTR. */
47         outb(3, port + 0x04);
48
49         /* Set the divisor latch. */
50         reg = inb(port + 0x03);
51         outb(reg | 0x80, port + 0x03);
52
53         /* Write the divisor. */
54         outb(DIVISOR(speed) & 0xFF, port);
55         outb(DIVISOR(speed) >> 8 & 0xFF, port + 1);
56
57         /* Restore the previous value of the divisor. */
58         outb(reg &= ~0x80, port + 0x03);
59 }
60
61 void serial_init(void)
62 {
63 #ifdef CONFIG_SERIAL_SET_SPEED
64         serial_hardware_init(IOBASE, CONFIG_SERIAL_BAUD_RATE, 8, 0, 1);
65 #endif
66 }
67
68 void serial_putchar(unsigned char c)
69 {
70         while ((inb(IOBASE + 0x05) & 0x20) == 0) ;
71         outb(c, IOBASE);
72 }
73
74 int serial_havechar(void)
75 {
76         return inb(IOBASE + 0x05) & 0x01;
77 }
78
79 int serial_getchar(void)
80 {
81         while (!serial_havechar()) ;
82         return (int)inb(IOBASE);
83 }
84
85 /*  These are thinly veiled vt100 functions used by curses */
86
87 #define VT100_CLEAR       "\e[H\e[J"
88 /* These defines will fail if you use bold and reverse at the same time.
89  * Switching off one of them will switch off both. tinycurses knows about
90  * this and does the right thing.
91  */
92 #define VT100_SBOLD       "\e[1m"
93 #define VT100_EBOLD       "\e[m"
94 #define VT100_SREVERSE    "\e[7m"
95 #define VT100_EREVERSE    "\e[m"
96 #define VT100_CURSOR_ADDR "\e[%d;%dH"
97 #define VT100_CURSOR_ON   "\e[?25l"
98 #define VT100_CURSOR_OFF  "\e[?25h"
99 /* The following smacs/rmacs are actually for xterm; a real vt100 has
100    enacs=\E(B\E)0, smacs=^N, rmacs=^O.  */
101 #define VT100_SMACS       "\e(0"
102 #define VT100_RMACS       "\e(B"
103 /* A vt100 doesn't do color, setaf/setab below are from xterm-color. */
104 #define VT100_SET_COLOR   "\e[3%d;4%dm"
105
106 static void serial_putcmd(char *str)
107 {
108         while(*str)
109                 serial_putchar(*(str++));
110 }
111
112 void serial_clear(void)
113 {
114         serial_putcmd(VT100_CLEAR);
115 }
116
117 void serial_start_bold(void)
118 {
119         serial_putcmd(VT100_SBOLD);
120 }
121
122 void serial_end_bold(void)
123 {
124         serial_putcmd(VT100_EBOLD);
125 }
126
127 void serial_start_reverse(void)
128 {
129         serial_putcmd(VT100_SREVERSE);
130 }
131
132 void serial_end_reverse(void)
133 {
134         serial_putcmd(VT100_EREVERSE);
135 }
136
137 void serial_start_altcharset(void)
138 {
139         serial_putcmd(VT100_SMACS);
140 }
141
142 void serial_end_altcharset(void)
143 {
144         serial_putcmd(VT100_RMACS);
145 }
146
147 /**
148  * Set the foreground and background colors on the serial console.
149  *
150  * @param fg Foreground color number.
151  * @param bg Background color number.
152  */
153 void serial_set_color(short fg, short bg)
154 {
155         char buffer[32];
156         snprintf(buffer, sizeof(buffer), VT100_SET_COLOR, fg, bg);
157         serial_putcmd(buffer);
158 }
159
160 void serial_set_cursor(int y, int x)
161 {
162         char buffer[32];
163         snprintf(buffer, sizeof(buffer), VT100_CURSOR_ADDR, y + 1, x + 1);
164         serial_putcmd(buffer);
165 }
166
167 void serial_cursor_enable(int state)
168 {
169         if (state)
170                 serial_putcmd(VT100_CURSOR_ON);
171         else
172                 serial_putcmd(VT100_CURSOR_OFF);
173 }