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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [serial/] [m68k/] [mcf52xx/] [current/] [src/] [ser_mcf52xx.c] - Blame information for rev 798

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

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      ser_mcfxxxx.c
4
//
5
//      Serial driver for Freescale coldfire processors
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 2003, 2004, 2006, 2008 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):    bartv
43
// Contributors: bartv
44
// Date:         2003-06-04
45
// Purpose:      support coldfire on-chip uart's
46
// Description:  The various coldfire mcfxxxx processors all use the same
47
//               basic UART. There are some variations, e.g. different
48
//               fifo sizes, autobaud capability, and calculating baud
49
//               rates requires platform-specific knowledge such as the
50
//               cpu speed. Also there is no standardization of base
51
//               addresses or interrupt vectors. Never the less a single
52
//               driver should be able to support most devices, with
53
//               various processor-specific or platform-specific #define's
54
//               and other support.
55
//
56
//####DESCRIPTIONEND####
57
//==========================================================================
58
 
59
// NOTE: some platforms may use GPIO pins for other modem lines such as
60
// ring and DSR/DTR/DCD. This code could check for #ifdef HAL_MCF52xx_UART_SET_DCD()
61
// and incorporate support from the platform HAL.
62
 
63
#include <pkgconf/system.h>
64
#include <pkgconf/io_serial.h>
65
#include CYGBLD_HAL_VARIANT_H
66
#include CYGBLD_HAL_PROC_H
67
#include CYGBLD_HAL_PLATFORM_H
68
#include <pkgconf/devs_serial_mcfxxxx.h>
69
 
70
#include <cyg/io/io.h>
71
#include <cyg/io/devtab.h>
72
#include <cyg/io/serial.h>
73
 
74
#include <cyg/hal/hal_arch.h>
75
#include <cyg/hal/hal_intr.h>
76
#include <cyg/hal/hal_io.h>
77
 
78
//#define MCFxxxx_SERIAL_STATS    1
79
#undef MCFxxxx_SERIAL_STATS
80
 
81
#ifdef MCFxxxx_SERIAL_STATS
82
# define INCR_STAT(_info_, _field_, _amount_)           \
83
    CYG_MACRO_START                                     \
84
    (_info_)->_field_ += _amount_;                      \
85
    CYG_MACRO_END
86
#else
87
# define INCR_STAT(_info_, _field_, _amount_)           \
88
    CYG_MACRO_START                                     \
89
    CYG_MACRO_END
90
#endif
91
 
92
// ----------------------------------------------------------------------------
93
// devtab entries for the supported devices.
94
 
95
static bool             mcfxxxx_serial_init(struct cyg_devtab_entry*);
96
static Cyg_ErrNo        mcfxxxx_serial_lookup(struct cyg_devtab_entry**, struct cyg_devtab_entry*, const char*);
97
static Cyg_ErrNo        mcfxxxx_serial_set_config(serial_channel*, cyg_uint32, const void*, cyg_uint32*);
98
static bool             mcfxxxx_serial_putc(serial_channel*, unsigned char);
99
static unsigned char    mcfxxxx_serial_getc(serial_channel*);
100
static void             mcfxxxx_serial_start_xmit(serial_channel*);
101
static void             mcfxxxx_serial_stop_xmit(serial_channel*);
102
static cyg_uint32       mcfxxxx_serial_isr(cyg_vector_t, cyg_addrword_t);
103
static void             mcfxxxx_serial_dsr(cyg_vector_t, cyg_ucount32, cyg_addrword_t);
104
 
105
typedef struct mcfxxxx_serial_info {
106
    cyg_uint8*      base;
107
    cyg_vector_t    isr_vec;
108
    int             isr_priority;
109
    cyg_uint8       uimr_shadow;
110
    cyg_uint8       umr1_shadow;
111
    cyg_uint8       umr2_shadow;
112
    cyg_uint8       flags;
113
    cyg_interrupt   serial_interrupt;
114
    cyg_handle_t    serial_interrupt_handle;
115
#ifdef MCFxxxx_SERIAL_STATS
116
    cyg_uint32      isr_count;
117
    cyg_uint32      dsr_count;
118
    cyg_uint32      rx_bytes;
119
    cyg_uint32      tx_bytes;
120
    cyg_uint32      rx_errors;
121
#endif    
122
} mcfxxxx_serial_info;
123
 
124
#define MCFxxxx_SERIAL_RTS              (0x01 << 0)
125
#define MCFxxxx_SERIAL_CTS              (0x01 << 1)
126
#define MCFxxxx_SERIAL_RS485_RTS        (0x01 << 2)
127
 
128
static SERIAL_FUNS(mcfxxxx_serial_funs,
129
                   mcfxxxx_serial_putc,
130
                   mcfxxxx_serial_getc,
131
                   mcfxxxx_serial_set_config,
132
                   mcfxxxx_serial_start_xmit,
133
                   mcfxxxx_serial_stop_xmit
134
    );
135
 
136
 
