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/] [mips/] [jmr3904/] [v2_0/] [src/] [tx3904_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
//      tx3904_serial.c
4
//
5
//      Serial device driver for TX3904 on-chip serial devices
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):   nickg
44
// Contributors: nickg
45
// Date:        1999-03-3
46
// Purpose:     TX3904 serial device driver
47
// Description: TX3904 serial device driver
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
#include <pkgconf/hal.h>
54
#include <pkgconf/io_serial.h>
55
#include <cyg/hal/hal_io.h>
56
#include <cyg/hal/hal_intr.h>
57
 
58
#include <cyg/io/io.h>
59
#include <cyg/io/devtab.h>
60
#include <cyg/io/serial.h>
61
 
62
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904
63
 
64
cyg_bool cyg_hal_is_break(char *buf, int size);
65
void cyg_hal_user_break( CYG_ADDRWORD *regs );
66
 
67
//-------------------------------------------------------------------------
68
 
69
extern void diag_printf(const char *fmt, ...);
70
 
71
//-------------------------------------------------------------------------
72
// Forward definitions
73
 
74
static bool tx3904_serial_init(struct cyg_devtab_entry *tab);
75
static bool tx3904_serial_putc(serial_channel *chan, unsigned char c);
76
static Cyg_ErrNo tx3904_serial_lookup(struct cyg_devtab_entry **tab,
77
                                   struct cyg_devtab_entry *sub_tab,
78
                                   const char *name);
79
static unsigned char tx3904_serial_getc(serial_channel *chan);
80
static Cyg_ErrNo tx3904_serial_set_config(serial_channel *chan, cyg_uint32 key,
81
                                          const void *xbuf, cyg_uint32 *len);
82
static void tx3904_serial_start_xmit(serial_channel *chan);
83
static void tx3904_serial_stop_xmit(serial_channel *chan);
84
 
85
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
86
static cyg_uint32 tx3904_serial_ISR(cyg_vector_t vector, cyg_addrword_t data, cyg_addrword_t *regs);
87
static void       tx3904_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
88
#endif
89
 
90
 
91
//-------------------------------------------------------------------------
92
// TX3904 serial line control register values:
93
 
94
// Offsets to serial control registers from base
95
#define SERIAL_CR       0x00
96
#define SERIAL_SR       0x04
97
#define SERIAL_ICR      0x08
98
#define SERIAL_ISR      0x0C
99
#define SERIAL_FCR      0x10
100
#define SERIAL_BRG      0x14
101
#define SERIAL_TXB      0x20
102
#define SERIAL_RXB      0x30
103
 
104
// Status register bits
105
#define ISR_RXRDY       0x01
106
#define ISR_TXRDY       0x02
107
#define ISR_ERROR       0x04
108
 
109
// Control register bits
110
#define LCR_SB1         0x0000
111
#define LCR_SB1_5       0x0000
112
#define LCR_SB2         0x0004
113
#define LCR_PN          0x0000    // Parity mode - none
114
#define LCR_PS          0x0000    // Forced "space" parity
115
#define LCR_PM          0x0000    // Forced "mark" parity
116
#define LCR_PE          0x0018    // Parity mode - even
117
#define LCR_PO          0x0010    // Parity mode - odd
118
#define LCR_WL5         0x0001    // not supported - use 7bit
119
#define LCR_WL6         0x0001    // not supported - use 7bit
120
#define LCR_WL7         0x0001    // 7 bit chars
121
#define LCR_WL8         0x0000    // 8 bit chars
122
 
123
#define LCR_BRG         0x0020    // Select baud rate generator
124
 
125
#define ICR_RXE         0x0001  // receive enable
126
#define ICR_TXE         0x0002  // transmit enable
127
 
128
//-------------------------------------------------------------------------
129
// Tables to map input values to hardware settings
130
 
131
static unsigned char select_word_length[] = {
132
    LCR_WL5,    // 5 bits / word (char)
133
    LCR_WL6,
134
    LCR_WL7,
135
    LCR_WL8
136
};
137
 
