udbg_16550.c 5.1 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 < 0 || 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 */