137
#ifdef CYGPKG_DEVS_SERIAL_MCFxxxx_SERIAL0
138
static mcfxxxx_serial_info  mcfxxxx_serial0_info = {
139
    base:           (cyg_uint8*)HAL_MCFxxxx_UART0_BASE,
140
    isr_vec:        CYGNUM_HAL_ISR_UART0,
141
    isr_priority:   CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_ISR_PRIORITY,
142
#ifdef MCFxxxx_SERIAL_STATS
143
    isr_count:      0,
144
    dsr_count:      0,
145
    rx_bytes:       0,
146
    tx_bytes:       0,
147
    rx_errors:      0,
148
#endif
149
    flags:
150
#if defined(CYGHWR_HAL_M68K_MCFxxxx_UART0_RS485_RTS)
151
                    MCFxxxx_SERIAL_RS485_RTS |
152
#elif defined(CYGHWR_HAL_M68K_MCFxxxx_UART0_RTS)
153
                    MCFxxxx_SERIAL_RTS |
154
#endif    
155
#if defined(CYGHWR_HAL_M68K_MCFxxxx_UART0_CTS)
156
                    MCFxxxx_SERIAL_CTS |
157
#endif    
158
                    0x00
159
};
160
 
161
# ifdef CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_BUFSIZE
162
static unsigned char    mcfxxxx_serial0_tx_buf[CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_BUFSIZE];
163
static unsigned char    mcfxxxx_serial0_rx_buf[CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_BUFSIZE];
164
 
165
static SERIAL_CHANNEL_USING_INTERRUPTS(mcfxxxx_serial0_chan,
166
                                       mcfxxxx_serial_funs,
167
                                       mcfxxxx_serial0_info,
168
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_BAUD),
169
                                       CYG_SERIAL_STOP_DEFAULT,
170
                                       CYG_SERIAL_PARITY_DEFAULT,
171
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
172
                                       CYG_SERIAL_FLAGS_DEFAULT,
173
                                       mcfxxxx_serial0_tx_buf, CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_BUFSIZE,
174
                                       mcfxxxx_serial0_rx_buf, CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_BUFSIZE
175
    );
176
#else
177
static SERIAL_CHANNEL(mcfxxxx_serial0_chan,
178
                      mcfxxxx_serial_funs,
179
                      mcfxxxx_serial0_info,
180
                      CYG_SERIAL_BAUD_RATE(CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL0_BAUD),
181
                      CYG_SERIAL_STOP_DEFAULT,
182
                      CYG_SERIAL_PARITY_DEFAULT,
183
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
184
                      CYG_SERIAL_FLAGS_DEFAULT
185
    );
186
# endif
187
 
188
DEVTAB_ENTRY(mcfxxxx_serial0_devtab,
189
             CYGDAT_DEVS_SERIAL_MCFxxxx_SERIAL0_NAME,
190
             0,                     // Does not depend on a lower level interface
191
             &cyg_io_serial_devio,
192
             mcfxxxx_serial_init,
193
             mcfxxxx_serial_lookup,     // Serial driver may need initializing
194
             &mcfxxxx_serial0_chan
195
    );
196
#endif
197
 
198
#ifdef CYGPKG_DEVS_SERIAL_MCFxxxx_SERIAL1
199
static mcfxxxx_serial_info  mcfxxxx_serial1_info = {
200
    base:           (cyg_uint8*)HAL_MCFxxxx_UART1_BASE,
201
    isr_vec:        CYGNUM_HAL_ISR_UART1,
202
    isr_priority:   CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_ISR_PRIORITY,
203
#ifdef MCFxxxx_SERIAL_STATS
204
    isr_count:      0,
205
    dsr_count:      0,
206
    rx_bytes:       0,
207
    tx_bytes:       0,
208
    rx_errors:      0,
209
#endif    
210
    flags:
211
#if defined(CYGHWR_HAL_M68K_MCFxxxx_UART1_RS485_RTS)
212
                    MCFxxxx_SERIAL_RS485_RTS |
213
#elif defined(CYGHWR_HAL_M68K_MCFxxxx_UART1_RTS)
214
                    MCFxxxx_SERIAL_RTS |
215
#endif    
216
#if defined(CYGHWR_HAL_M68K_MCFxxxx_UART1_CTS)
217
                    MCFxxxx_SERIAL_CTS |
218
#endif    
219
                    0x00
220
};
221
 
222
# ifdef CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_BUFSIZE
223
static unsigned char    mcfxxxx_serial1_tx_buf[CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_BUFSIZE];
224
static unsigned char    mcfxxxx_serial1_rx_buf[CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_BUFSIZE];
225
 
226
static SERIAL_CHANNEL_USING_INTERRUPTS(mcfxxxx_serial1_chan,
227
                                       mcfxxxx_serial_funs,
228
                                       mcfxxxx_serial1_info,
229
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_BAUD),
230
                                       CYG_SERIAL_STOP_DEFAULT,
231
                                       CYG_SERIAL_PARITY_DEFAULT,
232
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
233
                                       CYG_SERIAL_FLAGS_DEFAULT,
