OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [serial/] [arm/] [at91/] [v2_0/] [src/] [at91_serial.c] - Blame information for rev 365

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      io/serial/arm/at91/at91_serial.c
4
//
5
//      Atmel AT91/EB40 Serial I/O Interface Module (interrupt driven)
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):     gthomas
44
// Contributors:  gthomas
45
// Date:          2001-07-24
46
// Purpose:       Atmel AT91/EB40 Serial I/O module (interrupt driven version)
47
// Description: 
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
#include <pkgconf/system.h>
54
#include <pkgconf/io_serial.h>
55
#include <pkgconf/io.h>
56
#include <pkgconf/kernel.h>
57
 
58
#include <cyg/io/io.h>
59
#include <cyg/hal/hal_io.h>
60
#include <cyg/hal/hal_intr.h>
61
#include <cyg/io/devtab.h>
62
#include <cyg/io/serial.h>
63
#include <cyg/infra/diag.h>
64
 
65
#ifdef CYGPKG_IO_SERIAL_ARM_AT91
66
 
67
#include "at91_serial.h"
68
 
69
typedef struct at91_serial_info {
70
    CYG_ADDRWORD   base;
71
    CYG_WORD       int_num;
72
    cyg_interrupt  serial_interrupt;
73
    cyg_handle_t   serial_interrupt_handle;
74
} at91_serial_info;
75
 
76
static bool at91_serial_init(struct cyg_devtab_entry *tab);
77
static bool at91_serial_putc(serial_channel *chan, unsigned char c);
78
static Cyg_ErrNo at91_serial_lookup(struct cyg_devtab_entry **tab,
79
                                    struct cyg_devtab_entry *sub_tab,
80
                                    const char *name);
81
static unsigned char at91_serial_getc(serial_channel *chan);
82
static Cyg_ErrNo at91_serial_set_config(serial_channel *chan, cyg_uint32 key,
83
                                        const void *xbuf, cyg_uint32 *len);
84
static void at91_serial_start_xmit(serial_channel *chan);
85
static void at91_serial_stop_xmit(serial_channel *chan);
86
 
87
static cyg_uint32 at91_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
88
static void       at91_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
89
 
90
static SERIAL_FUNS(at91_serial_funs,
91
                   at91_serial_putc,
92
                   at91_serial_getc,
93
                   at91_serial_set_config,
94
                   at91_serial_start_xmit,
95
                   at91_serial_stop_xmit
96
    );
97
 
98
#ifdef CYGPKG_IO_SERIAL_ARM_AT91_SERIAL0
99
static at91_serial_info at91_serial_info0 = {(CYG_ADDRWORD)AT91_USART0,
100
                                             CYGNUM_HAL_INTERRUPT_USART0};
101
#if CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE > 0
102
static unsigned char at91_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE];
103
static unsigned char at91_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BUFSIZE];
104
 
105
static SERIAL_CHANNEL_USING_INTERRUPTS(at91_serial_channel0,
106
                                       at91_serial_funs,
107
                                       at91_serial_info0,
108
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BAUD),
109
                                       CYG_SERIAL_STOP_DEFAULT,
110
                                       CYG_SERIAL_PARITY_DEFAULT,
111
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
112
                                       CYG_SERIAL_FLAGS_DEFAULT,
113
                                       &at91_serial_out_buf0[0], sizeof(at91_serial_out_buf0),
114
                                       &at91_serial_in_buf0[0], sizeof(at91_serial_in_buf0)
115
    );
116
#else
117
static SERIAL_CHANNEL(at91_serial_channel0,
118
                      at91_serial_funs,
119
                      at91_serial_info0,
120
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL0_BAUD),
121
                      CYG_SERIAL_STOP_DEFAULT,
122
                      CYG_SERIAL_PARITY_DEFAULT,
123
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
124
                      CYG_SERIAL_FLAGS_DEFAULT
125
    );
126
#endif
127
 
128
DEVTAB_ENTRY(at91_serial_io0,
129
             CYGDAT_IO_SERIAL_ARM_AT91_SERIAL0_NAME,
130
             0,                     // Does not depend on a lower level interface
131
             &cyg_io_serial_devio,
132
             at91_serial_init,
133
             at91_serial_lookup,     // Serial driver may need initializing
134
             &at91_serial_channel0
135
    );
136
#endif //  CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1
137
 
138
#ifdef CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1
139
static at91_serial_info at91_serial_info1 = {(CYG_ADDRWORD)AT91_USART1,
140
                                              CYGNUM_HAL_INTERRUPT_USART1};
