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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [devs/] [serial/] [freescale/] [uart/] [drv/] [current/] [src/] [ser_freescale_uart.c] - Blame information for rev 810

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

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      ser_freescale_uart.c
4
//
5
//      Freescale UART 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) 2011 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):   Ilija Kocho <ilijak@siva.com.mk>
43
// Contributors:
44
// Date:        2011-02-10
45
// Purpose:     Freescale UART Serial I/O module (interrupt driven version)
46
// Description:
47
//
48
//
49
//####DESCRIPTIONEND####
50
//==========================================================================
51
 
52
#include <pkgconf/io_serial.h>
53
#include <pkgconf/io.h>
54
 
55
#include <cyg/io/io.h>
56
#include <cyg/hal/hal_intr.h>
57
#include <cyg/hal/hal_arbiter.h>
58
#include <cyg/hal/hal_io.h>
59
#include <cyg/io/devtab.h>
60
#include <cyg/infra/diag.h>
61
#include <cyg/io/serial.h>
62
#include <cyg/io/ser_freescale_uart.h>
63
 
64
// Only build this driver for if Freescale UART is needed.
65
#ifdef CYGPKG_IO_SERIAL_FREESCALE_UART
66
 
67
typedef struct uart_pins_s {
68
    cyg_uint32 rx;
69
    cyg_uint32 tx;
70
    cyg_uint32 rts;
71
    cyg_uint32 cts;
72
} uart_pins_t;
73
 
74
 
75
typedef struct uart_serial_info {
76
    CYG_ADDRWORD   uart_base;          // Base address of the uart port
77
    CYG_WORD       interrupt_num;      // NVIC interrupt vector
78
    cyg_priority_t interrupt_priority; // NVIC interupt priority
79
    const uart_pins_t *pins_p;
80
    cyg_bool tx_active;
81
    cyg_interrupt  interrupt_obj;      // Interrupt object
82
    cyg_handle_t   interrupt_handle;   // Interrupt handle
83
} uart_serial_info;
84
 
85
static bool uart_serial_init(struct cyg_devtab_entry * tab);
86
static bool uart_serial_putc(serial_channel * chan, unsigned char c);
87
static Cyg_ErrNo uart_serial_lookup(struct cyg_devtab_entry ** tab,
88
                                    struct cyg_devtab_entry * sub_tab,
89
                                    const char * name);
90
static unsigned char uart_serial_getc(serial_channel *chan);
91
static Cyg_ErrNo uart_serial_set_config(serial_channel *chan, cyg_uint32 key,
92
                                        const void *xbuf, cyg_uint32 *len);
93
static void uart_serial_start_xmit(serial_channel *chan);
94
static void uart_serial_stop_xmit(serial_channel *chan);
95
 
96
// Interrupt servers
97
static cyg_uint32 uart_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
98
static void       uart_serial_DSR(cyg_vector_t vector, cyg_ucount32 count,
99
                                  cyg_addrword_t data);
100
 
101
static SERIAL_FUNS(uart_serial_funs,
102
                   uart_serial_putc,
103
                   uart_serial_getc,
104
                   uart_serial_set_config,
105
                   uart_serial_start_xmit,
106
                   uart_serial_stop_xmit);
107
 
108
// Available baud rates
109
static cyg_int32 select_baud[] = {
110
    0,      // Unused
111
    50,     // 50
112
    75,     // 75
113
    110,    // 110
114
    0,      // 134.5
115
    150,    // 150
116
    200,    // 200
117
    300,    // 300
118
    600,    // 600
119
    1200,   // 1200
120
    1800,   // 1800
121
    2400,   // 2400
122
    3600,   // 3600
123
    4800,   // 4800
124
    7200,   // 7200
125
    9600,   // 9600
126
    14400,  // 14400
127
    19200,  // 19200
128
    38400,  // 38400
129
    57600,  // 57600
130
    115200, // 115200
131
    230400, // 230400
132
};
133
 
134
#include <cyg/io/ser_freescale_uart_chan.inl>
135
 
136
//----------------------------------------------------------------------------
137
// Internal function to actually configure the hardware to desired
138
// baud rate, etc.
139
//----------------------------------------------------------------------------
140
static bool
141
uart_serial_config_port(serial_channel * chan, cyg_serial_info_t * new_config,
142
                        bool init)