234
                                       mcfxxxx_serial1_tx_buf, CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_BUFSIZE,
235
                                       mcfxxxx_serial1_rx_buf, CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_BUFSIZE
236
    );
237
#else
238
static SERIAL_CHANNEL(mcfxxxx_serial1_chan,
239
                      mcfxxxx_serial_funs,
240
                      mcfxxxx_serial1_info,
241
                      CYG_SERIAL_BAUD_RATE(CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL1_BAUD),
242
                      CYG_SERIAL_STOP_DEFAULT,
243
                      CYG_SERIAL_PARITY_DEFAULT,
244
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
245
                      CYG_SERIAL_FLAGS_DEFAULT
246
    );
247
# endif
248
 
249
DEVTAB_ENTRY(mcfxxxx_serial1_devtab,
250
             CYGDAT_DEVS_SERIAL_MCFxxxx_SERIAL1_NAME,
251
             0,                     // Does not depend on a lower level interface
252
             &cyg_io_serial_devio,
253
             mcfxxxx_serial_init,
254
             mcfxxxx_serial_lookup,     // Serial driver may need initializing
255
             &mcfxxxx_serial1_chan
256
    );
257
#endif
258
 
259
#ifdef CYGPKG_DEVS_SERIAL_MCFxxxx_SERIAL2
260
static mcfxxxx_serial_info  mcfxxxx_serial2_info = {
261
    base:           (cyg_uint8*)HAL_MCFxxxx_UART2_BASE,
262
    isr_vec:        CYGNUM_HAL_ISR_UART2,
263
    isr_priority:   CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_ISR_PRIORITY,
264
#ifdef MCFxxxx_SERIAL_STATS
265
    isr_count:      0,
266
    dsr_count:      0,
267
    rx_bytes:       0,
268
    tx_bytes:       0,
269
    rx_errors:      0,
270
#endif    
271
    flags:
272
#if defined(CYGHWR_HAL_M68K_MCFxxxx_UART2_RS485_RTS)
273
                    MCFxxxx_SERIAL_RS485_RTS |
274
#elif defined(CYGHWR_HAL_M68K_MCFxxxx_UART2_RTS)
275
                    MCFxxxx_SERIAL_RTS |
276
#endif    
277
#if defined(CYGHWR_HAL_M68K_MCFxxxx_UART2_CTS)
278
                    MCFxxxx_SERIAL_CTS |
279
#endif    
280
                    0x00
281
};
282
 
283
# ifdef CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_BUFSIZE
284
static unsigned char    mcfxxxx_serial2_tx_buf[CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_BUFSIZE];
285
static unsigned char    mcfxxxx_serial2_rx_buf[CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_BUFSIZE];
286
 
287
static SERIAL_CHANNEL_USING_INTERRUPTS(mcfxxxx_serial2_chan,
288
                                       mcfxxxx_serial_funs,
289
                                       mcfxxxx_serial2_info,
290
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_BAUD),
291
                                       CYG_SERIAL_STOP_DEFAULT,
292
                                       CYG_SERIAL_PARITY_DEFAULT,
293
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
294
                                       CYG_SERIAL_FLAGS_DEFAULT,
295
                                       mcfxxxx_serial2_tx_buf, CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_BUFSIZE,
296
                                       mcfxxxx_serial2_rx_buf, CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_BUFSIZE
297
    );
298
#else
299
static SERIAL_CHANNEL(mcfxxxx_serial2_chan,
300
                      mcfxxxx_serial_funs,
301
                      mcfxxxx_serial2_info,
302
                      CYG_SERIAL_BAUD_RATE(CYGNUM_DEVS_SERIAL_MCFxxxx_SERIAL2_BAUD),
303
                      CYG_SERIAL_STOP_DEFAULT,
304
                      CYG_SERIAL_PARITY_DEFAULT,
305
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
306
                      CYG_SERIAL_FLAGS_DEFAULT
307
    );
308
# endif
309
 
310
DEVTAB_ENTRY(mcfxxxx_serial2_devtab,
311
             CYGDAT_DEVS_SERIAL_MCFxxxx_SERIAL2_NAME,
312
             0,                     // Does not depend on a lower level interface
313
             &cyg_io_serial_devio,
314
             mcfxxxx_serial_init,
315
             mcfxxxx_serial_lookup,     // Serial driver may need initializing
316
             &mcfxxxx_serial2_chan
317
    );
318
#endif
319
 
320
// ----------------------------------------------------------------------------
321
 
322
static cyg_uint32   mcfxxxx_baud_rates[] = {
323
    0,      // Unused
324
    50,     // 50
325
    75,     // 75
326
    110,    // 110
327
    134,    // 134.5
328
    150,    // 150
329
    200,    // 200
330
    300,    // 300
331
    600,    // 600
332
    1200,   // 1200
333
    1800,   // 1800
334
    2400,   // 2400
335
    3600,   // 3600
336
    4800,   // 4800
337
    7200,   // 7200
338
    9600,   // 9600
339
    14400,  // 14400
340
    19200,  // 19200
341
    38400,  // 38400
342
    57600,  // 57600
343
    115200, // 115200
344
    230400  // 230400
345
};
346
 