141
#if CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE > 0
142
static unsigned char at91_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE];
143
static unsigned char at91_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BUFSIZE];
144
 
145
static SERIAL_CHANNEL_USING_INTERRUPTS(at91_serial_channel1,
146
                                       at91_serial_funs,
147
                                       at91_serial_info1,
148
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BAUD),
149
                                       CYG_SERIAL_STOP_DEFAULT,
150
                                       CYG_SERIAL_PARITY_DEFAULT,
151
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
152
                                       CYG_SERIAL_FLAGS_DEFAULT,
153
                                       &at91_serial_out_buf1[0], sizeof(at91_serial_out_buf1),
154
                                       &at91_serial_in_buf1[0], sizeof(at91_serial_in_buf1)
155
    );
156
#else
157
static SERIAL_CHANNEL(at91_serial_channel1,
158
                      at91_serial_funs,
159
                      at91_serial_info1,
160
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AT91_SERIAL1_BAUD),
161
                      CYG_SERIAL_STOP_DEFAULT,
162
                      CYG_SERIAL_PARITY_DEFAULT,
163
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
164
                      CYG_SERIAL_FLAGS_DEFAULT
165
    );
166
#endif
167
 
168
DEVTAB_ENTRY(at91_serial_io1,
169
             CYGDAT_IO_SERIAL_ARM_AT91_SERIAL1_NAME,
170
             0,                     // Does not depend on a lower level interface
171
             &cyg_io_serial_devio,
172
             at91_serial_init,
173
             at91_serial_lookup,     // Serial driver may need initializing
174
             &at91_serial_channel1
175
    );
176
#endif //  CYGPKG_IO_SERIAL_ARM_AT91_SERIAL1
177
 
178
// Internal function to actually configure the hardware to desired baud rate, etc.
179
static bool
180
at91_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
181
{
182
    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
183
    CYG_ADDRWORD base = at91_chan->base;
184
    cyg_uint32 parity = select_parity[new_config->parity];
185
    cyg_uint32 word_length = select_word_length[new_config->word_length-CYGNUM_SERIAL_WORD_LENGTH_5];
186
    cyg_uint32 stop_bits = select_stop_bits[new_config->stop];
187
 
188
    if ((word_length == 0xFF) ||
189
        (parity == 0xFF) ||
190
        (stop_bits == 0xFF)) {
191
        return false;  // Unsupported configuration
192
    }
193
 
194
    // Reset device
195
    HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_RxRESET | AT91_US_CR_TxRESET);
196
 
197
    // Configuration
198
    HAL_WRITE_UINT32(base+AT91_US_MR, parity | word_length | stop_bits);
199
 
200
    // Baud rate
201
    HAL_WRITE_UINT32(base+AT91_US_BRG, AT91_US_BAUD(select_baud[new_config->baud]));
202
 
203
    // Disable all interrupts
204
    HAL_WRITE_UINT32(base+AT91_US_IDR, 0xFFFFFFFF);
205
 
206
    // Enable Rx interrupts
207
    HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_RxRDY);
208
 
209
    // Enable RX and TX
210
    HAL_WRITE_UINT32(base+AT91_US_CR, AT91_US_CR_RxENAB | AT91_US_CR_TxENAB);
211
 
212
    return true;
213
}
214
 
215
// Function to initialize the device.  Called at bootstrap time.
216
static bool
217
at91_serial_init(struct cyg_devtab_entry *tab)
218
{
219
    serial_channel *chan = (serial_channel *)tab->priv;
220
    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
221
    int res;
222
 
223
#ifdef CYGDBG_IO_INIT
224
    diag_printf("AT91 SERIAL init - dev: %x.%d\n", at91_chan->base, at91_chan->int_num);
225
#endif
226
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
227
    if (chan->out_cbuf.len != 0) {
228
        cyg_drv_interrupt_create(at91_chan->int_num,
229
                                 4,                      // Priority
230
                                 (cyg_addrword_t)chan,   // Data item passed to interrupt handler
231
                                 at91_serial_ISR,
232
                                 at91_serial_DSR,
233
                                 &at91_chan->serial_interrupt_handle,
234
                                 &at91_chan->serial_interrupt);
235
        cyg_drv_interrupt_attach(at91_chan->serial_interrupt_handle);
236
        cyg_drv_interrupt_unmask(at91_chan->int_num);
237
    }
238
    res = at91_serial_config_port(chan, &chan->config, true);
239
    return res;
240
}
241
 
