aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/udbg_16550.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-23 01:56:06 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 22:49:50 -0500
commit463ce0e103f419f51b1769111e73fe8bb305d0ec (patch)
treeb4ffced87b886d81b518790fcaf841dd006e8068 /arch/powerpc/kernel/udbg_16550.c
parentd1405b869850982f05c7ec0d3f137ca27588192f (diff)
[PATCH] powerpc: serial port discovery (#2)
This moves the discovery of legacy serial ports to a separate file, makes it common to ppc32 and ppc64, and reworks it to use the new OF address translators to get to the ports early. This new version can also detect some PCI serial cards using legacy chips and will probably match those discovered port with the default console choice. Only ppc64 gets udbg still yet, unifying udbg isn't finished yet. It also adds some speed-probing code to udbg so that the default console can come up at the same speed it was set to by the firmware. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/udbg_16550.c')
-rw-r--r--arch/powerpc/kernel/udbg_16550.c63
1 files changed, 53 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index 9313574ab935..50fd376446c9 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -43,6 +43,8 @@ struct NS16550 {
43#define LSR_TEMT 0x40 /* Xmitter empty */ 43#define LSR_TEMT 0x40 /* Xmitter empty */
44#define LSR_ERR 0x80 /* Error */ 44#define LSR_ERR 0x80 /* Error */
45 45
46#define LCR_DLAB 0x80
47
46static volatile struct NS16550 __iomem *udbg_comport; 48static volatile struct NS16550 __iomem *udbg_comport;
47 49
48static void udbg_550_putc(unsigned char c) 50static void udbg_550_putc(unsigned char c)
@@ -77,29 +79,70 @@ static unsigned char udbg_550_getc(void)
77 return 0; 79 return 0;
78} 80}
79 81
80void udbg_init_uart(void __iomem *comport, unsigned int speed) 82void udbg_init_uart(void __iomem *comport, unsigned int speed,
83 unsigned int clock)
81{ 84{
82 u16 dll = speed ? (115200 / speed) : 12; 85 unsigned int dll, base_bauds = clock / 16;
86
87 if (speed == 0)
88 speed = 9600;
89 dll = base_bauds / speed;
83 90
84 if (comport) { 91 if (comport) {
85 udbg_comport = (struct NS16550 __iomem *)comport; 92 udbg_comport = (struct NS16550 __iomem *)comport;
86 out_8(&udbg_comport->lcr, 0x00); 93 out_8(&udbg_comport->lcr, 0x00);
87 out_8(&udbg_comport->ier, 0xff); 94 out_8(&udbg_comport->ier, 0xff);
88 out_8(&udbg_comport->ier, 0x00); 95 out_8(&udbg_comport->ier, 0x00);
89 out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ 96 out_8(&udbg_comport->lcr, LCR_DLAB);
90 out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, 97 out_8(&udbg_comport->dll, dll & 0xff);
91 3 = 38400, 12 = 9600 baud */ 98 out_8(&udbg_comport->dlm, dll >> 8);
92 out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero 99 /* 8 data, 1 stop, no parity */
93 for fast rates; */ 100 out_8(&udbg_comport->lcr, 0x03);
94 out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ 101 /* RTS/DTR */
95 out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ 102 out_8(&udbg_comport->mcr, 0x03);
96 out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ 103 /* Clear & enable FIFOs */
104 out_8(&udbg_comport->fcr ,0x07);
97 udbg_putc = udbg_550_putc; 105 udbg_putc = udbg_550_putc;
98 udbg_getc = udbg_550_getc; 106 udbg_getc = udbg_550_getc;
99 udbg_getc_poll = udbg_550_getc_poll; 107 udbg_getc_poll = udbg_550_getc_poll;
100 } 108 }
101} 109}
102 110
111unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
112{
113 unsigned int dll, dlm, divisor, prescaler, speed;
114 u8 old_lcr;
115 volatile struct NS16550 __iomem *port = comport;
116
117 old_lcr = in_8(&port->lcr);
118
119 /* select divisor latch registers. */
120 out_8(&port->lcr, LCR_DLAB);
121
122 /* now, read the divisor */
123 dll = in_8(&port->dll);
124 dlm = in_8(&port->dlm);
125 divisor = dlm << 8 | dll;
126
127 /* check prescaling */
128 if (in_8(&port->mcr) & 0x80)
129 prescaler = 4;
130 else
131 prescaler = 1;
132
133 /* restore the LCR */
134 out_8(&port->lcr, old_lcr);
135
136 /* calculate speed */
137 speed = (clock / prescaler) / (divisor * 16);
138
139 /* sanity check */
140 if (speed < 9600 || speed > 115200)
141 speed = 9600;
142
143 return speed;
144}
145
103#ifdef CONFIG_PPC_MAPLE 146#ifdef CONFIG_PPC_MAPLE
104void udbg_maple_real_putc(unsigned char c) 147void udbg_maple_real_putc(unsigned char c)
105{ 148{