347
static bool
348
mcfxxxx_serial_config(serial_channel* chan, cyg_serial_info_t* config, cyg_bool init)
349
{
350
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
351
    cyg_uint8*              base    = info->base;
352
 
353
    if (init) {
354
#if defined(CYGPKG_DEVS_SERIAL_MCFxxxx_SERIAL0) && defined(HAL_MCFxxxx_UART0_PROC_INIT)
355
        if (info == &mcfxxxx_serial0_info) {
356
            HAL_MCFxxxx_UART0_PROC_INIT();
357
        }
358
#endif
359
#if defined(CYGPKG_DEVS_SERIAL_MCFxxxx_SERIAL1) && defined(HAL_MCFxxxx_UART1_PROC_INIT)
360
        if (info == &mcfxxxx_serial1_info) {
361
            HAL_MCFxxxx_UART1_PROC_INIT();
362
        }
363
#endif
364
#if defined(CYGPKG_DEVS_SERIAL_MCFxxxx_SERIAL2) && defined(HAL_MCFxxxx_UART2_PROC_INIT)
365
        if (info == &mcfxxxx_serial2_info) {
366
            HAL_MCFxxxx_UART2_PROC_INIT();
367
        }
368
#endif
369
        // Various resets to get the UART in a known good state
370
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UCR]), HAL_MCFxxxx_UARTx_UCR_MISC_RR);
371
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UCR]), HAL_MCFxxxx_UARTx_UCR_MISC_RT);
372
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UCR]), HAL_MCFxxxx_UARTx_UCR_MISC_RES);
373
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UCR]), HAL_MCFxxxx_UARTx_UCR_MISC_RBCI);
374
 
375
        // Initialize the interrupt mask register. We want to trigger on rxrdy() and
376
        // optionally on breaks. Tx interrupts are not enabled by default, only
377
        // when a transmit is in progress.
378
        //
379
        // Some processors may define HAL_MCFxxxx_UARTx_UIMR_RXFTO which can be
380
        // used instead of RXRDY, getting an interrupt only when the fifo is full
381
        // or when 64 bit times have elapsed without new data. This reduces the
382
        // number of rx interrupts by e.g. a factor of 12. It is not without
383
        // penalty: if higher-level code could start processing data before the
384
        // fifo has filled up then the latency is increased significantly; even
385
        // if a whole packet needs to be received first, unless the packet size
386
        // maps cleanly on to fifo boundaries the latency is increased by the
387
        // timeout; if software flow control is in use then this side may not
388
        // respond to XON/XOFF bytes for a while. For now rx fifos are used
389
        // by default if available, although this should probably be made configurable.
390
        info->uimr_shadow = 0;
391
        if (chan->out_cbuf.len != 0) {
392
# if defined(HAL_MCFxxxx_UARTx_UIMR_RXFIFO) && defined(HAL_MCFxxxx_UARTx_UIMR_RXFTO) && defined(HAL_MCFxxxx_UARTx_URF)
393
            info->uimr_shadow = HAL_MCFxxxx_UARTx_UIMR_RXFTO | HAL_MCFxxxx_UARTx_UIMR_RXFIFO;
394
# else            
395
            info->uimr_shadow = HAL_MCFxxxx_UARTx_UIMR_RXRDY;
396
#endif            
397
        }
398
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
399
        info->uimr_shadow |= HAL_MCFxxxx_UARTx_UIMR_DB;
400
#endif
401
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UIMR]), info->uimr_shadow);
402
 
403
        // If the hardware supports tx fifo control, set it up so that
404
        // interrupts only occur when the fifo is more than 75% empty.
405
        // That cuts down on the number of interrupts without
406
        // affecting performance. The processor should service the interrupt
407
        // and replenish the fifo before the remaining bytes go out.
408
#ifdef HAL_MCFxxxx_UARTx_UTF
409
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UTF]), HAL_MCFxxxx_UARTx_UTF_TXS_75);
410
#endif
411
        // Ditto for rx fifo, but trigger on 50%. That is a compromise between
412
        // latency and efficiency.
413
#ifdef HAL_MCFxxxx_UARTx_URF
414
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_URF]), HAL_MCFxxxx_UARTx_URF_RXS_50);
415
#endif        
416
        // Always use the internal prescaled CLKIN.
417
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UCSR]), HAL_MCFxxxx_UARTx_UCSR_RCS_CLKIN | HAL_MCFxxxx_UARTx_UCSR_TCS_CLKIN);
418
 
419
        // Hardware flow control.
420
        //
421
        // Default: no TXRTS, no TXCTS, no RXRTS, no configurable RTS fifo level
422
        info->umr1_shadow   = 0x00;
423
        info->umr2_shadow   = 0x00;
424
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UACR]), 0x00);
425
 
426
        // CTS, used to throttle the transmitter automatically. This involves