138
static unsigned char select_stop_bits[] = {
139
    0,
140
    LCR_SB1,    // 1 stop bit
141
    LCR_SB1_5,  // 1.5 stop bit
142
    LCR_SB2     // 2 stop bits
143
};
144
 
145
static unsigned char select_parity[] = {
146
    LCR_PN,     // No parity
147
    LCR_PE,     // Even parity
148
    LCR_PO,     // Odd parity
149
    LCR_PM,     // Mark parity
150
    LCR_PS,     // Space parity
151
};
152
 
153
// The values in this table plug straight into the BRG register
154
// in the serial driver hardware. They comprise a baud rate divisor
155
// in the bottom 8 bits and a clock selector in the top 8 bits.
156
// These figures all come from Toshiba.
157
 
158
#if (CYGHWR_HAL_MIPS_CPU_FREQ == 50)
159
 
160
static unsigned short select_baud[] = {
161
    0,          // Unused
162
    0,          // 50
163
    0,          // 75
164
    0,          // 110
165
    0,          // 134.5
166
    0,          // 150
167
    0,          // 200
168
    0,          // 300
169
    0x0300|20,  // 600
170
    0x0300|10,  // 1200
171
    0,          // 1800
172
    0x0300|05,  // 2400
173
    0,          // 3600
174
    0x0300|10,  // 4800
175
    0,          // 7200
176
    0x0200|05,  // 9600
177
    0,          // 14400
178
    0x0100|10,  // 19200
179
    0x0100|05,  // 38400
180
    0,          // 57600
181
    0,          // 115200
182
    0,          // 230400
183
};
184
 
185
#elif (CYGHWR_HAL_MIPS_CPU_FREQ == 66)
186
 
187
static unsigned short select_baud[] = {
188
    0,          // Unused
189
    0,          // 50
190
    0,          // 75
191
    0,          // 110
192
    0,          // 134.5
193
    0,          // 150
194
    0,          // 200
195
    0,          // 300
196
    0x0300|27,  // 600
197
    0x0200|54,  // 1200
198
    0,          // 1800
199
    0x0200|27,  // 2400
200
    0,          // 3600
201
    0x0100|54,  // 4800
202
    0,          // 7200
203
    0x0100|27,  // 9600
204
    0,          // 14400
205
    0x0000|54,  // 19200
206
    0x0000|27,  // 38400
207
    0,          // 57600
208
    0,          // 115200
209
    0,          // 230400
210
};
211
 
212
#else
213
 
214
#error Unsupported CPU frequency
215
 
216
#endif
217
 
218
//-------------------------------------------------------------------------
219
// Info for each serial device controlled
220
 
221
typedef struct tx3904_serial_info {
222
    CYG_ADDRWORD   base;
223
    CYG_WORD       int_num;
224
    cyg_interrupt  interrupt;
225
    cyg_handle_t   interrupt_handle;
226
    cyg_uint8      input_char;
227
    cyg_bool       input_char_valid;
228
    cyg_bool       output_ready;
229
    cyg_uint16     cur_baud;
230
} tx3904_serial_info;
231
 
232
//-------------------------------------------------------------------------
233
// Callback functions exported by this driver
234
 
235
static SERIAL_FUNS(tx3904_serial_funs,
236
                   tx3904_serial_putc,
237
                   tx3904_serial_getc,
238
                   tx3904_serial_set_config,
239
                   tx3904_serial_start_xmit,
240
                   tx3904_serial_stop_xmit
241
    );
242
 
243
//-------------------------------------------------------------------------
244
// Hardware info for each serial line
245
 
246
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
247
static tx3904_serial_info tx3904_serial_info0 = {
248
    0xFFFFF300,
249
    CYGNUM_HAL_INTERRUPT_SIO_0
250
};
251
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE > 0
252
static unsigned char tx3904_serial_out_buf0[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE];
253
static unsigned char tx3904_serial_in_buf0[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE];
254
#endif
255
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
256
 