143
{
144
    cyg_uint32 regval;
145
    uart_serial_info * uart_chan = (uart_serial_info *)(chan->dev_priv);
146
    cyg_addrword_t uart_base = uart_chan->uart_base;
147
    cyg_uint32 baud_rate = select_baud[new_config->baud];
148
 
149
    if(!baud_rate) return false;    // Invalid baud rate selected
150
 
151
    // Configure PORT pins
152
    CYGHWR_IO_FREESCALE_UART_PIN(uart_chan->pins_p->rx);
153
    CYGHWR_IO_FREESCALE_UART_PIN(uart_chan->pins_p->tx);
154
 
155
    CYGHWR_IO_FREESCALE_UART_BAUD_SET(uart_base, baud_rate);
156
 
157
    if(new_config->word_length != 8)
158
        return false;
159
 
160
    switch(new_config->parity) {
161
    case CYGNUM_SERIAL_PARITY_NONE:
162
        regval = 0;
163
        break;
164
    case CYGNUM_SERIAL_PARITY_EVEN:
165
        regval = CYGHWR_DEV_FREESCALE_UART_C1_PE;
166
        break;
167
    case CYGNUM_SERIAL_PARITY_ODD:
168
        regval = CYGHWR_DEV_FREESCALE_UART_C1_PE |
169
                 CYGHWR_DEV_FREESCALE_UART_C1_PT;
170
        break;
171
    default: return false;
172
    }
173
 
174
    HAL_WRITE_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_C1, regval);
175
 
176
    if(init) { // Enable the receiver interrupt
177
        regval = CYGHWR_DEV_FREESCALE_UART_C2_RIE;
178
    } else {    // Restore the old interrupt state
179
        HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_C2, regval);
180
    }
181
 
182
    // Enable the device
183
    regval |= CYGHWR_DEV_FREESCALE_UART_C2_TE |
184
              CYGHWR_DEV_FREESCALE_UART_C2_RE;
185
 
186
    HAL_WRITE_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_C2, regval);
187
 
188
    uart_chan->tx_active = false;
189
 
190
    if(new_config != &chan->config)
191
        chan->config = *new_config;
192
 
193
    return true;
194
}
195
 
196
//--------------------------------------------------------------
197
// Function to initialize the device.  Called at bootstrap time.
198
//--------------------------------------------------------------
199
static bool
200
uart_serial_init(struct cyg_devtab_entry * tab)
201
{
202
    serial_channel * chan = (serial_channel *)tab->priv;
203
    uart_serial_info * uart_chan = (uart_serial_info *)chan->dev_priv;
204
 
205
    // Really only required for interrupt driven devices
206
    (chan->callbacks->serial_init)(chan);
207
    if(chan->out_cbuf.len != 0) {
208
        cyg_drv_interrupt_create(uart_chan->interrupt_num,
209
                                 uart_chan->interrupt_priority,
210
                                 // Data item passed to interrupt handler
211
                                 (cyg_addrword_t)chan,
212
                                 uart_serial_ISR,
213
                                 uart_serial_DSR,
214
                                 &uart_chan->interrupt_handle,
215
                                 &uart_chan->interrupt_obj);
216
 
217
        cyg_drv_interrupt_attach(uart_chan->interrupt_handle);
218
        cyg_drv_interrupt_unmask(uart_chan->interrupt_num);
219
    }
220
    return uart_serial_config_port(chan, &chan->config, true);
221
}
222
 
223
//----------------------------------------------------------------------
224
// This routine is called when the device is "looked" up (i.e. attached)
225
//----------------------------------------------------------------------
226
static Cyg_ErrNo
227
uart_serial_lookup(struct cyg_devtab_entry ** tab,
228
                   struct cyg_devtab_entry * sub_tab, const char * name)
229
{
230
    serial_channel * chan = (serial_channel *)(*tab)->priv;
231
    // Really only required for interrupt driven devices
232
    (chan->callbacks->serial_init)(chan);
233
 
234
    return ENOERR;
235
}
236
 
237
//-----------------------------------------------------------------
238
// Send a character to Tx
239
//-----------------------------------------------------------------
240
static bool
241
uart_serial_putc(serial_channel * chan, unsigned char ch_out)
242
{
243
    uart_serial_info * uart_chan = (uart_serial_info *)chan->dev_priv;
244
    cyg_addrword_t uart_base = uart_chan->uart_base;
245
    cyg_uint32 uart_sr;
246
 
247
    HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_S1, uart_sr);
248
    if(uart_sr & CYGHWR_DEV_FREESCALE_UART_S1_TDRE) {
249
        HAL_WRITE_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_D, ch_out);
250
        return true;
251
    } else {
252
        return false;
253
    }
254
}
255
 
256
 
257
//---------------------------------------------------------------------
258
// Fetch a character Rx (for polled operation only)
259
//---------------------------------------------------------------------
260
static unsigned char
261
uart_serial_getc(serial_channel * chan)
262
{
263
    cyg_uint8 ch_in;
264
    uart_serial_info * uart_chan = (uart_serial_info *)chan->dev_priv;
265
    cyg_addrword_t uart_base = uart_chan->uart_base;
266
 
267
    cyg_uint32 uart_sr;
268
 
269
    do {
270
        HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_S1, uart_sr);
271
    } while(uart_sr & CYGHWR_DEV_FREESCALE_UART_S1_RDRF);
272
 
273
    HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_D, ch_in);
274
 
275
    return ch_in;
276
}
277
 
278
 