427
        // setting the TXCTS bit. However it is not the default, h/w flow control
428
        // has to be explicitly enabled by a set_config() call.
429
 
430
        // RTS. This may not be connected at all, or it may be used
431
        // for h/w control of an RS485 transceiver, or it may be used
432
        // for RS232 handshaking. If the latter then the uart provides
433
        // automatic support for throttling the other side when the
434
        // fifo starts filling up.
435
        if (info->flags & MCFxxxx_SERIAL_RS485_RTS) {
436
            info->umr2_shadow   = HAL_MCFxxxx_UARTx_UMR2_TXRTS;
437
        } else if (info->flags & MCFxxxx_SERIAL_RTS) {
438
            // RS232 h/w flow control.
439
            // See if the processor supports configurable RTS levels.
440
# ifdef HAL_MCFxxxx_UARTx_UACR_RTSL_25
441
            // Set up RTS to change when the fifo is 25% full. This means the
442
            // processor can accept another 18 bytes, more than the 16-byte
443
            // transmit fifo in a typical PC uart. Increasing the RTS level to
444
            // any more than this may cause overruns.
445
            HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UACR]), HAL_MCFxxxx_UARTx_UACR_RTSL_25);
446
# else
447
            // Only RxRTS mode is supported, so use it.
448
            info->umr1_shadow   = HAL_MCFxxxx_UARTx_UMR1_RXRTS;
449
# endif
450
            // If RTS is connected assert it here, allowing the other side to transmit
451
            // data. This may be too early since the h/w is not fully set up yet, but
452
            // we only want to do this during init.
453
            HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UOP1]), HAL_MCFxxxx_UARTx_UOP_RTS);
454
        } else {
455
            // RTS is not connected at all.
456
        }
457
 
458
        // Enable both RX and TX
459
        HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UCR]), HAL_MCFxxxx_UARTx_UCR_TC_TE | HAL_MCFxxxx_UARTx_UCR_RC_RE);
460
    }
461
 
462
    info->umr1_shadow   &= ~(HAL_MCFxxxx_UARTx_UMR1_BC_MASK | HAL_MCFxxxx_UARTx_UMR1_PM_MASK);
463
    switch (config->word_length) {
464
      case CYGNUM_SERIAL_WORD_LENGTH_5:
465
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_BC_5;
466
        break;
467
      case CYGNUM_SERIAL_WORD_LENGTH_6:
468
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_BC_6;
469
        break;
470
      case CYGNUM_SERIAL_WORD_LENGTH_7:
471
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_BC_7;
472
        break;
473
      case CYGNUM_SERIAL_WORD_LENGTH_8:
474
      default:
475
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_BC_8;
476
        break;
477
    }
478
    switch (config->parity) {
479
      case CYGNUM_SERIAL_PARITY_EVEN:
480
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_PM_WITH;
481
        break;
482
      case CYGNUM_SERIAL_PARITY_ODD:
483
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_PM_WITH | HAL_MCFxxxx_UARTx_UMR1_PT;
484
        break;
485
      case CYGNUM_SERIAL_PARITY_MARK:
486
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_PM_FORCE  | HAL_MCFxxxx_UARTx_UMR1_PT;
487
        break;
488
      case CYGNUM_SERIAL_PARITY_SPACE:
489
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_PM_FORCE;
490
        break;
491
      case CYGNUM_SERIAL_PARITY_NONE:
492
      default:
493
        info->umr1_shadow |= HAL_MCFxxxx_UARTx_UMR1_PM_NO;
494
        break;
495
    }
496
    info->umr2_shadow &= ~HAL_MCFxxxx_UARTx_UMR2_SB_MASK;
497
    switch (config->stop) {
498
      case CYGNUM_SERIAL_STOP_2:
499
        info->umr2_shadow |= HAL_MCFxxxx_UARTx_UMR2_SB_2;
500
        break;
501
      case CYGNUM_SERIAL_STOP_1_5:
502
        info->umr2_shadow |= (CYGNUM_SERIAL_WORD_LENGTH_5 == config->word_length) ? 0x07 : 0x08;
503
        break;
504
      case CYGNUM_SERIAL_STOP_1:
505
      default:
506
        info->umr2_shadow |= (CYGNUM_SERIAL_WORD_LENGTH_5 == config->word_length) ? 0x00 : HAL_MCFxxxx_UARTx_UMR2_SB_1;
507
        break;
508
    }
509
 
510
    HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UCR]), HAL_MCFxxxx_UARTx_UCR_MISC_RMRP);
511
    HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UMR]), info->umr1_shadow);
512
    HAL_WRITE_UINT8(&(base[HAL_MCFxxxx_UARTx_UMR]), info->umr2_shadow);
513
 
514
    // Set the baud rate, using a processor or platform macro. That way the
515
    // calculation can depend on the clock speed.
516
    HAL_MCFxxxx_UARTx_SET_BAUD(base, mcfxxxx_baud_rates[config->baud]);
517
 
518
    if (config != &chan->config) {
519
        chan->config = *config;
520
    }
