Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (5.98 KB)

1
/*-
2
 * Copyright (c) 2008-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
 * pl011.c - ARM PrimeCell PL011 UART
32
 */
33

    
34
#include <driver.h>
35
#include <tty.h>
36
#include <serial.h>
37

    
38
/* #define DEBUG_PL011 1 */
39

    
40
#ifdef DEBUG_PL011
41
#define DPRINTF(a) printf a
42
#else
43
#define DPRINTF(a)
44
#endif
45

    
46
#define UART_BASE        CONFIG_PL011_BASE
47
#define UART_IRQ        CONFIG_PL011_IRQ
48
#define UART_CLK        14745600
49
#define BAUD_RATE        115200
50

    
51
/* UART Registers */
52
#define UART_DR                (UART_BASE + 0x00)
53
#define UART_RSR        (UART_BASE + 0x04)
54
#define UART_ECR        (UART_BASE + 0x04)
55
#define UART_FR                (UART_BASE + 0x18)
56
#define UART_IBRD        (UART_BASE + 0x24)
57
#define UART_FBRD        (UART_BASE + 0x28)
58
#define UART_LCRH        (UART_BASE + 0x2c)
59
#define UART_CR                (UART_BASE + 0x30)
60
#define UART_IMSC        (UART_BASE + 0x38)
61
#define UART_MIS        (UART_BASE + 0x40)
62
#define UART_ICR        (UART_BASE + 0x44)
63

    
64
/* Flag register */
65
#define FR_RXFE                0x10        /* Receive FIFO empty */
66
#define FR_TXFF                0x20        /* Transmit FIFO full */
67

    
68
/* Masked interrupt status register */
69
#define MIS_RX                0x10        /* Receive interrupt */
70
#define MIS_TX                0x20        /* Transmit interrupt */
71

    
72
/* Interrupt clear register */
73
#define ICR_RX                0x10        /* Clear receive interrupt */
74
#define ICR_TX                0x20        /* Clear transmit interrupt */
75

    
76
/* Line control register (High) */
77
#define LCRH_WLEN8        0x60        /* 8 bits */
78
#define LCRH_FEN        0x10        /* Enable FIFO */
79

    
80
/* Control register */
81
#define CR_UARTEN        0x0001        /* UART enable */
82
#define CR_TXE                0x0100        /* Transmit enable */
83
#define CR_RXE                0x0200        /* Receive enable */
84

    
85
/* Interrupt mask set/clear register */
86
#define IMSC_RX                0x10        /* Receive interrupt mask */
87
#define IMSC_TX                0x20        /* Transmit interrupt mask */
88

    
89
/* Forward functions */
90
static int        pl011_init(struct driver *);
91
static void        pl011_xmt_char(struct serial_port *, char);
92
static char        pl011_rcv_char(struct serial_port *);
93
static void        pl011_set_poll(struct serial_port *, int);
94
static void        pl011_start(struct serial_port *);
95
static void        pl011_stop(struct serial_port *);
96

    
97

    
98
struct driver pl011_driver = {
99
        /* name */        "pl011",
100
        /* devops */        NULL,
101
        /* devsz */        0,
102
        /* flags */        0,
103
        /* probe */        NULL,
104
        /* init */        pl011_init,
105
        /* detach */        NULL,
106
};
107

    
108
static struct serial_ops pl011_ops = {
109
        /* xmt_char */        pl011_xmt_char,
110
        /* rcv_char */        pl011_rcv_char,
111
        /* set_poll */        pl011_set_poll,
112
        /* start */        pl011_start,
113
        /* stop */        pl011_stop,
114
};
115

    
116
static struct serial_port pl011_port;
117

    
118

    
119
static void
120
pl011_xmt_char(struct serial_port *sp, char c)
121
{
122

    
123
        while (bus_read_32(UART_FR) & FR_TXFF)
124
                ;
125
        bus_write_32(UART_DR, (uint32_t)c);
126
}
127

    
128
static char
129
pl011_rcv_char(struct serial_port *sp)
130
{
131
        char c;
132

    
133
        while (bus_read_32(UART_FR) & FR_RXFE)
134
                ;
135
        c = bus_read_32(UART_DR) & 0xff;
136
        return c;
137
}
138

    
139
static void
140
pl011_set_poll(struct serial_port *sp, int on)
141
{
142

    
143
        if (on) {
144
                /*
145
                 * Disable interrupt for polling mode.
146
                 */
147
                bus_write_32(UART_IMSC, 0);
148
        } else
149
                bus_write_32(UART_IMSC, (IMSC_RX | IMSC_TX));
150
}
151

    
152
static int
153
pl011_isr(void *arg)
154
{
155
        struct serial_port *sp = arg;
156
        int c;
157
        uint32_t mis;
158

    
159
        mis = bus_read_32(UART_MIS);
160

    
161
        if (mis & MIS_RX) {
162
                /*
163
                 * Receive interrupt
164
                 */
165
                while (bus_read_32(UART_FR) & FR_RXFE)
166
                        ;
167
                do {
168
                        c = bus_read_32(UART_DR);
169
                        serial_rcv_char(sp, c);
170
                } while ((bus_read_32(UART_FR) & FR_RXFE) == 0);
171

    
172
                /* Clear interrupt status */
173
                bus_write_32(UART_ICR, ICR_RX);
174
        }
175
        if (mis & MIS_TX) {
176
                /*
177
                 * Transmit interrupt
178
                 */
179
                serial_xmt_done(sp);
180

    
181
                /* Clear interrupt status */
182
                bus_write_32(UART_ICR, ICR_TX);
183
        }
184
        return 0;
185
}
186

    
187
static void
188
pl011_start(struct serial_port *sp)
189
{
190
        uint32_t divider, remainder, fraction;
191

    
192
        bus_write_32(UART_CR, 0);        /* Disable everything */
193
        bus_write_32(UART_ICR, 0x07ff);        /* Clear all interrupt status */
194

    
195
        /*
196
         * Set baud rate:
197
         * IBRD = UART_CLK / (16 * BAUD_RATE)
198
         * FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
199
         */
200
        divider = UART_CLK / (16 * BAUD_RATE);
201
        remainder = UART_CLK % (16 * BAUD_RATE);
202
        fraction = (8 * remainder / BAUD_RATE) >> 1;
203
        fraction += (8 * remainder / BAUD_RATE) & 1;
204
        bus_write_32(UART_IBRD, divider);
205
        bus_write_32(UART_FBRD, fraction);
206

    
207
        /* Set N, 8, 1, FIFO enable */
208
        bus_write_32(UART_LCRH, (LCRH_WLEN8 | LCRH_FEN));
209

    
210
        /* Enable UART */
211
        bus_write_32(UART_CR, (CR_RXE | CR_TXE | CR_UARTEN));
212

    
213
        /* Install interrupt handler */
214
        sp->irq = irq_attach(UART_IRQ, IPL_COMM, 0, pl011_isr, IST_NONE, sp);
215

    
216
        /* Enable TX/RX interrupt */
217
        bus_write_32(UART_IMSC, (IMSC_RX | IMSC_TX));
218
}
219

    
220
static void
221
pl011_stop(struct serial_port *sp)
222
{
223

    
224
        bus_write_32(UART_IMSC, 0);        /* Disable all interrupts */
225
        bus_write_32(UART_CR, 0);        /* Disable everything */
226
}
227

    
228
static int
229
pl011_init(struct driver *self)
230
{
231

    
232
        serial_attach(&pl011_ops, &pl011_port);
233
        return 0;
234
}