279
//---------------------------------------------------
280
// Set up the device characteristics; baud rate, etc.
281
//---------------------------------------------------
282
static bool
283
uart_serial_set_config(serial_channel * chan, cyg_uint32 key,
284
                       const void *xbuf, cyg_uint32 * len)
285
{
286
    switch(key) {
287
    case CYG_IO_SET_CONFIG_SERIAL_INFO: {
288
            cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
289
            if(*len < sizeof(cyg_serial_info_t)) {
290
                return -EINVAL;
291
            }
292
            *len = sizeof(cyg_serial_info_t);
293
            if(true != uart_serial_config_port(chan, config, false))
294
            return -EINVAL;
295
        }
296
        break;
297
    default:
298
        return -EINVAL;
299
    }
300
    return ENOERR;
301
}
302
 
303
//-------------------------------------
304
// Enable the transmitter on the device
305
//-------------------------------------
306
static void uart_serial_start_xmit(serial_channel * chan)
307
{
308
    uart_serial_info * uart_chan = (uart_serial_info *)chan->dev_priv;
309
    cyg_addrword_t uart_base = uart_chan->uart_base;
310
    cyg_uint32 uart_cr12;
311
 
312
    if(!uart_chan->tx_active) {
313
        uart_chan->tx_active = true;
314
        HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_C2, uart_cr12);
315
        uart_cr12 |= CYGHWR_DEV_FREESCALE_UART_C2_TIE;
316
        HAL_WRITE_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_C2, uart_cr12);
317
    }
318
}
319
 
320
//--------------------------------------
321
// Disable the transmitter on the device
322
//--------------------------------------
323
static void uart_serial_stop_xmit(serial_channel * chan)
324
{
325
    uart_serial_info * uart_chan = (uart_serial_info *)chan->dev_priv;
326
 
327
    cyg_addrword_t uart_base = uart_chan->uart_base;
328
    cyg_uint32 uart_cr12;
329
 
330
    if(uart_chan->tx_active) {
331
        uart_chan->tx_active = false;
332
        HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_C2, uart_cr12);
333
        uart_cr12 &= ~CYGHWR_DEV_FREESCALE_UART_C2_TIE;
334
        HAL_WRITE_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_C2, uart_cr12);
335
    }
336
}
337
 
338
//-----------------------------------------
339
// The low level interrupt handler
340
//-----------------------------------------
341
static
342
cyg_uint32 uart_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
343
{
344
    serial_channel * chan = (serial_channel *)data;
345
    uart_serial_info * uart_chan = (uart_serial_info *)chan->dev_priv;
346
 
347
    cyg_drv_interrupt_mask(uart_chan->interrupt_num);
348
    cyg_drv_interrupt_acknowledge(uart_chan->interrupt_num);
349
 
350
    return CYG_ISR_CALL_DSR; // cause the DSR to run
351
}
352
 
353
 
354
//------------------------------------------
355
// The high level interrupt handler
356
//------------------------------------------
357
 
358
#define CYGHWR_DEV_FREESCALE_UART_S1_ERRORS \
359
                                 (CYGHWR_DEV_FREESCALE_UART_S1_OR | \
360
                                  CYGHWR_DEV_FREESCALE_UART_S1_NF | \
361
                                  CYGHWR_DEV_FREESCALE_UART_S1_FE | \
362
                                  CYGHWR_DEV_FREESCALE_UART_S1_PF)
363
 
364
static void
365
uart_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
366
{
367
    serial_channel * chan = (serial_channel *)data;
368
    uart_serial_info * uart_chan = (uart_serial_info *)chan->dev_priv;
369
    cyg_addrword_t uart_base = uart_chan->uart_base;
370
    volatile cyg_uint32 uart_sr;
371
    cyg_uint8 uart_dr;
372
 
373
    HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_S1, uart_sr);
374
    if(uart_sr & (CYGHWR_DEV_FREESCALE_UART_S1_RDRF |
375
                  CYGHWR_DEV_FREESCALE_UART_S1_ERRORS)) {
376
        // Receiver full or errors
377
        HAL_READ_UINT8(uart_base + CYGHWR_DEV_FREESCALE_UART_D, uart_dr);
378
        if(uart_sr & CYGHWR_DEV_FREESCALE_UART_S1_ERRORS) {
379
            // Check for receive error
380
        } else { // No errors, get the character
381
            (chan->callbacks->rcv_char)(chan, (cyg_uint8)uart_dr);
382
        }
383
    }
384
 
385
    if(uart_chan->tx_active && (uart_sr & CYGHWR_DEV_FREESCALE_UART_S1_TDRE)){
386
        //Transmitter empty
387
        (chan->callbacks->xmt_char)(chan);
388
    }
389
 
390
    cyg_drv_interrupt_unmask(uart_chan->interrupt_num);
391
}
392
 
393
#endif // CYGPKG_IO_SERIAL_FREESCALE_UART
394
// EOF ser_freescale_uart.c

powered by: WebSVN 2.1.0

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