521
 
522
    return true;
523
}
524
 
525
// ----------------------------------------------------------------------------
526
static bool
527
mcfxxxx_serial_init(struct cyg_devtab_entry* devtab_entry)
528
{
529
    serial_channel*         chan    = (serial_channel*) devtab_entry->priv;
530
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
531
 
532
    mcfxxxx_serial_config(chan, &(chan->config), true);
533
 
534
    if (0 != chan->out_cbuf.len) {
535
        cyg_drv_interrupt_create(info->isr_vec,
536
                                 info->isr_priority,
537
                                 (cyg_addrword_t) chan,
538
                                 &mcfxxxx_serial_isr,
539
                                 &mcfxxxx_serial_dsr,
540
                                 &(info->serial_interrupt_handle),
541
                                 &(info->serial_interrupt));
542
        cyg_drv_interrupt_attach(info->serial_interrupt_handle);
543
        cyg_drv_interrupt_unmask(info->isr_vec);
544
    }
545
    return true;
546
}
547
 
548
// ----------------------------------------------------------------------------
549
static Cyg_ErrNo
550
mcfxxxx_serial_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name)
551
{
552
    serial_channel* chan    = (serial_channel*) (*tab)->priv;
553
    (chan->callbacks->serial_init)(chan);
554
    return ENOERR;
555
}
556
 
557
// ----------------------------------------------------------------------------
558
static Cyg_ErrNo
559
mcfxxxx_serial_set_config(serial_channel* chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
560
{
561
    Cyg_ErrNo result    = ENOERR;
562
 
563
    switch(key) {
564
      case CYG_IO_SET_CONFIG_SERIAL_INFO:
565
        {
566
            mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
567
            cyg_serial_info_t*  config = (cyg_serial_info_t*) buf;
568
            if (*len < sizeof(cyg_serial_info_t)) {
569
                return -EINVAL;
570
            }
571
            *len = sizeof(cyg_serial_info_t);
572
            // DSR/DTR is never supported.
573
            if (config->flags & (CYGNUM_SERIAL_FLOW_DSRDTR_RX | CYGNUM_SERIAL_FLOW_DSRDTR_TX)) {
574
                result = -ENOSUPP;
575
                config->flags &= ~(CYGNUM_SERIAL_FLOW_DSRDTR_RX | CYGNUM_SERIAL_FLOW_DSRDTR_TX);
576
            }
577
            // RTS/CTS may be supported, if the appropriate pins are connected.
578
            if ((config->flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX) && !(info->flags & MCFxxxx_SERIAL_RTS)) {
579
                result = -ENOSUPP;
580
                config->flags &= ~CYGNUM_SERIAL_FLOW_RTSCTS_RX;
581
            }
582
            if ((config->flags & CYGNUM_SERIAL_FLOW_RTSCTS_TX) && !(info->flags & MCFxxxx_SERIAL_CTS)) {
583
                result = -ENOSUPP;
584
                config->flags &= ~CYGNUM_SERIAL_FLOW_RTSCTS_TX;
585
            }
586
            if (ENOERR == result) {
587
                if (! mcfxxxx_serial_config(chan, config, false)) {
588
                    result = -EINVAL;
589
                }
590
            }
591
            break;
592
        }
593
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
594
      case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE:
595
        {
596
            // RX flow control involves just the RTS line. Most of the
597
            // work is done by the hardware depending on the state of
598
            // the fifo. This option serves mainly to drop RTS if
599
            // higher-level code is running out of buffer space, even
600
            // if the fifo is not yet full.
601
            mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
602
            cyg_uint32*             flag    = (cyg_uint32*) buf;
603
            if (! (info->flags & MCFxxxx_SERIAL_RTS)) {
604
                return -ENOSUPP;
605
            }
606
            if (*flag) {
607
                HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UOP0, HAL_MCFxxxx_UARTx_UOP_RTS);
608
            } else {
609
                HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UOP1, HAL_MCFxxxx_UARTx_UOP_RTS);
610
            }
611
        }
612
        break;
613
 
614
      case CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG:
615
        {
616
            mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
617
 
618
            // DSR/DTR is never supported.
619
            if (chan->config.flags & (CYGNUM_SERIAL_FLOW_DSRDTR_RX | CYGNUM_SERIAL_FLOW_DSRDTR_TX)) {
620
                result = -ENOSUPP;
621
                chan->config.flags &= ~(CYGNUM_SERIAL_FLOW_DSRDTR_RX | CYGNUM_SERIAL_FLOW_DSRDTR_TX);
622
            }
623
            // RTS/CTS may be supported, if the appropriate pins are connected.
624
            if ((chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX) && !(info->flags & MCFxxxx_SERIAL_RTS)) {
625
                result = -ENOSUPP;
626
                chan->config.flags &= ~CYGNUM_SERIAL_FLOW_RTSCTS_RX;
627
            }
628
            if ((chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_TX) && !(info->flags & MCFxxxx_SERIAL_CTS)) {
629
                result = -ENOSUPP;
630
                chan->config.flags &= ~CYGNUM_SERIAL_FLOW_RTSCTS_TX;
631
            }
632
 
633
            // RTS flow control for RX. Either UMR1 RxRTS or a UACR RTS trigger
634
            // level has been set during initialization. There is little point
635
            // changing either of these. If h/w flow control is being disabled
636
            // then the other side should start ignoring the RTS signal, even
637
            // if this side still thinks it is a good idea to change it depending
638
            // on the fifo level.
639
 
640
            // CTS flow control for TX just involves the UMR2 TxCTS bit.
641
            if (0 != (chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_TX)) {
642
                info->umr2_shadow |= HAL_MCFxxxx_UARTx_UMR2_TXCTS;
643
            } else {
644
                info->umr2_shadow &= ~HAL_MCFxxxx_UARTx_UMR2_TXCTS;
645
            }
646
            HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UCR, HAL_MCFxxxx_UARTx_UCR_MISC_RMRP);
647
            HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UMR, info->umr1_shadow);
