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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [serial/] [arm/] [sa11x0/] [current/] [src/] [sa11x0_serial.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
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 Free Software Foundation, 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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):     gthomas
43
// Contributors:  gthomas
44
// Date:          2000-05-08
45
// Purpose:       StrongARM SA11x0 Serial I/O module (interrupt driven version)
46
// Description: 
47
//
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
#include <pkgconf/system.h>
53
#include <pkgconf/io_serial.h>
54
#include <pkgconf/io.h>
55
#include <pkgconf/kernel.h>
56
 
57
#include <cyg/io/io.h>
58
#include <cyg/hal/hal_intr.h>
59
#include <cyg/io/devtab.h>
60
#include <cyg/io/serial.h>
61
#include <cyg/infra/diag.h>
62
 
63
#ifdef CYGPKG_IO_SERIAL_ARM_SA11X0
64
 
65
#include "sa11x0_serial.h"
66
 
67
typedef struct sa11x0_serial_info {
68
    CYG_ADDRWORD   base;
69
    CYG_WORD       int_num;
70
    cyg_interrupt  serial_interrupt;
71
    cyg_handle_t   serial_interrupt_handle;
72
} sa11x0_serial_info;
73
 
74
static bool sa11x0_serial_init(struct cyg_devtab_entry *tab);
75
static bool sa11x0_serial_putc(serial_channel *chan, unsigned char c);
76
static Cyg_ErrNo sa11x0_serial_lookup(struct cyg_devtab_entry **tab,
77
                                   struct cyg_devtab_entry *sub_tab,
78
                                   const char *name);
79
static unsigned char sa11x0_serial_getc(serial_channel *chan);
80
static Cyg_ErrNo sa11x0_serial_set_config(serial_channel *chan, cyg_uint32 key,
81
                                          const void *xbuf, cyg_uint32 *len);
82
static void sa11x0_serial_start_xmit(serial_channel *chan);
83
static void sa11x0_serial_stop_xmit(serial_channel *chan);
84
 
85
static cyg_uint32 sa11x0_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
86
static void       sa11x0_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
87
 
88
static SERIAL_FUNS(sa11x0_serial_funs,
89
                   sa11x0_serial_putc,
90
                   sa11x0_serial_getc,
91
                   sa11x0_serial_set_config,
92
                   sa11x0_serial_start_xmit,
93
                   sa11x0_serial_stop_xmit
94
    );
95
 
96
#ifdef CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL0
97
static sa11x0_serial_info sa11x0_serial_info0 = {(CYG_ADDRWORD)SA11X0_UART3_CONTROL0,
98
                                                 CYGNUM_HAL_INTERRUPT_UART3};
99
#if CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BUFSIZE > 0
100
static unsigned char sa11x0_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BUFSIZE];
101
static unsigned char sa11x0_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BUFSIZE];
102
 
103
static SERIAL_CHANNEL_USING_INTERRUPTS(sa11x0_serial_channel0,
104
                                       sa11x0_serial_funs,
105
                                       sa11x0_serial_info0,
106
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BAUD),
107
                                       CYG_SERIAL_STOP_DEFAULT,
108
                                       CYG_SERIAL_PARITY_DEFAULT,
109
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
110
                                       CYG_SERIAL_FLAGS_DEFAULT,
111
                                       &sa11x0_serial_out_buf0[0], sizeof(sa11x0_serial_out_buf0),
112
                                       &sa11x0_serial_in_buf0[0], sizeof(sa11x0_serial_in_buf0)
113
    );
114
#else
115
static SERIAL_CHANNEL(sa11x0_serial_channel0,
116
                      sa11x0_serial_funs,
117
                      sa11x0_serial_info0,
118
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL0_BAUD),
119
                      CYG_SERIAL_STOP_DEFAULT,
120
                      CYG_SERIAL_PARITY_DEFAULT,
121
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
122
                      CYG_SERIAL_FLAGS_DEFAULT
123
    );
124
#endif
125
 
126
DEVTAB_ENTRY(sa11x0_serial_io0,
127
             CYGDAT_IO_SERIAL_ARM_SA11X0_SERIAL0_NAME,
128
             0,                     // Does not depend on a lower level interface
129
             &cyg_io_serial_devio,
130
             sa11x0_serial_init,
131
             sa11x0_serial_lookup,     // Serial driver may need initializing
132
             &sa11x0_serial_channel0
133
    );
134
#endif //  CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL1
135
 