257
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
258
static tx3904_serial_info tx3904_serial_info1 = {
259
    0xFFFFF400,
260
    CYGNUM_HAL_INTERRUPT_SIO_1
261
};
262
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE > 0
263
static unsigned char tx3904_serial_out_buf1[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE];
264
static unsigned char tx3904_serial_in_buf1[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE];
265
#endif
266
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
267
 
268
//-------------------------------------------------------------------------
269
// Channel descriptions:
270
 
271
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
272
#define SIZEOF_BUF(_x_) 0
273
#else
274
#define SIZEOF_BUF(_x_) sizeof(_x_)
275
#endif
276
 
277
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
278
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE > 0
279
static SERIAL_CHANNEL_USING_INTERRUPTS(tx3904_serial_channel0,
280
                                       tx3904_serial_funs,
281
                                       tx3904_serial_info0,
282
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BAUD),
283
                                       CYG_SERIAL_STOP_DEFAULT,
284
                                       CYG_SERIAL_PARITY_DEFAULT,
285
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
286
                                       CYG_SERIAL_FLAGS_DEFAULT,
287
                                       &tx3904_serial_out_buf0[0],
288
                                       SIZEOF_BUF(tx3904_serial_out_buf0),
289
                                       &tx3904_serial_in_buf0[0],
290
                                       SIZEOF_BUF(tx3904_serial_in_buf0)
291
    );
292
#else
293
static SERIAL_CHANNEL(tx3904_serial_channel0,
294
                      tx3904_serial_funs,
295
                      tx3904_serial_info0,
296
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BAUD),
297
                      CYG_SERIAL_STOP_DEFAULT,
298
                      CYG_SERIAL_PARITY_DEFAULT,
299
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
300
                      CYG_SERIAL_FLAGS_DEFAULT
301
    );
302
#endif
303
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
304
 
305
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
306
#if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE > 0
307
static SERIAL_CHANNEL_USING_INTERRUPTS(tx3904_serial_channel1,
308
                                       tx3904_serial_funs,
309
                                       tx3904_serial_info1,
310
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BAUD),
311
                                       CYG_SERIAL_STOP_DEFAULT,
312
                                       CYG_SERIAL_PARITY_DEFAULT,
313
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
314
                                       CYG_SERIAL_FLAGS_DEFAULT,
315
                                       &tx3904_serial_out_buf1[0],
316
                                       SIZEOF_BUF(tx3904_serial_out_buf1),
317
                                       &tx3904_serial_in_buf1[0],
318
                                       SIZEOF_BUF(tx3904_serial_in_buf1)
319
    );
320
#else
321
static SERIAL_CHANNEL(tx3904_serial_channel1,
322
                      tx3904_serial_funs,
323
                      tx3904_serial_info1,
324
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BAUD),
325
                      CYG_SERIAL_STOP_DEFAULT,
326
                      CYG_SERIAL_PARITY_DEFAULT,
327
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
328
                      CYG_SERIAL_FLAGS_DEFAULT
329
    );
330
#endif
331
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
332
 
333
//-------------------------------------------------------------------------
334
// And finally, the device table entries:
335
 
336
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
337
DEVTAB_ENTRY(tx3904_serial_io0,
338
             CYGDAT_IO_SERIAL_TX39_JMR3904_SERIAL0_NAME,
339
             0,                     // Does not depend on a lower level interface
340
             &cyg_io_serial_devio,
341
             tx3904_serial_init,
342
             tx3904_serial_lookup,     // Serial driver may need initializing
343
             &tx3904_serial_channel0
344
    );
345
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
346
 
347
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
348
DEVTAB_ENTRY(tx3904_serial_io1,
349
             CYGDAT_IO_SERIAL_TX39_JMR3904_SERIAL1_NAME,
350
             0,                     // Does not depend on a lower level interface
351
             &cyg_io_serial_devio,
352
             tx3904_serial_init,
353
             tx3904_serial_lookup,     // Serial driver may need initializing
354
             &tx3904_serial_channel1
355
    );
356
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
357
 