648
            HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UMR, info->umr2_shadow);
649
        }
650
        break;
651
#endif
652
      default:
653
        return -EINVAL;
654
    }
655
 
656
    return result;
657
}
658
 
659
// ----------------------------------------------------------------------------
660
// Non-blocking send, returning true if the character was consumed. This can
661
// be called in both interrupt and polled mode.
662
 
663
static bool
664
mcfxxxx_serial_putc(serial_channel* chan, unsigned char ch)
665
{
666
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
667
    cyg_uint8               usr;
668
 
669
    HAL_READ_UINT8(info->base + HAL_MCFxxxx_UARTx_USR, usr);
670
    if (usr & HAL_MCFxxxx_UARTx_USR_TXRDY) {
671
        HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UTB, ch);
672
        INCR_STAT(info, tx_bytes, 1);
673
        return true;
674
    }
675
    return false;
676
}
677
 
678
// Blocking receive, only called in polled mode.
679
 
680
static unsigned char
681
mcfxxxx_serial_getc(serial_channel* chan)
682
{
683
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
684
    cyg_uint8               usr, data;
685
 
686
    do {
687
        HAL_READ_UINT8(info->base + HAL_MCFxxxx_UARTx_USR, usr);
688
    } while (! (usr & HAL_MCFxxxx_UARTx_USR_RXRDY));
689
    HAL_READ_UINT8(info->base + HAL_MCFxxxx_UARTx_URB, data);
690
    INCR_STAT(info, rx_bytes, 1);
691
    return data;
692
}
693
 
694
// Start transmitting, only called in interrupt mode. This just requires
695
// unmasking tx interrupts, with the interrupt handling code doing the
696
// rest. The UIMR register is write-only so this has to go via a shadow
697
// copy.
698
//
699
// If the processor supports interrupting on TXFIFO then that is used
700
// instead, raising interrupts only if the fifo >= 75% empty.
701
//
702
// In RS485 mode it is necessary to enable RTS here so that the transceiver
703
// is no longer tristated. RTS will be dropped automatically at the end of the
704
// transmit. It is assumed that the fifo will be refilled quickly enough
705
// that RTS does not get dropped too soon. Arguably RTS should be raised
706
// in the fifo fill code, but that would introduce problems if another node
707
// has decided a timeout has occurred and it should start transmitting now.
708
 
709
static void
710
mcfxxxx_serial_start_xmit(serial_channel* chan)
711
{
712
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
713
    CYG_INTERRUPT_STATE     saved_state;
714
 
715
    if (info->flags & MCFxxxx_SERIAL_RS485_RTS) {
716
        HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UOP1, HAL_MCFxxxx_UARTx_UOP_RTS);
717
    }
718
 
719
    HAL_DISABLE_INTERRUPTS(saved_state);
720
#ifdef HAL_MCFxxxx_UARTx_UIMR_TXFIFO
721
    info->uimr_shadow |= HAL_MCFxxxx_UARTx_UIMR_TXFIFO;
722
#else    
723
    info->uimr_shadow |= HAL_MCFxxxx_UARTx_UIMR_TXRDY;
724
#endif    
725
    HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UIMR, info->uimr_shadow);
726
    HAL_RESTORE_INTERRUPTS(saved_state);
727
}
728
 
729
// Stop transmitting, only called in interrupt mode.
730
static void
731
mcfxxxx_serial_stop_xmit(serial_channel* chan)
732
{
733
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
734
    CYG_INTERRUPT_STATE     saved_state;
735
 
736
    HAL_DISABLE_INTERRUPTS(saved_state);
737
#ifdef HAL_MCFxxxx_UARTx_UIMR_TXFIFO
738
    info->uimr_shadow &= ~HAL_MCFxxxx_UARTx_UIMR_TXFIFO;
739
#else    
740
    info->uimr_shadow &= ~HAL_MCFxxxx_UARTx_UIMR_TXRDY;
741
#endif    
742
    HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UIMR, info->uimr_shadow);
743
    HAL_RESTORE_INTERRUPTS(saved_state);