136
#ifdef CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL1
137
static sa11x0_serial_info sa11x0_serial_info1 = {(CYG_ADDRWORD)SA11X0_UART1_CONTROL0,
138
                                                 CYGNUM_HAL_INTERRUPT_UART1};
139
#if CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BUFSIZE > 0
140
static unsigned char sa11x0_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BUFSIZE];
141
static unsigned char sa11x0_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BUFSIZE];
142
 
143
static SERIAL_CHANNEL_USING_INTERRUPTS(sa11x0_serial_channel1,
144
                                       sa11x0_serial_funs,
145
                                       sa11x0_serial_info1,
146
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BAUD),
147
                                       CYG_SERIAL_STOP_DEFAULT,
148
                                       CYG_SERIAL_PARITY_DEFAULT,
149
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
150
                                       CYG_SERIAL_FLAGS_DEFAULT,
151
                                       &sa11x0_serial_out_buf1[0], sizeof(sa11x0_serial_out_buf1),
152
                                       &sa11x0_serial_in_buf1[0], sizeof(sa11x0_serial_in_buf1)
153
    );
154
#else
155
static SERIAL_CHANNEL(sa11x0_serial_channel1,
156
                      sa11x0_serial_funs,
157
                      sa11x0_serial_info1,
158
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_SA11X0_SERIAL1_BAUD),
159
                      CYG_SERIAL_STOP_DEFAULT,
160
                      CYG_SERIAL_PARITY_DEFAULT,
161
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
162
                      CYG_SERIAL_FLAGS_DEFAULT
163
    );
164
#endif
165
 
166
DEVTAB_ENTRY(sa11x0_serial_io1,
167
             CYGDAT_IO_SERIAL_ARM_SA11X0_SERIAL1_NAME,
168
             0,                     // Does not depend on a lower level interface
169
             &cyg_io_serial_devio,
170
             sa11x0_serial_init,
171
             sa11x0_serial_lookup,     // Serial driver may need initializing
172
             &sa11x0_serial_channel1
173
    );
174
#endif //  CYGPKG_IO_SERIAL_ARM_SA11X0_SERIAL1
175
 
176
// Internal function to actually configure the hardware to desired baud rate, etc.
177
static bool
178
sa11x0_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
179
{
180
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
181
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
182
    unsigned char parity = select_parity[new_config->parity];
183
    unsigned char word_length = select_word_length[new_config->word_length-CYGNUM_SERIAL_WORD_LENGTH_5];
184
    unsigned char stop_bits = select_stop_bits[new_config->stop];
185
    int baud = SA11X0_UART_BAUD_RATE_DIVISOR(select_baud[new_config->baud]);
186
    if ((word_length == 0xFF) ||
187
        (parity == 0xFF) ||
188
        (stop_bits == 0xFF)) {
189
        return false;  // Unsupported configuration
190
    }
191
    // Disable Receiver and Transmitter (clears FIFOs)
192
    port->ctl3 = SA11X0_UART_RX_DISABLED |
193
                 SA11X0_UART_TX_DISABLED;
194
 
195
    // Clear sticky (writable) status bits.
196
    port->stat0 = SA11X0_UART_RX_IDLE |
197
                  SA11X0_UART_RX_BEGIN_OF_BREAK |
198
                  SA11X0_UART_RX_END_OF_BREAK;
199
 
200
    // Set parity, word length, stop bits
201
    port->ctl0 = parity |
202
                 word_length |
203
                 stop_bits;
204
 
205
    // Set the desired baud rate.
206
    port->ctl1 = (baud >> 8) & SA11X0_UART_H_BAUD_RATE_DIVISOR_MASK;
207
    port->ctl2 = baud & SA11X0_UART_L_BAUD_RATE_DIVISOR_MASK;
208
 
209
    // Enable the receiver (with interrupts) and the transmitter.
210
    port->ctl3 = SA11X0_UART_RX_ENABLED |
211
                 SA11X0_UART_TX_ENABLED |
212
                 SA11X0_UART_RX_FIFO_INT_ENABLED;
213
    return true;
214
}
215
 
