OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [serial/] [arm/] [sa11x0/] [v2_0/] [src/] [sa11x0_serial.c] - Blame information for rev 27

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      io/serial/arm/sa11x0/sa11x0_serial.c
4
//
5
//      StrongARM SA11x0 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:          2000-05-08
46
// Purpose:       StrongARM SA11x0 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_intr.h>
60
#include <cyg/io/devtab.h>
61
#include <cyg/io/serial.h>
62
#include <cyg/infra/diag.h>
63
 
64
#ifdef CYGPKG_IO_SERIAL_ARM_SA11X0
65
 
66
#include "sa11x0_serial.h"
67
 
68
typedef struct sa11x0_serial_info {
69
    CYG_ADDRWORD   base;
70
    CYG_WORD       int_num;
71
    cyg_interrupt  serial_interrupt;
72
    cyg_handle_t   serial_interrupt_handle;
73
} sa11x0_serial_info;
74
 
75
static bool sa11x0_serial_init(struct cyg_devtab_entry *tab);
76
static bool sa11x0_serial_putc(serial_channel *chan, unsigned char c);
77
static Cyg_ErrNo sa11x0_serial_lookup(struct cyg_devtab_entry **tab,
78
                                   struct cyg_devtab_entry *sub_tab,
79
                                   const char *name);
80
static unsigned char sa11x0_serial_getc(serial_channel *chan);
81
static Cyg_ErrNo sa11x0_serial_set_config(serial_channel *chan, cyg_uint32 key,
82
                                          const void *xbuf, cyg_uint32 *len);
83
static void sa11x0_serial_start_xmit(serial_channel *chan);
84
static void sa11x0_serial_stop_xmit(serial_channel *chan);
85
 
86
static cyg_uint32 sa11x0_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
87
static void       sa11x0_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
88
 
89
static SERIAL_FUNS(sa11x0_serial_funs,
90
                   sa11x0_serial_putc,
91
                   sa11x0_serial_getc,
92
                   sa11x0_serial_set_config,
93
                   sa11x0_serial_start_xmit,
94
                   sa11x0_serial_stop_xmit
95
    );
96
 
97
#ifdef CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL0
98
static sa11x0_serial_info sa11x0_serial_info0 = {(CYG_ADDRWORD)SA11X0_UART3_CONTROL0,
99
                                                 CYGNUM_HAL_INTERRUPT_UART3};
100
#if CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BUFSIZE > 0
101
static unsigned char sa11x0_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BUFSIZE];
102
static unsigned char sa11x0_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BUFSIZE];
103
 
104
static SERIAL_CHANNEL_USING_INTERRUPTS(sa11x0_serial_channel0,
105
                                       sa11x0_serial_funs,
106
                                       sa11x0_serial_info0,
107
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BAUD),
108
                                       CYG_SERIAL_STOP_DEFAULT,
109
                                       CYG_SERIAL_PARITY_DEFAULT,
110
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
111
                                       CYG_SERIAL_FLAGS_DEFAULT,
112
                                       &sa11x0_serial_out_buf0[0], sizeof(sa11x0_serial_out_buf0),
113
                                       &sa11x0_serial_in_buf0[0], sizeof(sa11x0_serial_in_buf0)
114
    );
115
#else
116
static SERIAL_CHANNEL(sa11x0_serial_channel0,
117
                      sa11x0_serial_funs,
118
                      sa11x0_serial_info0,
119
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BAUD),
120
                      CYG_SERIAL_STOP_DEFAULT,
121
                      CYG_SERIAL_PARITY_DEFAULT,
122
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
123
                      CYG_SERIAL_FLAGS_DEFAULT
124
    );
125
#endif
126
 
127
DEVTAB_ENTRY(sa11x0_serial_io0,
128
             CYGDAT_IO_SERIAL_ARM_SA11X0_SERIAL0_NAME,
129
             0,                     // Does not depend on a lower level interface
130
             &cyg_io_serial_devio,
131
             sa11x0_serial_init,
132
             sa11x0_serial_lookup,     // Serial driver may need initializing
133
             &sa11x0_serial_channel0
134
    );
135
#endif //  CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL1
136
 
137
#ifdef CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL1
138
static sa11x0_serial_info sa11x0_serial_info1 = {(CYG_ADDRWORD)SA11X0_UART1_CONTROL0,
139
                                                 CYGNUM_HAL_INTERRUPT_UART1};
