udbg_16550.c 6.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * udbg for for NS16550 compatable serial ports
 *
 * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */
#include <linux/types.h>
12
#include <asm/udbg.h>
13 14 15 16
#include <asm/io.h>

extern u8 real_readb(volatile u8 __iomem  *addr);
extern void real_writeb(u8 data, volatile u8 __iomem *addr);
17 18
extern u8 real_205_readb(volatile u8 __iomem  *addr);
extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

struct NS16550 {
	/* this struct must be packed */
	unsigned char rbr;  /* 0 */
	unsigned char ier;  /* 1 */
	unsigned char fcr;  /* 2 */
	unsigned char lcr;  /* 3 */
	unsigned char mcr;  /* 4 */
	unsigned char lsr;  /* 5 */
	unsigned char msr;  /* 6 */
	unsigned char scr;  /* 7 */
};

#define thr rbr
#define iir fcr
#define dll rbr
#define dlm ier
#define dlab lcr

#define LSR_DR   0x01  /* Data ready */
#define LSR_OE   0x02  /* Overrun */
#define LSR_PE   0x04  /* Parity error */
#define LSR_FE   0x08  /* Framing error */
#define LSR_BI   0x10  /* Break */
#define LSR_THRE 0x20  /* Xmit holding register empty */
#define LSR_TEMT 0x40  /* Xmitter empty */
#define LSR_ERR  0x80  /* Error */

47 48
#define LCR_DLAB 0x80

49
static struct NS16550 __iomem *udbg_comport;
50

51
static void udbg_550_flush(void)
52 53 54 55
{
	if (udbg_comport) {
		while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
56 57 58 59 60 61
	}
}

static void udbg_550_putc(char c)
{
	if (udbg_comport) {
62 63
		if (c == '\n')
			udbg_550_putc('\r');
64 65
		udbg_550_flush();
		out_8(&udbg_comport->thr, c);
66 67 68 69 70 71 72 73 74 75 76 77 78 79
	}
}

static int udbg_550_getc_poll(void)
{
	if (udbg_comport) {
		if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
			return in_8(&udbg_comport->rbr);
		else
			return -1;
	}
	return -1;
}

80
static int udbg_550_getc(void)
81 82 83 84 85 86
{
	if (udbg_comport) {
		while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
			/* wait for char */;
		return in_8(&udbg_comport->rbr);
	}
87
	return -1;
88 89
}

90 91
void udbg_init_uart(void __iomem *comport, unsigned int speed,
		    unsigned int clock)
92
{
93
	unsigned int dll, base_bauds;
94

95 96
	if (clock == 0)
		clock = 1843200;
97 98
	if (speed == 0)
		speed = 9600;
99 100

	base_bauds = clock / 16;
101
	dll = base_bauds / speed;
102 103 104 105 106 107

	if (comport) {
		udbg_comport = (struct NS16550 __iomem *)comport;
		out_8(&udbg_comport->lcr, 0x00);
		out_8(&udbg_comport->ier, 0xff);
		out_8(&udbg_comport->ier, 0x00);
108 109 110 111 112 113 114 115 116
		out_8(&udbg_comport->lcr, LCR_DLAB);
		out_8(&udbg_comport->dll, dll & 0xff);
		out_8(&udbg_comport->dlm, dll >> 8);
		/* 8 data, 1 stop, no parity */
		out_8(&udbg_comport->lcr, 0x03);
		/* RTS/DTR */
		out_8(&udbg_comport->mcr, 0x03);
		/* Clear & enable FIFOs */
		out_8(&udbg_comport->fcr ,0x07);
117
		udbg_putc = udbg_550_putc;
118
		udbg_flush = udbg_550_flush;
119 120
		udbg_getc = udbg_550_getc;
		udbg_getc_poll = udbg_550_getc_poll;
121 122 123
	}
}

124 125 126 127
unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
{
	unsigned int dll, dlm, divisor, prescaler, speed;
	u8 old_lcr;
128
	struct NS16550 __iomem *port = comport;
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

	old_lcr = in_8(&port->lcr);

	/* select divisor latch registers.  */
	out_8(&port->lcr, LCR_DLAB);

	/* now, read the divisor */
	dll = in_8(&port->dll);
	dlm = in_8(&port->dlm);
	divisor = dlm << 8 | dll;

	/* check prescaling */
	if (in_8(&port->mcr) & 0x80)
		prescaler = 4;
	else
		prescaler = 1;

	/* restore the LCR */
	out_8(&port->lcr, old_lcr);

	/* calculate speed */
	speed = (clock / prescaler) / (divisor * 16);

	/* sanity check */
153
	if (speed > (clock / 16))
154 155 156 157 158
		speed = 9600;

	return speed;
}