216
// Function to initialize the device.  Called at bootstrap time.
217
static bool
218
sa11x0_serial_init(struct cyg_devtab_entry *tab)
219
{
220
    serial_channel *chan = (serial_channel *)tab->priv;
221
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
222
    int res;
223
#ifdef CYGDBG_IO_INIT
224
    diag_printf("SA11X0 SERIAL init - dev: %x.%d\n", sa11x0_chan->base, sa11x0_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(sa11x0_chan->int_num,
229
                                 99,                     // Priority - unused
230
                                 (cyg_addrword_t)chan,   // Data item passed to interrupt handler
231
                                 sa11x0_serial_ISR,
232
                                 sa11x0_serial_DSR,
233
                                 &sa11x0_chan->serial_interrupt_handle,
234
                                 &sa11x0_chan->serial_interrupt);
235
        cyg_drv_interrupt_attach(sa11x0_chan->serial_interrupt_handle);
236
        cyg_drv_interrupt_unmask(sa11x0_chan->int_num);
237
    }
238
    res = sa11x0_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
sa11x0_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
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
250
    return ENOERR;
251
}
252
 
253
// Send a character to the device output buffer.
254
// Return 'true' if character is sent to device
255
static bool
256
sa11x0_serial_putc(serial_channel *chan, unsigned char c)
257
{
258
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
259
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
260
    if (port->stat1 & SA11X0_UART_TX_FIFO_NOT_FULL) {
261
        port->data = c;
262
        return true;
263
    } else {
264
        return false;  // Couldn't send, tx was busy
265
    }
266
}
267
 
268
// Fetch a character from the device input buffer, waiting if necessary
269
static unsigned char
270
sa11x0_serial_getc(serial_channel *chan)
271
{
272
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
273
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
274
    return port->data;
275
}
276
 
277
// Set up the device characteristics; baud rate, etc.
278
static Cyg_ErrNo
279
sa11x0_serial_set_config(serial_channel *chan, cyg_uint32 key,
280
                         const void *xbuf, cyg_uint32 *len)
281
{
282
    switch (key) {
283
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
284
      {
285
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
286
        if ( *len < sizeof(cyg_serial_info_t) ) {
287
            return -EINVAL;
288
        }
289
        *len = sizeof(cyg_serial_info_t);
290
        if ( true != sa11x0_serial_config_port(chan, config, false) )
291
            return -EINVAL;
292
      }
293
      break;
294
    default:
295
        return -EINVAL;
296
    }
297
    return ENOERR;
298
}
299
 
300
// Enable the transmitter on the device
301
static void
302
sa11x0_serial_start_xmit(serial_channel *chan)
303
{
304
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
305
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
306
    (chan->callbacks->xmt_char)(chan);  // Kick transmitter (if necessary)
307
    port->ctl3 |= SA11X0_UART_TX_FIFO_INT_ENABLED;
308
}
309
 
310
// Disable the transmitter on the device
311
static void
312
sa11x0_serial_stop_xmit(serial_channel *chan)
313
{
314
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
315
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
316
    port->ctl3 &= ~SA11X0_UART_TX_FIFO_INT_ENABLED;
317
}
318
 
319
// Serial I/O - low level interrupt handler (ISR)
320
static cyg_uint32
321
sa11x0_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
322
{
323
    cyg_drv_interrupt_mask(vector);
324
    cyg_drv_interrupt_acknowledge(vector);
325
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
326
}
327
 
328
// Serial I/O - high level interrupt handler (DSR)
329
static void
330
sa11x0_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
331
{
332
    serial_channel *chan = (serial_channel *)data;
333
    sa11x0_serial_info *sa11x0_chan = (sa11x0_serial_info *)chan->dev_priv;
334
    volatile struct serial_port *port = (volatile struct serial_port *)sa11x0_chan->base;
335
    unsigned int stat0 = port->stat0;
336
    if (stat0 & SA11X0_UART_TX_SERVICE_REQUEST) {
337
        (chan->callbacks->xmt_char)(chan);
338
    }
339
    if (stat0 & SA11X0_UART_RX_INTS) {
340
        while (port->stat1 & SA11X0_UART_RX_FIFO_NOT_EMPTY) {
341
            (chan->callbacks->rcv_char)(chan, port->data);
342
        }
343
        port->stat0 = SA11X0_UART_RX_IDLE;  // Need to clear this manually
344
    }
345
    if (stat0 & (SA11X0_UART_RX_BEGIN_OF_BREAK |
346
                 SA11X0_UART_RX_END_OF_BREAK ) ) {
347
        // Need to clear any of these manually also or noise
348
        // from plugging in can cause an interrupt loop!
349
        port->stat0 = stat0 & (SA11X0_UART_RX_BEGIN_OF_BREAK |
350
                               SA11X0_UART_RX_END_OF_BREAK );
351
    }
352
    cyg_drv_interrupt_unmask(vector);
353
}
354
#endif

powered by: WebSVN 2.1.0

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