diff options
Diffstat (limited to 'arch/x86/boot/early_serial_console.c')
-rw-r--r-- | arch/x86/boot/early_serial_console.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/arch/x86/boot/early_serial_console.c b/arch/x86/boot/early_serial_console.c new file mode 100644 index 000000000000..030f4b93e255 --- /dev/null +++ b/arch/x86/boot/early_serial_console.c | |||
@@ -0,0 +1,139 @@ | |||
1 | #include "boot.h" | ||
2 | |||
3 | #define DEFAULT_SERIAL_PORT 0x3f8 /* ttyS0 */ | ||
4 | |||
5 | #define XMTRDY 0x20 | ||
6 | |||
7 | #define DLAB 0x80 | ||
8 | |||
9 | #define TXR 0 /* Transmit register (WRITE) */ | ||
10 | #define RXR 0 /* Receive register (READ) */ | ||
11 | #define IER 1 /* Interrupt Enable */ | ||
12 | #define IIR 2 /* Interrupt ID */ | ||
13 | #define FCR 2 /* FIFO control */ | ||
14 | #define LCR 3 /* Line control */ | ||
15 | #define MCR 4 /* Modem control */ | ||
16 | #define LSR 5 /* Line Status */ | ||
17 | #define MSR 6 /* Modem Status */ | ||
18 | #define DLL 0 /* Divisor Latch Low */ | ||
19 | #define DLH 1 /* Divisor latch High */ | ||
20 | |||
21 | #define DEFAULT_BAUD 9600 | ||
22 | |||
23 | static void early_serial_init(int port, int baud) | ||
24 | { | ||
25 | unsigned char c; | ||
26 | unsigned divisor; | ||
27 | |||
28 | outb(0x3, port + LCR); /* 8n1 */ | ||
29 | outb(0, port + IER); /* no interrupt */ | ||
30 | outb(0, port + FCR); /* no fifo */ | ||
31 | outb(0x3, port + MCR); /* DTR + RTS */ | ||
32 | |||
33 | divisor = 115200 / baud; | ||
34 | c = inb(port + LCR); | ||
35 | outb(c | DLAB, port + LCR); | ||
36 | outb(divisor & 0xff, port + DLL); | ||
37 | outb((divisor >> 8) & 0xff, port + DLH); | ||
38 | outb(c & ~DLAB, port + LCR); | ||
39 | |||
40 | early_serial_base = port; | ||
41 | } | ||
42 | |||
43 | static void parse_earlyprintk(void) | ||
44 | { | ||
45 | int baud = DEFAULT_BAUD; | ||
46 | char arg[32]; | ||
47 | int pos = 0; | ||
48 | int port = 0; | ||
49 | |||
50 | if (cmdline_find_option("earlyprintk", arg, sizeof arg) > 0) { | ||
51 | char *e; | ||
52 | |||
53 | if (!strncmp(arg, "serial", 6)) { | ||
54 | port = DEFAULT_SERIAL_PORT; | ||
55 | pos += 6; | ||
56 | } | ||
57 | |||
58 | if (arg[pos] == ',') | ||
59 | pos++; | ||
60 | |||
61 | if (!strncmp(arg, "ttyS", 4)) { | ||
62 | static const int bases[] = { 0x3f8, 0x2f8 }; | ||
63 | int idx = 0; | ||
64 | |||
65 | if (!strncmp(arg + pos, "ttyS", 4)) | ||
66 | pos += 4; | ||
67 | |||
68 | if (arg[pos++] == '1') | ||
69 | idx = 1; | ||
70 | |||
71 | port = bases[idx]; | ||
72 | } | ||
73 | |||
74 | if (arg[pos] == ',') | ||
75 | pos++; | ||
76 | |||
77 | baud = simple_strtoull(arg + pos, &e, 0); | ||
78 | if (baud == 0 || arg + pos == e) | ||
79 | baud = DEFAULT_BAUD; | ||
80 | } | ||
81 | |||
82 | if (port) | ||
83 | early_serial_init(port, baud); | ||
84 | } | ||
85 | |||
86 | #define BASE_BAUD (1843200/16) | ||
87 | static unsigned int probe_baud(int port) | ||
88 | { | ||
89 | unsigned char lcr, dll, dlh; | ||
90 | unsigned int quot; | ||
91 | |||
92 | lcr = inb(port + LCR); | ||
93 | outb(lcr | DLAB, port + LCR); | ||
94 | dll = inb(port + DLL); | ||
95 | dlh = inb(port + DLH); | ||
96 | outb(lcr, port + LCR); | ||
97 | quot = (dlh << 8) | dll; | ||
98 | |||
99 | return BASE_BAUD / quot; | ||
100 | } | ||
101 | |||
102 | static void parse_console_uart8250(void) | ||
103 | { | ||
104 | char optstr[64], *options; | ||
105 | int baud = DEFAULT_BAUD; | ||
106 | int port = 0; | ||
107 | |||
108 | /* | ||
109 | * console=uart8250,io,0x3f8,115200n8 | ||
110 | * need to make sure it is last one console ! | ||
111 | */ | ||
112 | if (cmdline_find_option("console", optstr, sizeof optstr) <= 0) | ||
113 | return; | ||
114 | |||
115 | options = optstr; | ||
116 | |||
117 | if (!strncmp(options, "uart8250,io,", 12)) | ||
118 | port = simple_strtoull(options + 12, &options, 0); | ||
119 | else if (!strncmp(options, "uart,io,", 8)) | ||
120 | port = simple_strtoull(options + 8, &options, 0); | ||
121 | else | ||
122 | return; | ||
123 | |||
124 | if (options && (options[0] == ',')) | ||
125 | baud = simple_strtoull(options + 1, &options, 0); | ||
126 | else | ||
127 | baud = probe_baud(port); | ||
128 | |||
129 | if (port) | ||
130 | early_serial_init(port, baud); | ||
131 | } | ||
132 | |||
133 | void console_init(void) | ||
134 | { | ||
135 | parse_earlyprintk(); | ||
136 | |||
137 | if (!early_serial_base) | ||
138 | parse_console_uart8250(); | ||
139 | } | ||