358
// ------------------------------------------------------------------------
359
// Delay for some number of character times. This is based on the baud
360
// rate currently set. We use the numbers that plug in to the BRG
361
// clock select and divider to control two loops. The innermost delay
362
// loop uses a count that is derived from dividing the CPU frequency
363
// by the BRG granularity (and we then add 1 to compensate for any
364
// rounding).  This gives the number of cycles that the innermost loop
365
// must consume.  For the sake of simplicity we assume that this loop
366
// will take 1 cycle per loop, which is roughly true in optimized
367
// code.
368
 
369
void delay_char_time(tx3904_serial_info *tx3904_chan, int n)
370
{
371
    static cyg_uint16 clock_val[4] = { 4, 16, 64, 256 };
372
    cyg_uint16 baud_val = select_baud[tx3904_chan->cur_baud];
373
    cyg_count32 clock_loop = clock_val[baud_val>>8];
374
    cyg_count32 div_loop = baud_val & 0xFF;
375
    cyg_count32 bit_time = ((CYGHWR_HAL_MIPS_CPU_FREQ_ACTUAL)/(2457600)) + 1;
376
 
377
    n *= 11;    // allow for start and stop bits and 8 data bits
378
 
379
    while( n-- )
380
    {
381
        cyg_count32 i,j,k;
382
 
383
        for( i = 0; i < clock_loop; i++ )
384
            for( j = 0; j < div_loop; j++ )
385
                for( k = 0; k < bit_time; k++ )
386
                    continue;
387
    }
388
}
389
 
390
//-------------------------------------------------------------------------
391
 
392
static bool
393
tx3904_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
394
{
395
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
396
    cyg_uint16 cr = 0;
397
    cyg_uint16 icr = 0;
398
    cyg_uint16 baud_divisor = select_baud[new_config->baud];
399
 
400
    if (baud_divisor == 0)
401
        return false;  // Invalid baud rate selected
402
 
403
    // set up other config values:
404
 
405
    cr |= select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
406
    cr |= select_stop_bits[new_config->stop];
407
    cr |= select_parity[new_config->parity];
408
 
409
    // Source transfer clock from BRG
410
    cr |= LCR_BRG;
411
 
412
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE    
413
    // Enable RX interrupts only at present
414
#ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
415
    if ((chan->out_cbuf.len != 0) || (chan == &tx3904_serial_channel0)) {
416
#else
417
    if (chan->out_cbuf.len != 0) {
418
#endif
419
        icr |= ICR_RXE;
420
    }
421
#endif
422
 
423
    // Avoid any interrupts while we are fiddling with the line parameters.
424
    cyg_drv_interrupt_mask(tx3904_chan->int_num);
425
 
426
 
427
    // In theory we should wait here for the transmitter to drain the
428
    // FIFO so we dont change the line parameters with characters
429
    // unsent. Unfortunately the TX39 serial devices do not allow us
430
    // to discover when the FIFO is empty.
431
 
432
    delay_char_time(tx3904_chan, 8);
433
 
434
    // Disable device entirely.
435
//    HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_CR, 0);
436
//    HAL_WRITE_UINT8(tx3904_chan->base+SERIAL_ICR, 0);
437
 
438
    // Reset the FIFOs
439
 
440
    HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_FCR, 7);
441
    HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_FCR, 0);
442
 
443
    // Set up baud rate
444
 
445
    HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_BRG, baud_divisor );
446
 
447
    // Write CR into hardware
448
    HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_CR, cr);
449
 
450
    // Write ICR into hardware
451
    HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_ICR, icr);
452
 
453
    // Re-enable interrupts.
454
    cyg_drv_interrupt_unmask(tx3904_chan->int_num);
455
 
456
    // Save current baud rate
457
    tx3904_chan->cur_baud = new_config->baud;
458
 
459
    if (new_config != &chan->config) {
460
        chan->config = *new_config;
461
    }
462
    return true;
463
}
464
 
465
//-------------------------------------------------------------------------
466
// Function to initialize the device.  Called at bootstrap time.
467
 