744
}
745
 
746
// ----------------------------------------------------------------------------
747
// The main serial I/O callbacks expect to be called in DSR context, not
748
// ISR context, so it is not possible to do much processing in the ISR.
749
// Instead everything is deferred to the DSR.
750
 
751
static cyg_uint32
752
mcfxxxx_serial_isr(cyg_vector_t vec, cyg_addrword_t data)
753
{
754
    serial_channel*         chan    = (serial_channel*) data;
755
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
756
    HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UIMR, 0);
757
 
758
    INCR_STAT(info, isr_count, 1);
759
 
760
    return CYG_ISR_CALL_DSR;
761
}
762
 
763
// ----------------------------------------------------------------------------
764
static void
765
mcfxxxx_serial_dsr(cyg_vector_t vec, cyg_ucount32 count, cyg_addrword_t data)
766
{
767
    serial_channel*         chan    = (serial_channel*) data;
768
    mcfxxxx_serial_info*    info    = (mcfxxxx_serial_info*) chan->dev_priv;
769
    cyg_uint8               uisr;
770
 
771
    INCR_STAT(info, dsr_count, 1);
772
 
773
    HAL_READ_UINT8(info->base + HAL_MCFxxxx_UARTx_UISR, uisr);
774
 
775
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
776
    // This is not quite right, it will report a break event instead of a delta-break,
777
    // so higher-level code will see two breaks instead of start-break and end-break.
778
    // In practice that should be good enough.
779
    //
780
    // There is also a received-break bit in the usr register, indicating that a
781
    // break occurred in the middle of a character.
782
    if (uisr & HAL_MCFxxxx_UARTx_UISR_DB) {
783
        cyg_serial_line_status_t    stat;
784
        HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UCR, HAL_MCFxxxx_UARTx_UCR_MISC_RBCI);
785
        stat.value  = 1;
786
        stat.which  = CYGNUM_SERIAL_STATUS_BREAK;
787
        (chan->callbacks->indicate_status)(chan, &stat);
788
    }
789
#endif
790
 
791
    // Do not report CTS changes to higher-level code. There is no point since flow
792
    // control should be handled by the hardware.
793
 
794
    if (uisr & HAL_MCFxxxx_UARTx_UISR_RXRDY) {
795
        cyg_uint8 usr, data;
796
        while (1) {
797
            HAL_READ_UINT8(info->base + HAL_MCFxxxx_UARTx_USR, usr);
798
 
799
            if (! (usr & HAL_MCFxxxx_UARTx_USR_RXRDY)) {
800
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS                
801
                // Now check for an overrun, so that the error is
802
                // reported in approximately the right place in the
803
                // data stream. It is possible that an extra byte
804
                // or so has come in after the overrun, but that
805
                // cannot be detected.
806
                if (usr & HAL_MCFxxxx_UARTx_USR_OE) {
807
                    cyg_serial_line_status_t    stat;
808
                    HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UCR, HAL_MCFxxxx_UARTx_UCR_MISC_RES);
809
                    stat.value  = 1;
810
                    stat.which  = CYGNUM_SERIAL_STATUS_OVERRUNERR;
811
                    (chan->callbacks->indicate_status)(chan, &stat);
812
                    INCR_STAT(info, rx_errors, 1);
813
                }
814
#endif
815
                // There is no more data in the fifo, so look for transmits.
816
                break;
817
            }
818
 
819
            // RXRDY is set, so we have either a valid or a corrupted byte
820
            // in the current fifo position. First pass the byte up the stack,
821
            // then report the error.
822
            HAL_READ_UINT8(info->base + HAL_MCFxxxx_UARTx_URB, data);
823
            (chan->callbacks->rcv_char)(chan, data);
824
            INCR_STAT(info, rx_bytes, 1);
825
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
826
            if (usr & HAL_MCFxxxx_UARTx_USR_FE) {
827
                cyg_serial_line_status_t    stat;
828
                stat.value = 1;
829
                stat.which  = CYGNUM_SERIAL_STATUS_FRAMEERR;
830
                (chan->callbacks->indicate_status)(chan, &stat);
831
                INCR_STAT(info, rx_errors, 1);
832
            }
833
            if (usr & HAL_MCFxxxx_UARTx_USR_PE) {
834
                cyg_serial_line_status_t    stat;
835
                stat.value = 1;
836
                stat.which  = CYGNUM_SERIAL_STATUS_PARITYERR;
837
                (chan->callbacks->indicate_status)(chan, &stat);
838
                INCR_STAT(info, rx_errors, 1);
839
            }
840
#endif
841
        }
842
    }
843
 
844
    if (uisr & HAL_MCFxxxx_UARTx_UISR_TXRDY) {
845
        (chan->callbacks->xmt_char)(chan);
846
    }
847
 
848
    // Re-enable UART interrupts
849
    HAL_WRITE_UINT8(info->base + HAL_MCFxxxx_UARTx_UIMR, info->uimr_shadow);
850
}

powered by: WebSVN 2.1.0

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