udbg_16550.c 5.8 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_putc(char c)
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
{
	if (udbg_comport) {
		while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
		out_8(&udbg_comport->thr, c);
		if (c == '\n')
			udbg_550_putc('\r');
	}
}

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;
}

73
static int udbg_550_getc(void)
74 75 76 77 78 79
{
	if (udbg_comport) {
		while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
			/* wait for char */;
		return in_8(&udbg_comport->rbr);
	}
80
	return -1;
81 82
}

83 84
void udbg_init_uart(void __iomem *comport, unsigned int speed,
		    unsigned int clock)
85
{
86
	unsigned int dll, base_bauds;
87

88 89
	if (clock == 0)
		clock = 1843200;
90 91
	if (speed == 0)
		speed = 9600;
92 93

	base_bauds = clock / 16;
94
	dll = base_bauds / speed;
95 96 97 98 99 100

	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);
101 102 103 104 105 106 107 108 109
		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);
110 111 112
		udbg_putc = udbg_550_putc;
		udbg_getc = udbg_550_getc;
		udbg_getc_poll = udbg_550_getc_poll;
113 114 115
	}
}

116 117 118 119
unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock)
{
	unsigned int dll, dlm, divisor, prescaler, speed;
	u8 old_lcr;
120
	struct NS16550 __iomem *port = comport;
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

	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 */
145
	if (speed > (clock / 16))
146 147 148 149 150
		speed = 9600;

	return speed;
}

151
#ifdef CONFIG_PPC_MAPLE
152
void udbg_maple_real_putc(char c)
153 154 155 156 157 158 159 160 161 162
{
	if (udbg_comport) {
		while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
		real_writeb(c, &udbg_comport->thr); eieio();
		if (c == '\n')
			udbg_maple_real_putc('\r');
	}
}

163
void __init udbg_init_maple_realmode(void)
164
{
165
	udbg_comport = (struct NS16550 __iomem *)0xf40003f8;
166

167 168 169
	udbg_putc = udbg_maple_real_putc;
	udbg_getc = NULL;
	udbg_getc_poll = NULL;
170 171
}
#endif /* CONFIG_PPC_MAPLE */
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

#ifdef CONFIG_PPC_PASEMI
void udbg_pas_real_putc(char c)
{
	if (udbg_comport) {
		while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
		real_205_writeb(c, &udbg_comport->thr); eieio();
		if (c == '\n')
			udbg_pas_real_putc('\r');
	}
}

void udbg_init_pas_realmode(void)
{
187
	udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL;
188 189 190 191 192 193

	udbg_putc = udbg_pas_real_putc;
	udbg_getc = NULL;
	udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_MAPLE */
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208

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

static void udbg_44x_as1_putc(char c)
{
	if (udbg_comport) {
		while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
		as1_writeb(c, &udbg_comport->thr); eieio();
		if (c == '\n')
			udbg_44x_as1_putc('\r');
	}
}

209 210 211 212 213 214 215 216 217 218
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;
}

219 220 221
void __init udbg_init_44x_as1(void)
{
	udbg_comport =
222
		(struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
223 224

	udbg_putc = udbg_44x_as1_putc;
225
	udbg_getc = udbg_44x_as1_getc;
226 227
}
#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260

#ifdef CONFIG_PPC_EARLY_DEBUG_40x
static void udbg_40x_real_putc(char c)
{
	if (udbg_comport) {
		while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
			/* wait for idle */;
		real_writeb(c, &udbg_comport->thr); eieio();
		if (c == '\n')
			udbg_40x_real_putc('\r');
	}
}

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;
	udbg_getc = udbg_40x_real_getc;
	udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_EARLY_DEBUG_40x */