159
#ifdef CONFIG_PPC_MAPLE
160
void udbg_maple_real_flush(void)
161 162 163 164
{
	if (udbg_comport) {
		while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
165 166 167 168 169 170
	}
}

void udbg_maple_real_putc(char c)
{
	if (udbg_comport) {
171 172
		if (c == '\n')
			udbg_maple_real_putc('\r');
173 174
		udbg_maple_real_flush();
		real_writeb(c, &udbg_comport->thr); eieio();
175 176 177
	}
}

178
void __init udbg_init_maple_realmode(void)
179
{
180
	udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
181

182
	udbg_putc = udbg_maple_real_putc;
183
	udbg_flush = udbg_maple_real_flush;
184 185
	udbg_getc = NULL;
	udbg_getc_poll = NULL;
186 187
}
#endif /* CONFIG_PPC_MAPLE */
188 189

#ifdef CONFIG_PPC_PASEMI
190
void udbg_pas_real_flush(void)
191 192 193 194
{
	if (udbg_comport) {
		while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
195 196 197 198 199 200
	}
}

void udbg_pas_real_putc(char c)
{
	if (udbg_comport) {
201 202
		if (c == '\n')
			udbg_pas_real_putc('\r');
203 204
		udbg_pas_real_flush();
		real_205_writeb(c, &udbg_comport->thr); eieio();
205 206 207 208 209
	}
}

void udbg_init_pas_realmode(void)
{
210
	udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
211 212

	udbg_putc = udbg_pas_real_putc;
213
	udbg_flush = udbg_pas_real_flush;
214 215 216 217
	udbg_getc = NULL;
	udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_MAPLE */
218 219 220 221

#ifdef CONFIG_PPC_EARLY_DEBUG_44x
#include <platforms/44x/44x.h>

222
static void udbg_44x_as1_flush(void)
223 224 225 226
{
	if (udbg_comport) {
		while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
227 228 229 230 231 232
	}
}

static void udbg_44x_as1_putc(char c)
{
	if (udbg_comport) {
233 234
		if (c == '\n')
			udbg_44x_as1_putc('\r');
235 236
		udbg_44x_as1_flush();
		as1_writeb(c, &udbg_comport->thr); eieio();
237 238 239
	}
}

240 241 242 243 244 245 246 247 248 249
static int udbg_44x_as1_getc(void)
{
	if (udbg_comport) {
		while ((as1_readb(&udbg_comport->lsr) & LSR_DR) == 0)
			; /* wait for char */
		return as1_readb(&udbg_comport->rbr);
	}
	return -1;
}

250 251 252
void __init udbg_init_44x_as1(void)
{
	udbg_comport =
253
		(struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
254 255

	udbg_putc = udbg_44x_as1_putc;
256
	udbg_flush = udbg_44x_as1_flush;
257
	udbg_getc = udbg_44x_as1_getc;
258 259
}
#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
260 261

#ifdef CONFIG_PPC_EARLY_DEBUG_40x
262
static void udbg_40x_real_flush(void)
263 264 265 266
{
	if (udbg_comport) {
		while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
267 268 269 270 271 272
	}
}

static void udbg_40x_real_putc(char c)
{
	if (udbg_comport) {
273 274
		if (c == '\n')
			udbg_40x_real_putc('\r');
275 276
		udbg_40x_real_flush();
		real_writeb(c, &udbg_comport->thr); eieio();
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
	}
}

static int udbg_40x_real_getc(void)
{
	if (udbg_comport) {
		while ((real_readb(&udbg_comport->lsr) & LSR_DR) == 0)
			; /* wait for char */
		return real_readb(&udbg_comport->rbr);
	}
	return -1;
}

void __init udbg_init_40x_realmode(void)
{
	udbg_comport = (struct NS16550 __iomem *)
		CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR;

	udbg_putc = udbg_40x_real_putc;
296
	udbg_flush = udbg_40x_real_flush;
297 298 299 300
	udbg_getc = udbg_40x_real_getc;
	udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_EARLY_DEBUG_40x */