468
bool tx3904_serial_init(struct cyg_devtab_entry *tab)
469
{
470
    serial_channel *chan = (serial_channel *)tab->priv;
471
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
472
 
473
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
474
 
475
    tx3904_chan->cur_baud = CYGNUM_SERIAL_BAUD_38400;
476
 
477
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE    
478
    if (chan->out_cbuf.len != 0) {
479
        // Install and enable the interrupt
480
        cyg_drv_interrupt_create(tx3904_chan->int_num,
481
                                 4,                      // Priority
482
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
483
                                 (cyg_ISR_t *)tx3904_serial_ISR,
484
                                 tx3904_serial_DSR,
485
                                 &tx3904_chan->interrupt_handle,
486
                                 &tx3904_chan->interrupt);
487
        cyg_drv_interrupt_attach(tx3904_chan->interrupt_handle);
488
        cyg_drv_interrupt_unmask(tx3904_chan->int_num);
489
    }
490
#endif
491
 
492
    tx3904_serial_config_port(chan, &chan->config, true);
493
 
494
    return true;
495
}
496
 
497
//-------------------------------------------------------------------------
498
// This routine is called when the device is "looked" up (i.e. attached)
499
 
500
static Cyg_ErrNo
501
tx3904_serial_lookup(struct cyg_devtab_entry **tab,
502
                  struct cyg_devtab_entry *sub_tab,
503
                  const char *name)
504
{
505
    serial_channel *chan = (serial_channel *)(*tab)->priv;
506
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
507
    return ENOERR;
508
}
509
 
510
//-------------------------------------------------------------------------
511
// Return 'true' if character is sent to device
512
 
513
bool
514
tx3904_serial_putc(serial_channel *chan, unsigned char c)
515
{
516
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
517
    cyg_uint16 isr;
518
 
519
    HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
520
 
521
    if( isr & ISR_TXRDY )
522
    {
523
        HAL_WRITE_UINT8( tx3904_chan->base+SERIAL_TXB, c );
524
 
525
        isr &= ~ISR_TXRDY;
526
 
527
        HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
528
 
529
        return true;
530
    }
531
    else return false;
532
}
533
 
534
//-------------------------------------------------------------------------
535
 
536
unsigned char
537
tx3904_serial_getc(serial_channel *chan)
538
{
539
    unsigned char c;
540
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
541
    cyg_uint16 isr;
542
 
543
    do
544
    {
545
        HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
546
 
547
        // Eliminate any RX errors
548
        if( isr & ISR_ERROR )
549
        {
550
            cyg_uint16 sr = 0;
551
 
552
            isr &= ISR_ERROR;
553
 
554
//            HAL_READ_UINT16( tx3904_chan->base+SERIAL_SR, sr );
555
 
556
            HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_SR, sr );
557
            HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
558
        }
559
 
560
    } while( (isr & ISR_RXRDY) != ISR_RXRDY );
561
 
562
    HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, c );
563
 
564
    isr &= ~ISR_RXRDY;
565
 
566
    HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
567
 
568
    return c;
569
}
570
 
571
//-------------------------------------------------------------------------
572
 
573
static Cyg_ErrNo
574
tx3904_serial_set_config(serial_channel *chan, cyg_uint32 key,
575
                         const void *xbuf, cyg_uint32 *len)
576
{
577
    switch (key) {
578
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
579
      {
580
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
581
        if ( *len < sizeof(cyg_serial_info_t) ) {
582
            return -EINVAL;
583
        }
584
        *len = sizeof(cyg_serial_info_t);
585
        if ( true != tx3904_serial_config_port(chan, config, false) )
586
            return -EINVAL;
587
      }
588
      break;
589
    default:
590
        return -EINVAL;
591
    }
592
    return ENOERR;
593
}
594
 
595
//-------------------------------------------------------------------------
596
// Enable the transmitter on the device
597
 
598
static void
599
tx3904_serial_start_xmit(serial_channel *chan)
600
{
601
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE    
602
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
603
    cyg_uint16 icr;
604
 
605
    HAL_READ_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
606
 
607
    icr |= ICR_TXE;
608
 
609
    HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
610
#endif    
611
}
612
 
613
//-------------------------------------------------------------------------
614
// Disable the transmitter on the device
615
 
