Project

General

Profile

Statistics
| Branch: | Revision:

root / prex-0.9.0 / bsp / drv / dev / serial / ns16550.c @ 03e9c04a

History | View | Annotate | Download (6.32 KB)

1 03e9c04a Brad Neuman
/*-
2
 * Copyright (c) 2009, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
/*
31
 * ns16550.c - NS16550 serial driver
32
 */
33
34
#include <driver.h>
35
#include <tty.h>
36
#include <serial.h>
37
38
/* #define DEBUG_NS16550 1 */
39
40
#ifdef DEBUG_NS16550
41
#define DPRINTF(a) printf a
42
#else
43
#define DPRINTF(a)
44
#endif
45
46
#define COM_BASE        CONFIG_NS16550_BASE
47
#define COM_IRQ                CONFIG_NS16550_IRQ
48
49
/* Register offsets */
50
#define COM_RBR                (COM_BASE + 0x00)        /* receive buffer register */
51
#define COM_THR                (COM_BASE + 0x00)        /* transmit holding register */
52
#define COM_IER                (COM_BASE + 0x01)        /* interrupt enable register */
53
#define COM_FCR                (COM_BASE + 0x02)        /* FIFO control register */
54
#define COM_IIR                (COM_BASE + 0x02)        /* interrupt identification register */
55
#define COM_LCR                (COM_BASE + 0x03)        /* line control register */
56
#define COM_MCR                (COM_BASE + 0x04)        /* modem control register */
57
#define COM_LSR                (COM_BASE + 0x05)        /* line status register */
58
#define COM_MSR                (COM_BASE + 0x06)        /* modem status register */
59
#define COM_DLL                (COM_BASE + 0x00)        /* divisor latch LSB (LCR[7] = 1) */
60
#define COM_DLM                (COM_BASE + 0x01)        /* divisor latch MSB (LCR[7] = 1) */
61
62
/* Interrupt enable register */
63
#define        IER_RDA                0x01        /* enable receive data available */
64
#define        IER_THRE        0x02        /* enable transmitter holding register empty */
65
#define        IER_RLS                0x04        /* enable recieve line status */
66
#define        IER_RMS                0x08        /* enable receive modem status */
67
68
/* Interrupt identification register */
69
#define        IIR_MSR                0x00        /* modem status change */
70
#define        IIR_IP                0x01        /* 0 when interrupt pending */
71
#define        IIR_TXB                0x02        /* transmitter holding register empty */
72
#define        IIR_RXB                0x04        /* received data available */
73
#define        IIR_LSR                0x06        /* line status change */
74
#define        IIR_MASK        0x07        /* mask off just the meaningful bits */
75
76
/* line status register */
77
#define        LSR_RCV_FIFO        0x80
78
#define        LSR_TSRE        0x40        /* Transmitter empty: byte sent */
79
#define        LSR_TXRDY        0x20        /* Transmitter buffer empty */
80
#define        LSR_BI                0x10        /* Break detected */
81
#define        LSR_FE                0x08        /* Framing error: bad stop bit */
82
#define        LSR_PE                0x04        /* Parity error */
83
#define        LSR_OE                0x02        /* Overrun, lost incoming byte */
84
#define        LSR_RXRDY        0x01        /* Byte ready in Receive Buffer */
85
#define        LSR_RCV_MASK        0x1f        /* Mask for incoming data or error */
86
87
/* Forward functions */
88
static int        ns16550_probe(struct driver *);
89
static int        ns16550_init(struct driver *);
90
91
static void        ns16550_xmt_char(struct serial_port *, char);
92
static char        ns16550_rcv_char(struct serial_port *);
93
static void        ns16550_set_poll(struct serial_port *, int);
94
static void        ns16550_start(struct serial_port *);
95
static void        ns16550_stop(struct serial_port *);
96
97
98
struct driver ns16550_driver = {
99
        /* name */        "ns16550",
100
        /* devops */        NULL,
101
        /* devsz */        0,
102
        /* flags */        0,
103
        /* probe */        ns16550_probe,
104
        /* init */        ns16550_init,
105
        /* unload */        NULL,
106
};
107
108
static struct serial_ops ns16550_ops = {
109
        /* xmt_char */        ns16550_xmt_char,
110
        /* rcv_char */        ns16550_rcv_char,
111
        /* set_poll */        ns16550_set_poll,
112
        /* start */        ns16550_start,
113
        /* stop */        ns16550_stop,
114
};
115
116
117
static struct serial_port ns16550_port;
118
119
120
static void
121
ns16550_xmt_char(struct serial_port *sp, char c)
122
{
123
124
        while (!(bus_read_8(COM_LSR) & LSR_TXRDY))
125
                ;
126
        bus_write_8(COM_THR, c);
127
}
128
129
static char
130
ns16550_rcv_char(struct serial_port *sp)
131
{
132
133
        while (!(bus_read_8(COM_LSR) & LSR_RXRDY))
134
                ;
135
        return bus_read_8(COM_RBR);
136
}
137
138
static void
139
ns16550_set_poll(struct serial_port *sp, int on)
140
{
141
142
        if (on) {
143
                /* Disable interrupt for polling mode. */
144
                bus_write_8(COM_IER, 0x00);
145
        } else {
146
                /* enable interrupt again */
147
                bus_write_8(COM_IER, IER_RDA|IER_THRE|IER_RLS);
148
        }
149
}
150
151
static int
152
ns16550_isr(void *arg)
153
{
154
        struct serial_port *sp = arg;
155
156
        switch (bus_read_8(COM_IIR) & IIR_MASK) {
157
        case IIR_MSR:                /* Modem status change */
158
                break;
159
        case IIR_LSR:                /* Line status change */
160
                bus_read_8(COM_LSR);
161
                break;
162
        case IIR_TXB:                /* Transmitter holding register empty */
163
                serial_xmt_done(sp);
164
                break;
165
        case IIR_RXB:                /* Received data available */
166
                bus_read_8(COM_LSR);
167
                serial_rcv_char(sp, bus_read_8(COM_RBR));
168
                break;
169
        }
170
        return 0;
171
}
172
173
static void
174
ns16550_start(struct serial_port *sp)
175
{
176
        int s;
177
178
        bus_write_8(COM_IER, 0x00);        /* Disable interrupt */
179
        bus_write_8(COM_LCR, 0x80);        /* Access baud rate */
180
        bus_write_8(COM_DLL, 0x01);        /* 115200 baud */
181
        bus_write_8(COM_DLM, 0x00);
182
        bus_write_8(COM_LCR, 0x03);        /* N, 8, 1 */
183
        bus_write_8(COM_FCR, 0x06);        /* Disable & clear FIFO */
184
185
        sp->irq = irq_attach(COM_IRQ, IPL_COMM, 0, ns16550_isr,
186
                             IST_NONE, sp);
187
188
        s = splhigh();
189
        bus_write_8(COM_MCR, 0x0b);  /* Enable OUT2 interrupt */
190
        bus_write_8(COM_IER, IER_RDA|IER_THRE|IER_RLS);  /* Enable interrupt */
191
        bus_read_8(COM_IIR);
192
        splx(s);
193
}
194
195
static void
196
ns16550_stop(struct serial_port *sp)
197
{
198
199
        /* Disable all interrupts */
200
        bus_write_8(COM_IER, 0x00);
201
}
202
203
204
static int
205
ns16550_probe(struct driver *self)
206
{
207
208
        if (bus_read_8(COM_LSR) == 0xff)
209
                return ENXIO;        /* Port is disabled */
210
        return 0;
211
}
212
213
static int
214
ns16550_init(struct driver *self)
215
{
216
217
        serial_attach(&ns16550_ops, &ns16550_port);
218
        return 0;
219
}