140
#if CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BUFSIZE > 0
141
static unsigned char sa11x0_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BUFSIZE];
142
static unsigned char sa11x0_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BUFSIZE];
143
 
144
static SERIAL_CHANNEL_USING_INTERRUPTS(sa11x0_serial_channel1,
145
                                       sa11x0_serial_funs,
146
                                       sa11x0_serial_info1,
147
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BAUD),
148
                                       CYG_SERIAL_STOP_DEFAULT,
149
                                       CYG_SERIAL_PARITY_DEFAULT,
150
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
151
                                       CYG_SERIAL_FLAGS_DEFAULT,
152
                                       &sa11x0_serial_out_buf1[0], sizeof(sa11x0_serial_out_buf1),
153
                                       &sa11x0_serial_in_buf1[0], sizeof(sa11x0_serial_in_buf1)
154
    );
155
#else
156
static SERIAL_CHANNEL(sa11x0_serial_channel1,
157
                      sa11x0_serial_funs,
158
                      sa11x0_serial_info1,
159
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BAUD),
160
                      CYG_SERIAL_STOP_DEFAULT,
161
                      CYG_SERIAL_PARITY_DEFAULT,
162
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
163
                      CYG_SERIAL_FLAGS_DEFAULT
164
    );
165
#endif
166
 
167
DEVTAB_ENTRY(sa11x0_serial_io1,
168
             CYGDAT_IO_SERIAL_ARM_SA11X0_SERIAL1_NAME,
169
             0,                     // Does not depend on a lower level interface
170
             &cyg_io_serial_devio,
171
             sa11x0_serial_init,
172
             sa11x0_serial_lookup,     // Serial driver may need initializing
173
             &sa11x0_serial_channel1
174
    );
175
#endif //  CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL1
176
 
177
// Internal function to actually configure the hardware to desired baud rate, etc.
178
static bool
179
sa11x0_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
180
{
181
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
182
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
183
    unsigned char parity = select_parity[new_config->parity];
184
    unsigned char word_length = select_word_length[new_config->word_length-CYGNUM_SERIAL_WORD_LENGTH_5];
185
    unsigned char stop_bits = select_stop_bits[new_config->stop];
186
    int baud = SA11X0_UART_BAUD_RATE_DIVISOR(select_baud[new_config->baud]);
187
    if ((word_length == 0xFF) ||
188
        (parity == 0xFF) ||
189
        (stop_bits == 0xFF)) {
190
        return false;  // Unsupported configuration
191
    }
192
    // Disable Receiver and Transmitter (clears FIFOs)
193
    port->ctl3 = SA11X0_UART_RX_DISABLED |
194
                 SA11X0_UART_TX_DISABLED;
195
 
196
    // Clear sticky (writable) status bits.
197
    port->stat0 = SA11X0_UART_RX_IDLE |
198
                  SA11X0_UART_RX_BEGIN_OF_BREAK |
199
                  SA11X0_UART_RX_END_OF_BREAK;
200
 
201
    // Set parity, word length, stop bits
202
    port->ctl0 = parity |
203
                 word_length |
204
                 stop_bits;
205
 
206
    // Set the desired baud rate.
207
    port->ctl1 = (baud >> 8) & SA11X0_UART_H_BAUD_RATE_DIVISOR_MASK;
208
    port->ctl2 = baud & SA11X0_UART_L_BAUD_RATE_DIVISOR_MASK;
209
 
210
    // Enable the receiver (with interrupts) and the transmitter.
211
    port->ctl3 = SA11X0_UART_RX_ENABLED |
212
                 SA11X0_UART_TX_ENABLED |
213
                 SA11X0_UART_RX_FIFO_INT_ENABLED;
214
    return true;
215
}
216
 
217
// Function to initialize the device.  Called at bootstrap time.
218
static bool
219
sa11x0_serial_init(struct cyg_devtab_entry *tab)
220
{
221
    serial_channel *chan = (serial_channel *)tab->priv;
222
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
223
    int res;
224
#ifdef CYGDBG_IO_INIT
225
    diag_printf("SA11X0 SERIAL init - dev: %x.%d\n", sa11x0_chan->base, sa11x0_chan->int_num);
226
#endif
227
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
228
    if (chan->out_cbuf.len != 0) {
229
        cyg_drv_interrupt_create(sa11x0_chan->int_num,
230
                                 99,                     // Priority - unused
231
                                 (cyg_addrword_t)chan,   // Data item passed to interrupt handler
232
                                 sa11x0_serial_ISR,
233
                                 sa11x0_serial_DSR,
234
                                 &sa11x0_chan->serial_interrupt_handle,
235
                                 &sa11x0_chan->serial_interrupt);
236
        cyg_drv_interrupt_attach(sa11x0_chan->serial_interrupt_handle);
237
        cyg_drv_interrupt_unmask(sa11x0_chan->int_num);
238
    }
239
    res = sa11x0_serial_config_port(chan, &chan->config, true);
240
    return res;
241
}
242
 
