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