summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/udbg_16550.c
blob: 9313574ab935c422a0b823436284d66f5f2eedc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * 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/config.h>
#include <linux/types.h>
#include <asm/udbg.h>
#include <asm/io.h>

extern u8 real_readb(volatile u8 __iomem  *addr);
extern void real_writeb(u8 data, volatile u8 __iomem *addr);

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 */

static volatile struct NS16550 __iomem *udbg_comport;

static void udbg_550_putc(unsigned char c)
{
	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;
}

static unsigned char udbg_550_getc(void)
{
	if (udbg_comport) {
		while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
			/* wait for char */;
		return in_8(&udbg_comport->rbr);
	}
	return 0;
}

void udbg_init_uart(void __iomem *comport, unsigned int speed)
{
	u16 dll = speed ? (115200 / speed) : 12;

	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);
		out_8(&udbg_comport->lcr, 0x80);	/* Access baud rate */
		out_8(&udbg_comport->dll, dll & 0xff);	/* 1 = 115200,  2 = 57600,
							   3 = 38400, 12 = 9600 baud */
		out_8(&udbg_comport->dlm, dll >> 8);	/* dll >> 8 which should be zero
							   for fast rates; */
		out_8(&udbg_comport->lcr, 0x03);	/* 8 data, 1 stop, no parity */
		out_8(&udbg_comport->mcr, 0x03);	/* RTS/DTR */
		out_8(&udbg_comport->fcr ,0x07);	/* Clear & enable FIFOs */
		udbg_putc = udbg_550_putc;
		udbg_getc = udbg_550_getc;
		udbg_getc_poll = udbg_550_getc_poll;
	}
}

#ifdef CONFIG_PPC_MAPLE
void udbg_maple_real_putc(unsigned 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_maple_real_putc('\r');
	}
}

void udbg_init_maple_realmode(void)
{
	udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8;

	udbg_putc = udbg_maple_real_putc;
	udbg_getc = NULL;
	udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_MAPLE */