243
// This routine is called when the device is "looked" up (i.e. attached)
244
static Cyg_ErrNo
245
sa11x0_serial_lookup(struct cyg_devtab_entry **tab,
246
                  struct cyg_devtab_entry *sub_tab,
247
                  const char *name)
248
{
249
    serial_channel *chan = (serial_channel *)(*tab)->priv;
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
sa11x0_serial_putc(serial_channel *chan, unsigned char c)
258
{
259
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
260
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
261
    if (port->stat1 & SA11X0_UART_TX_FIFO_NOT_FULL) {
262
        port->data = c;
263
        return true;
264
    } else {
265
        return false;  // Couldn't send, tx was busy
266
    }
267
}
268
 
269
// Fetch a character from the device input buffer, waiting if necessary
270
static unsigned char
271
sa11x0_serial_getc(serial_channel *chan)
272
{
273
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
274
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
275
    return port->data;
276
}
277
 
278
// Set up the device characteristics; baud rate, etc.
279
static Cyg_ErrNo
280
sa11x0_serial_set_config(serial_channel *chan, cyg_uint32 key,
281
                         const void *xbuf, cyg_uint32 *len)
282
{
283
    switch (key) {
284
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
285
      {
286
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
287
        if ( *len < sizeof(cyg_serial_info_t) ) {
288
            return -EINVAL;
289
        }
290
        *len = sizeof(cyg_serial_info_t);
291
        if ( true != sa11x0_serial_config_port(chan, config, false) )
292
            return -EINVAL;
293
      }
294
      break;
295
    default:
296
        return -EINVAL;
297
    }
298
    return ENOERR;
299
}
300
 
301
// Enable the transmitter on the device
302
static void
303
sa11x0_serial_start_xmit(serial_channel *chan)
304
{
305
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
306
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
307
    (chan->callbacks->xmt_char)(chan);  // Kick transmitter (if necessary)
308
    port->ctl3 |= SA11X0_UART_TX_FIFO_INT_ENABLED;
309
}
310
 
311
// Disable the transmitter on the device
312
static void
313
sa11x0_serial_stop_xmit(serial_channel *chan)
314
{
315
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
316
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
317
    port->ctl3 &= ~SA11X0_UART_TX_FIFO_INT_ENABLED;
318
}
319
 
320
// Serial I/O - low level interrupt handler (ISR)
321
static cyg_uint32
322
sa11x0_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
323
{
324
    cyg_drv_interrupt_mask(vector);
325
    cyg_drv_interrupt_acknowledge(vector);
326
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
327
}
328
 
329
// Serial I/O - high level interrupt handler (DSR)
330
static void
331
sa11x0_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
332
{
333
    serial_channel *chan = (serial_channel *)data;
334
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
335
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
336
    unsigned int stat0 = port->stat0;
337
    if (stat0 & SA11X0_UART_TX_SERVICE_REQUEST) {
338
        (chan->callbacks->xmt_char)(chan);
339
    }
340
    if (stat0 & SA11X0_UART_RX_INTS) {
341
        while (port->stat1 & SA11X0_UART_RX_FIFO_NOT_EMPTY) {
342
            (chan->callbacks->rcv_char)(chan, port->data);
343
        }
344
        port->stat0 = SA11X0_UART_RX_IDLE;  // Need to clear this manually
345
    }
346
    if (stat0 & (SA11X0_UART_RX_BEGIN_OF_BREAK |
347
                 SA11X0_UART_RX_END_OF_BREAK ) ) {
348
        // Need to clear any of these manually also or noise
349
        // from plugging in can cause an interrupt loop!
350
        port->stat0 = stat0 & (SA11X0_UART_RX_BEGIN_OF_BREAK |
351
                               SA11X0_UART_RX_END_OF_BREAK );
352
    }
353
    cyg_drv_interrupt_unmask(vector);
354
}
355
#endif

powered by: WebSVN 2.1.0

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