616
static void
617
tx3904_serial_stop_xmit(serial_channel *chan)
618
{
619
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE    
620
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
621
    cyg_uint16 icr;
622
 
623
    HAL_READ_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
624
 
625
    icr &= ~ICR_TXE;
626
 
627
    HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
628
#endif    
629
}
630
 
631
//-------------------------------------------------------------------------
632
// Serial I/O - low level interrupt handlers (ISR)
633
 
634
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
635
 
636
static cyg_uint32
637
tx3904_serial_ISR(cyg_vector_t vector, cyg_addrword_t data, cyg_addrword_t *regs)
638
{
639
    serial_channel *chan = (serial_channel *)data;
640
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
641
    cyg_uint8 isr;
642
    cyg_uint32 result = 0;
643
 
644
    cyg_drv_interrupt_mask(tx3904_chan->int_num);
645
    cyg_drv_interrupt_acknowledge(tx3904_chan->int_num);
646
 
647
    HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
648
 
649
    // Eliminate any RX errors
650
    if( isr & ISR_ERROR )
651
    {
652
        cyg_uint16 sr = 0;
653
 
654
        isr &= ~ISR_ERROR;
655
 
656
        HAL_READ_UINT16( tx3904_chan->base+SERIAL_SR, sr );
657
 
658
        HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_SR, 0 );
659
    }
660
 
661
    // Check for a TX interrupt and set the flag if so.
662
    if( isr & ISR_TXRDY )
663
    {
664
        isr &= ~ISR_TXRDY;
665
 
666
        tx3904_chan->output_ready = true;
667
 
668
        result |= CYG_ISR_CALL_DSR;  // Cause DSR to be run
669
    }
670
 
671
 
672
    // Check here for an RX interrupt and fetch the character. If it
673
    // is a ^C then call into GDB stub to handle it.
674
 
675
    if( isr & ISR_RXRDY )
676
    {
677
        cyg_uint8 rxb;
678
        HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, rxb );
679
 
680
        isr &= ~ISR_RXRDY;
681
 
682
        if( cyg_hal_is_break( &rxb , 1 ) )
683
            cyg_hal_user_break( regs );
684
        else
685
        {
686
            tx3904_chan->input_char = rxb;
687
            tx3904_chan->input_char_valid = true;
688
            result |= CYG_ISR_CALL_DSR;  // Cause DSR to be run
689
        }
690
 
691
    }
692
 
693
    HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
694
 
695
    return result;
696
}
697
 
698
 
699
#endif
700
 
701
//-------------------------------------------------------------------------
702
// Serial I/O - high level interrupt handler (DSR)
703
 
704
#ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
705
 
706
static void
707
tx3904_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
708
{
709
    serial_channel *chan = (serial_channel *)data;
710
    tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
711
    cyg_uint8 isr;
712
 
713
    HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
714
 
715
    if( tx3904_chan->input_char_valid )
716
    {
717
        (chan->callbacks->rcv_char)(chan, tx3904_chan->input_char);
718
 
719
        tx3904_chan->input_char_valid = false;
720
 
721
#if 0        
722
        // And while we are here, pull any further characters out of the
723
        // FIFO. This should help to reduce the interrupt rate.
724
 
725
        HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
726
 
727
        while( isr & ISR_RXRDY )
728
        {
729
            cyg_uint8 rxb;
730
            HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, rxb );
731
 
732
            (chan->callbacks->rcv_char)(chan, rxb);
733
 
734
            isr &= ~ISR_RXRDY;
735
 
736
            HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
737
            HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
738
        }
739
#endif
740
 
741
    }
742
 
743
    if( tx3904_chan->output_ready )
744
    {
745
        (chan->callbacks->xmt_char)(chan);
746
 
747
        tx3904_chan->output_ready = false;
748
    }
749
 
750
    cyg_drv_interrupt_unmask(tx3904_chan->int_num);
751
}
752
 
753
#endif
754
#endif // CYGPKG_IO_SERIAL_TX39_JMR3904
755
 
756
//-------------------------------------------------------------------------
757
// EOF tx3904_serial.c

powered by: WebSVN 2.1.0

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