242
// This routine is called when the device is "looked" up (i.e. attached)
243
static Cyg_ErrNo
244
at91_serial_lookup(struct cyg_devtab_entry **tab,
245
                  struct cyg_devtab_entry *sub_tab,
246
                  const char *name)
247
{
248
    serial_channel *chan = (serial_channel *)(*tab)->priv;
249
 
250
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
251
    return ENOERR;
252
}
253
 
254
// Send a character to the device output buffer.
255
// Return 'true' if character is sent to device
256
static bool
257
at91_serial_putc(serial_channel *chan, unsigned char c)
258
{
259
    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
260
    CYG_ADDRWORD base = at91_chan->base;
261
    cyg_uint32 stat;
262
 
263
    // Check status
264
    HAL_READ_UINT32(base+AT91_US_CSR, stat);
265
 
266
    // Send character if possible
267
    if ((stat & AT91_US_CSR_TxRDY) != 0) {
268
        HAL_WRITE_UINT32(base+AT91_US_THR, c);
269
        return true;
270
    } else {
271
        return false;  // Couldn't send, tx was busy
272
    }
273
}
274
 
275
// Fetch a character from the device input buffer, waiting if necessary
276
static unsigned char
277
at91_serial_getc(serial_channel *chan)
278
{
279
    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
280
    CYG_ADDRWORD base = at91_chan->base;
281
    cyg_uint32 c;
282
 
283
    // Read data
284
    HAL_READ_UINT32(base+AT91_US_RHR, c);
285
    return c;
286
}
287
 
288
// Set up the device characteristics; baud rate, etc.
289
static Cyg_ErrNo
290
at91_serial_set_config(serial_channel *chan, cyg_uint32 key,
291
                         const void *xbuf, cyg_uint32 *len)
292
{
293
    switch (key) {
294
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
295
      {
296
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
297
        if ( *len < sizeof(cyg_serial_info_t) ) {
298
            return -EINVAL;
299
        }
300
        *len = sizeof(cyg_serial_info_t);
301
        if ( true != at91_serial_config_port(chan, config, false) )
302
            return -EINVAL;
303
      }
304
      break;
305
    default:
306
        return -EINVAL;
307
    }
308
    return ENOERR;
309
}
310
 
311
// Enable the transmitter on the device
312
static void
313
at91_serial_start_xmit(serial_channel *chan)
314
{
315
    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
316
    CYG_ADDRWORD base = at91_chan->base;
317
 
318
    (chan->callbacks->xmt_char)(chan);  // Kick transmitter (if necessary)
319
    HAL_WRITE_UINT32(base+AT91_US_IER, AT91_US_IER_TxRDY);
320
}
321
 
322
// Disable the transmitter on the device
323
static void
324
at91_serial_stop_xmit(serial_channel *chan)
325
{
326
    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
327
    CYG_ADDRWORD base = at91_chan->base;
328
 
329
    HAL_WRITE_UINT32(base+AT91_US_IDR, AT91_US_IER_TxRDY);
330
}
331
 
332
// Serial I/O - low level interrupt handler (ISR)
333
static cyg_uint32
334
at91_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
335
{
336
    cyg_drv_interrupt_mask(vector);
337
    cyg_drv_interrupt_acknowledge(vector);
338
    return (CYG_ISR_CALL_DSR|CYG_ISR_HANDLED);  // Cause DSR to be run
339
}
340
 
341
// Serial I/O - high level interrupt handler (DSR)
342
static void
343
at91_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
344
{
345
    serial_channel *chan = (serial_channel *)data;
346
    at91_serial_info *at91_chan = (at91_serial_info *)chan->dev_priv;
347
    CYG_ADDRWORD base = at91_chan->base;
348
    cyg_uint32 stat, c;
349
 
350
    // Check status
351
    HAL_READ_UINT32(base+AT91_US_IMR, stat);
352
 
353
    if (stat & (AT91_US_IER_TxRDY)) {
354
        (chan->callbacks->xmt_char)(chan);
355
    }
356
    if (stat & (AT91_US_IER_RxRDY)) {
357
        while (true) {
358
            HAL_READ_UINT32(base+AT91_US_CSR, stat);
359
            if ((stat & AT91_US_CSR_RxRDY) == 0) {
360
                break;
361
            }
362
            HAL_READ_UINT32(base+AT91_US_RHR, c);
363
            (chan->callbacks->rcv_char)(chan, c);
364
        }
365
    }
366
    cyg_drv_interrupt_unmask(vector);
367
}
368
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.