]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/serial/mcf52xx/mcf5272/v2_0/src/ser_mcf5272_uart.c
Initial revision
[karo-tx-redboot.git] / packages / devs / serial / mcf52xx / mcf5272 / v2_0 / src / ser_mcf5272_uart.c
1 //==========================================================================
2 //
3 //      devs/serial/MCF52xx/MCF5282
4 //
5 //      MCF5272 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) 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
42 #include <cyg/io/io.h>
43 #include <cyg/io/devtab.h>
44 #include <cyg/io/serial.h>
45 #include <cyg/infra/diag.h>
46 #include <cyg/hal/hal_intr.h>
47 #include <cyg/hal/hal_memmap.h>
48 #include <cyg/infra/cyg_type.h>
49 #include <cyg/hal/hal_arch.h>
50 #include <cyg/hal/drv_api.h>
51 #include <pkgconf/hal.h>
52 #include <pkgconf/system.h>
53 #include <pkgconf/io_serial.h>
54 #include <pkgconf/io.h>
55 #include <pkgconf/io_serial_mcf5272_uart.h>
56 #include <cyg/io/ser_mcf5272_uart.h>
57
58
59 /* The UART priority level */
60 #define MCF5272_UART_PRIORITY_LEVEL 2
61
62
63 /* Autobaud states */
64 typedef enum autobaud_states_t
65 {
66     AB_IDLE = 0,  /* Normal state. Autobaud process hasn't been initiated yet. */
67     AB_BEGIN_BREAK, /* Detected a start of the break */
68     AB_BEGIN,       /* Detected the end of the break and has set up the autobaud.*/
69
70 }autobaud_states_t;
71
72 #define FIELD_OFFSET(type,field) (cyg_uint32)(&(((type*)0)->field))
73
74 typedef struct MCF5272_uart_info_t
75 {
76
77     volatile mcf5272_sim_uart_t*    base;                       // Base address of the UART registers
78     uint32                          uart_vector;                // UART interrupt vector number
79
80     cyg_interrupt                   serial_interrupt;           // Interrupt context
81     cyg_handle_t                    serial_interrupt_handle;    // Interrupt handle
82
83     volatile uint8                  imr_mirror;                 // Interrupt mask register mirror
84
85     cyg_serial_info_t               config;                     // The channel configuration
86
87     autobaud_states_t               autobaud_state;             // The autobaud state
88
89
90 } MCF5272_uart_info_t;
91
92 /* Function prtoftyps for the MCF5272 UART ISR and DSR. */
93 static cyg_uint32 MCF5272_uart_ISR(cyg_vector_t vector, cyg_addrword_t data);
94 static void       MCF5272_uart_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
95
96
97 /* Function prototypes for the serial functions. */
98 static bool MCF5272_uart_init(struct cyg_devtab_entry * tab);
99 static Cyg_ErrNo MCF5272_uart_lookup(struct cyg_devtab_entry **tab,
100                   struct cyg_devtab_entry *sub_tab,
101                   const char *name);
102 static bool MCF5272_uart_putc(serial_channel *chan, unsigned char c);
103 static unsigned char MCF5272_uart_getc(serial_channel *chan);
104 Cyg_ErrNo MCF5272_uart_set_config(serial_channel *chan, cyg_uint32 key,
105                             const void *xbuf, cyg_uint32 *len);
106 static void MCF5272_uart_start_xmit(serial_channel *chan);
107 static void MCF5272_uart_stop_xmit(serial_channel * chan);
108
109
110 /* Declare the serial functions that are called by the common serial driver layer. */
111 static SERIAL_FUNS
112 (
113     MCF5272_uart_funs,
114     MCF5272_uart_putc,
115     MCF5272_uart_getc,
116     MCF5272_uart_set_config,
117     MCF5272_uart_start_xmit,
118     MCF5272_uart_stop_xmit
119 );
120
121
122 /* Definition for channel 0 UART configuration. */
123 /************************************************/
124 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL0
125
126 /* Data structure contains
127    channel informtion.
128  */
129 static MCF5272_uart_info_t MCF5272_uart_channel_info_0;
130
131 /* If the channel buffer size is zero, do not include interrupt UART processing */
132 #if CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BUFSIZE > 0
133
134 /*      Allocated receive and transmit buffer.   The size of the buffer  is */
135 /* configured by the configtool.                                            */
136
137 static unsigned char MCF5272_uart_out_buf0[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BUFSIZE];
138 static unsigned char MCF5272_uart_in_buf0[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BUFSIZE];
139
140 /*      Channel function table.   We register  the UART  functions here  so */
141 /* that uppper serial drivers can call the serial driver's routines.        */
142
143 static SERIAL_CHANNEL_USING_INTERRUPTS(
144     MCF5272_uart_channel_0,
145     MCF5272_uart_funs,
146     MCF5272_uart_channel_info_0,
147     CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BAUD),
148     CYG_SERIAL_STOP_DEFAULT,
149     CYG_SERIAL_PARITY_DEFAULT,
150     CYG_SERIAL_WORD_LENGTH_DEFAULT,
151     CYG_SERIAL_FLAGS_DEFAULT,
152     MCF5272_uart_out_buf0, sizeof(MCF5272_uart_out_buf0),
153     MCF5272_uart_in_buf0, sizeof(MCF5272_uart_in_buf0)
154 );
155 #else
156 /* Don't use interrupt processing for the UART. */
157 static SERIAL_CHANNEL(
158     MCF5272_uart_channel_0,
159     MCF5272_uart_funs,
160     MCF5272_uart_channel_info_0,
161     CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BAUD),
162     CYG_SERIAL_STOP_DEFAULT,
163     CYG_SERIAL_PARITY_DEFAULT,
164     CYG_SERIAL_WORD_LENGTH_DEFAULT,
165     CYG_SERIAL_FLAGS_DEFAULT
166 );
167 #endif
168
169 DEVTAB_ENTRY(
170     MCF5272_uart_io0,
171     CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL0_NAME,
172     0,                       // Does not depend on a lower level interface
173     &cyg_io_serial_devio,    // The table of I/O functions.
174     MCF5272_uart_init,       // UART initialization function.
175     MCF5272_uart_lookup,     // The UART lookup function. This function typically sets
176                              // up the device for actual use, turing on interrupts, configuring the port, etc.
177     &MCF5272_uart_channel_0
178 );
179 #endif //  CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0
180
181 /* Definition for channel 1 UART configuration. */
182 /************************************************/
183
184 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL1
185
186
187 /* Data structure contains
188    channel informtion.
189  */
190 static MCF5272_uart_info_t MCF5272_uart_channel_info_1;
191
192 /* If the channel buffer size is zero, do not include interrupt UART processing */
193 #if CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BUFSIZE > 0
194
195 /*      Allocated receive and transmit buffer.   The size of the buffer  is */
196 /* configured by the configtool.                                            */
197
198 static unsigned char MCF5272_uart_out_buf1[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BUFSIZE];
199 static unsigned char MCF5272_uart_in_buf1[CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BUFSIZE];
200
201 /*      Channel function table.   We register  the UART  functions here  so */
202 /* that uppper serial drivers can call the serial driver's routines.        */
203
204 static SERIAL_CHANNEL_USING_INTERRUPTS(
205     MCF5272_uart_channel_1,
206     MCF5272_uart_funs,
207     MCF5272_uart_channel_info_1,
208     CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1_BAUD),
209     CYG_SERIAL_STOP_DEFAULT,
210     CYG_SERIAL_PARITY_DEFAULT,
211     CYG_SERIAL_WORD_LENGTH_DEFAULT,
212     CYG_SERIAL_FLAGS_DEFAULT,
213     MCF5272_uart_out_buf1, sizeof(MCF5272_uart_out_buf1),
214     MCF5272_uart_in_buf1, sizeof(MCF5272_uart_in_buf1)
215 );
216
217 #else
218 static SERIAL_CHANNEL(MCF5272_uart_channel_1,
219                       MCF5272_uart_funs,
220                       MCF5272_uart_channel_info_1,
221                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL0_BAUD),
222                       CYG_SERIAL_STOP_DEFAULT,
223                       CYG_SERIAL_PARITY_DEFAULT,
224                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
225                       CYG_SERIAL_FLAGS_DEFAULT
226     );
227 #endif
228 DEVTAB_ENTRY(
229     MCF5272_uart_io1,
230     CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL1_NAME,
231     0,                     // Does not depend on a lower level interface
232     &cyg_io_serial_devio,  // The table of I/O functions.
233     MCF5272_uart_init,     // UART initialization function.
234     MCF5272_uart_lookup,   // The UART lookup function. This function typically sets
235                            // up the device for actual use, turing on interrupts, configuring the port, etc.
236     &MCF5272_uart_channel_1
237 );
238 #endif //  CYGNUM_IO_SERIAL_MCF5272_UART_CHANNEL1
239
240
241
242 /* Definition of macros that access the UART's SIM registers */
243 /* Read from a register */
244
245 #define MCF5272_UART_WRITE(_addr_,_value_) \
246    *((volatile CYG_BYTE*)&(_addr_)) = (CYG_BYTE)(_value_)
247 /* Write to a register */
248 #define MCF5272_UART_READ(_addr_) \
249    *(volatile CYG_BYTE*)&(_addr_)
250
251
252 /* Function Prototypes */
253 /* =================== */
254 /* Internal function to actually configure the hardware to desired baud rate, etc. */
255 static bool MCF5272_uart_config_port(serial_channel*, cyg_serial_info_t*);
256 static void MCF5272_uart_start_xmit(serial_channel*);
257
258
259 /* Baudrate conversion table. */
260 static unsigned long baud_rates_table[]=
261 {
262     0,
263     50,     // CYGNUM_SERIAL_BAUD_50 = 1
264     75,     // CYGNUM_SERIAL_BAUD_75
265     110,    // CYGNUM_SERIAL_BAUD_110
266     134,    // CYGNUM_SERIAL_BAUD_134_5
267     150,    // CYGNUM_SERIAL_BAUD_150
268     200,    // CYGNUM_SERIAL_BAUD_200
269     300,    // CYGNUM_SERIAL_BAUD_300
270     600,    // CYGNUM_SERIAL_BAUD_600
271     1200,   // CYGNUM_SERIAL_BAUD_1200
272     1800,   // CYGNUM_SERIAL_BAUD_1800
273     2400,   // CYGNUM_SERIAL_BAUD_2400
274     3600,   // CYGNUM_SERIAL_BAUD_3600
275     4800,   // CYGNUM_SERIAL_BAUD_4800
276     7200,   // CYGNUM_SERIAL_BAUD_7200
277     9600,   // CYGNUM_SERIAL_BAUD_9600
278     14400,  // CYGNUM_SERIAL_BAUD_14400
279     19200,  // CYGNUM_SERIAL_BAUD_19200
280     38400,  // CYGNUM_SERIAL_BAUD_38400
281     57600,  // CYGNUM_SERIAL_BAUD_57600
282     115200, // CYGNUM_SERIAL_BAUD_115200
283     230400  // CYGNUM_SERIAL_BAUD_230400
284 };
285
286 /*      The table contains  divers  to  divide  the  clock  to  configre  a */
287 /* approppriate for the UART.                                               */
288
289 static unsigned long dividers_table[]=
290 {
291     0,
292     46080,   // 50
293     30720,   // 75
294     20945,   // 110
295     17130,   // 134_5
296     15360,   // 150
297     11520,   // 200
298     7680,    // 300
299     3840,    // 600
300     1920,    // 1200
301     1280,    // 1800
302     960,     // 2400
303     640,     // 3600
304     480,     // 4800
305     320,     // 7200
306     240,     // 9600
307     160,     // 14400
308     120,     // 19200
309     60,      // 38400
310     40,      // 57600
311     20,      // 115200
312     10       // 230400
313 };
314
315 /*******************************************************************************
316  MCF5272_uart_init() - This routine is called during bootstrap to set up the
317                        UART driver.
318
319  INPUT:
320     Pointer to the the device table.
321
322  RETURN:
323     Returns true if the initialization is successful. Otherwise, it retuns false
324 */
325 static bool MCF5272_uart_init(struct cyg_devtab_entry * tab)
326 {
327     serial_channel *chan = (serial_channel *)tab->priv;
328     MCF5272_uart_info_t *MCF5272_uart_chan = (MCF5272_uart_info_t *)chan->dev_priv;
329
330     #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL0
331
332     /*   Instantiation of the  UART channel  0 data  strucutre.  This  data */
333     /* structure contains channel information.                              */
334
335     if (strcmp(tab->name, CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL0_NAME) == 0)
336     {
337
338         /*   Initiliaze the UART information data to all zeros.             */
339
340         memset(MCF5272_uart_chan, sizeof(MCF5272_uart_info_t), 0);
341
342         /*   Set the base  address of the  UART registers to  differentiate */
343         /* itself from the different regusters for the other UART port.     */
344
345         MCF5272_uart_chan->base = (mcf5272_sim_uart_t*)&MCF5272_SIM->uart[0];
346
347         /*   Set the UART interrupt vector number.                          */
348
349         MCF5272_uart_chan->uart_vector = CYGNUM_HAL_VECTOR_UART1;
350
351         /*   Set the autobaud state to idle.                                */
352
353         MCF5272_uart_chan->autobaud_state = AB_IDLE;
354
355         /* Initilize the UART 0 output pins */
356
357         MCF5272_SIM->gpio.pbcnt =  MCF5272_GPIO_PBCNT_URT0_EN |
358             ((MCF5272_SIM->gpio.pbcnt) & ~MCF5272_GPIO_PBCNT_URT0_MSK);
359     }
360     #endif
361
362     #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL1
363
364     /* Instantiation of the UART channel 1 data strucutre. This data structure contains
365        channel information.
366      */
367     if (strcmp(tab->name, CYGDAT_IO_SERIAL_MCF5272_UART_CHANNEL1_NAME) == 0)
368     {
369
370         /*   Initiliaze the UART information data to all zeros.             */
371
372         memset(MCF5272_uart_chan, sizeof(MCF5272_uart_info_t), 0);
373
374         /*   Set the base  address of the  UART registers to  differentiate */
375         /* itself from the different regusters for the other UART port.     */
376
377         MCF5272_uart_chan->base = (mcf5272_sim_uart_t*)&MCF5272_SIM->uart[1];
378
379          /*   Set the UART interrupt vector number.                          */
380
381         MCF5272_uart_chan->uart_vector = CYGNUM_HAL_VECTOR_UART2;
382
383         /*   Set the autobaud state to idle.                                */
384
385         MCF5272_uart_chan->autobaud_state = AB_IDLE;
386
387         /* Initilize the UART 1 output pins */
388
389         MCF5272_SIM->gpio.pdcnt =  MCF5272_GPIO_PDCNT_URT1_EN |
390             ((MCF5272_SIM->gpio.pdcnt) & ~MCF5272_GPIO_PDCNT_URT1_MSK);
391
392     }
393     #endif
394
395
396     if (chan->out_cbuf.len > 0) {
397
398         /*   If the the buffer is greater  than zero, then the driver  will */
399         /* use  interrupt  driven  I/O.   Hence,  the  driver  creates   an */
400         /* interrupt context for the UART device.                           */
401
402         cyg_drv_interrupt_create(MCF5272_uart_chan->uart_vector,
403                                  MCF5272_UART_PRIORITY_LEVEL,           // Priority - Level 2
404                                  (cyg_addrword_t)chan,                  //  Data item passed to interrupt handler
405                                  MCF5272_uart_ISR,
406                                  MCF5272_uart_DSR,
407                                  &MCF5272_uart_chan->serial_interrupt_handle,
408                                  &MCF5272_uart_chan->serial_interrupt);
409
410         cyg_drv_interrupt_attach(MCF5272_uart_chan->serial_interrupt_handle);
411
412         (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
413     }
414
415     // Configure Serial device.
416     return(MCF5272_uart_config_port(chan, &chan->config));
417 }
418
419 /******************************************************************************************************
420  MCF5272_uart_config_port() - Configure the UART port.
421
422  Internal function to actually configure the hardware to desired baud rate, etc.
423
424  INPUT:
425     chan        - The channel information
426     new_confg   - The port configuration which include the desired baud rate, etc.
427
428  RETURN:
429     Returns true if the port configuration is successful. Otherwise, it retuns false
430
431  */
432 static bool MCF5272_uart_config_port(serial_channel *chan,
433                                      cyg_serial_info_t *new_config)
434 {
435     MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
436     uint8 mode_reg = 0;
437     uint32 ubgs;
438     unsigned int baud_divisor;
439
440
441     /*   Get the  divisor  from  the  baudrate  table  which  will  use  to */
442     /* configure the port's baud rate.                                      */
443
444     baud_divisor = baud_rates_table[new_config->baud];
445
446     /*   If the divisor is zeor, we dont' configure the port.               */
447
448     if (baud_divisor == 0) return false;
449
450     /*   Save the configuration value for later use.                        */
451
452     port->config = *new_config;
453
454     /*   We first write the reset values into the device and then configure */
455     /* the device the we way we want to use it.                             */
456         
457         /* Reset Transmitter */
458
459     MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_TX);
460
461         /* Reset Receiver */
462         
463     MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_RX);
464
465         /* Reset Mode Register */
466         
467     MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_MR);
468
469     /* Translate the parity configuration to UART mode bits. */
470
471     switch(port->config.parity)
472     {
473     default:
474     case CYGNUM_SERIAL_PARITY_NONE:
475         mode_reg = 0 | MCF5272_UART_UMR1_PM_NONE;
476         break;
477     case CYGNUM_SERIAL_PARITY_EVEN:
478         mode_reg = 0 | MCF5272_UART_UMR1_PM_EVEN;
479         break;
480     case CYGNUM_SERIAL_PARITY_ODD:
481         mode_reg = 0 | MCF5272_UART_UMR1_PM_ODD;
482         break;
483     case CYGNUM_SERIAL_PARITY_MARK:
484         mode_reg = 0 | MCF5272_UART_UMR1_PM_FORCE_HI;
485         break;
486     case CYGNUM_SERIAL_PARITY_SPACE:
487         mode_reg = 0 | MCF5272_UART_UMR1_PM_FORCE_LO;
488         break;
489     }
490
491     /* Translate the number of bits per character configuration to UART mode bits. */
492
493     switch(port->config.word_length)
494     {
495
496     case CYGNUM_SERIAL_WORD_LENGTH_5:
497         mode_reg |= MCF5272_UART_UMR1_BC_5;
498         break;
499     case CYGNUM_SERIAL_WORD_LENGTH_6:
500         mode_reg |= MCF5272_UART_UMR1_BC_6;
501         break;
502     case CYGNUM_SERIAL_WORD_LENGTH_7:
503         mode_reg |= MCF5272_UART_UMR1_BC_7;
504         break;
505     default:
506     case CYGNUM_SERIAL_WORD_LENGTH_8:
507         mode_reg |= MCF5272_UART_UMR1_BC_8;
508         break;
509     }
510
511         /* Configure the parity and the bits per character */
512         
513     MCF5272_UART_WRITE(port->base->umr, mode_reg);
514
515     /* Translate the stop bit length to UART mode bits. */
516
517     switch(port->config.stop)
518     {
519     default:
520     case CYGNUM_SERIAL_STOP_1:
521         mode_reg = MCF5272_UART_UMR2_STOP_BITS_1;
522         break;
523     case CYGNUM_SERIAL_STOP_1_5:
524         mode_reg = MCF5272_UART_UMR2_STOP_BITS_15;
525         break;
526     case CYGNUM_SERIAL_STOP_2:
527         mode_reg = MCF5272_UART_UMR2_STOP_BITS_2;
528         break;
529     }
530
531         /* No echo or loopback */
532         
533     MCF5272_UART_WRITE(port->base->umr, 0 | MCF5272_UART_UMR2_CM_NORMAL | mode_reg);
534
535         /* Set Rx and Tx baud by timer */
536         
537     MCF5272_UART_WRITE(port->base->ucr, 0 | MCF5272_UART_UCSR_RCS(0xD) |
538                        MCF5272_UART_UCSR_TCS(0xD));
539
540         /* Mask all USART interrupts */
541         
542     MCF5272_UART_WRITE(port->base->uisr_uimr, 0);
543
544         /* Calculate baud settings */
545         
546     ubgs = (uint16)((CYGHWR_HAL_SYSTEM_CLOCK_MHZ*1000000)/
547                     (baud_divisor * 32));
548
549     /*   Program the baud settings to the device.                           */
550
551         MCF5272_UART_WRITE(port->base->udu, (uint8)((ubgs & 0xFF00) >> 8));
552         MCF5272_UART_WRITE(port->base->udl, (uint8)(ubgs & 0x00FF));
553
554         /* Enable receiver and transmitter */
555
556     MCF5272_UART_WRITE(port->base->ucr, 0 | MCF5272_UART_UCR_TXRXEN);
557
558     /* Enable both transmit and receive interrupt. */
559
560     port->imr_mirror = MCF5272_UART_UIMR_TXRDY | MCF5272_UART_UIMR_FFULL |
561                        MCF5272_UART_UIMR_DB;
562     MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
563
564     return true; /* Returns true to indicate a successful configuration */
565
566 }
567
568 /*******************************************************************************
569  MCF5272_uart_lookup() - This routine is called when the device is "looked" up
570                         (i.e. attached)
571
572  INPUT:
573     tab - pointer to a pointer of the device table
574     sub_tab - Pointer to the sub device table.
575     name - name of the device
576
577  RETURN:
578     always return ENOERR
579
580 */
581 static Cyg_ErrNo MCF5272_uart_lookup(struct cyg_devtab_entry **tab,
582                   struct cyg_devtab_entry *sub_tab,
583                   const char *name)
584 {
585     serial_channel *chan = (serial_channel *)(*tab)->priv;
586     (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
587     return ENOERR;
588 }
589
590 /*******************************************************************************
591  MCF5272_uart_putc() - Send a character to the device output buffer.
592
593  INPUT:
594     chan - pointer to the serial private data.
595     c    - the character to output
596
597  RETURN:
598     'true' if character is sent to device, return 'false' when we've
599     ran out of buffer space in the device itself.
600
601 */
602
603 static bool MCF5272_uart_putc(serial_channel *chan, unsigned char c)
604 {
605     CYG_INTERRUPT_STATE int_state;
606     MCF5272_uart_info_t *port = (MCF5272_uart_info_t *)chan->dev_priv;
607
608     /* Make sure the transmitter is not full. If it is full, return false. */
609     if  (!(MCF5272_UART_READ(port->base->usr_ucsr) & MCF5272_UART_USR_TXRDY))
610         return false;
611
612     /* Enable transmit interrupt. */
613     HAL_DISABLE_INTERRUPTS(int_state);
614     port->imr_mirror |= MCF5272_UART_UIMR_TXRDY;
615     MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
616     HAL_RESTORE_INTERRUPTS(int_state);
617
618     /* Enable the UART transmit. */
619     MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_TXRXEN);
620
621         /* Send the character */
622     MCF5272_UART_WRITE(port->base->urb_utb, c);
623
624         return true ;
625 }
626
627
628 /******************************************************************************************************
629  MCF5272_uart_getc() - Fetch a character from the device input bufferand return it to the alling
630                        routine. Wait until there is a character ready.
631
632  INPUT:
633     chan - pointer to the serial private data.
634
635  RETURN:
636     the character read from the UART.
637
638  */
639 static unsigned char MCF5272_uart_getc(serial_channel *chan)
640 {
641     MCF5272_uart_info_t * port = (MCF5272_uart_info_t *)chan->dev_priv;
642
643     /* Wait until character has been received */
644
645         while (!(MCF5272_UART_READ(port->base->usr_ucsr) & MCF5272_UART_USR_RXRDY))
646     {
647         diag_printf("ready poll");
648     }
649
650     /* Read the character from the FIFO queue. */
651         
652     return MCF5272_UART_READ(port->base->urf);
653
654 }
655
656
657 /*******************************************************************************
658  MCF5272_uart_set_config() - Set up the device characteristics; baud rate, etc.
659
660  INPUT:
661     chan - pointer to the serial private data.
662     key  - configuration key (command).
663     xbuf - pointer to the configuration buffer
664     len  - the length of the configuration buffer
665
666  RETURN:
667     NOERR - If the configuration is successful
668     EINVAL -  If the argument is invalid
669
670 */
671
672 Cyg_ErrNo MCF5272_uart_set_config(serial_channel *chan, cyg_uint32 key,
673                             const void *xbuf, cyg_uint32 *len)
674 {
675     cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
676     MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
677
678
679     switch (key) {
680     case CYG_IO_SET_CONFIG_SERIAL_INFO:
681       {
682           /* Set serial configuration. */
683               if ( *len < sizeof(cyg_serial_info_t) ) {
684               return EINVAL;
685           }
686           *len = sizeof(cyg_serial_info_t);
687
688           if (!MCF5272_uart_config_port(chan, config))
689               return EINVAL;
690       }
691       break;
692
693     case CYG_IO_GET_CONFIG_SERIAL_INFO:
694         // Retrieve UART configuration
695         *config = port->config;
696         break;
697
698     default:
699         return EINVAL;
700     }
701     return ENOERR;
702 }
703
704
705 /*******************************************************************************
706   MCF5272_uart_start_xmit() - Enable the transmitter on the device.
707
708   INPUT:
709     chan - pointer to the serial private data.
710
711 */
712 static void MCF5272_uart_start_xmit(serial_channel *chan)
713 {
714     CYG_INTERRUPT_STATE int_state;
715     MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
716
717     /* Enable the UART transmit. */
718     MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_TXEN);
719
720     /* Enable transmit interrupt */
721     HAL_DISABLE_INTERRUPTS(int_state);
722     port->imr_mirror |= MCF5272_UART_UIMR_TXRDY;
723     MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
724     HAL_RESTORE_INTERRUPTS(int_state);
725
726
727 }
728
729
730 /******************************************************************************************************
731  MCF5272_uart_stop_xmit() - Disable the transmitter on the device
732
733  INPUT:
734     chan - pointer to the serial private data.
735
736 */
737 static void MCF5272_uart_stop_xmit(serial_channel * chan)
738 {       
739    CYG_INTERRUPT_STATE int_state;
740    MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
741
742    /* Disable transmit interrupt */
743    HAL_DISABLE_INTERRUPTS(int_state);
744    port->imr_mirror &= ~MCF5272_UART_UIMR_TXRDY;
745    MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
746    HAL_RESTORE_INTERRUPTS(int_state);
747
748    /* Disable the UART transmit.
749       !!!!!!!!!!!!!
750       !!!WARNING!!!
751       !!!!!!!!!!!!!
752       If the transmit the disabe
753       the diag_printf routines will poll forever to transmit the
754       a character. Hence, don't ever disable the transmit if
755       we want it to work with diag_printf.
756    */
757    //MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_TXDE);
758
759
760 }
761
762
763 /******************************************************************************************************
764  MCF5272_uart_ISR() - UART I/O interrupt interrupt service routine (ISR).
765
766  INPUT:
767     vector - the interrupt vector number
768     data   - user parameter.
769
770
771  RETURN:
772      returns CYG_ISR_CALL_DSR to call the DSR.
773
774  */
775 static cyg_uint32 MCF5272_uart_ISR(cyg_vector_t vector, cyg_addrword_t data)
776 {
777     serial_channel *chan = (serial_channel *) data;
778     MCF5272_uart_info_t * port = (MCF5272_uart_info_t *) chan->dev_priv;
779
780
781     /* Write the value in the interrupt status register back
782        to the mask register to disable the interrupt temporarily.
783      */
784
785     MCF5272_UART_WRITE(port->base->uisr_uimr, 0);
786
787     return CYG_ISR_CALL_DSR;  // Cause DSR to run
788 }
789
790
791
792 /******************************************************************************************************
793  MCF5272_uart_DSR() - Defered Service Routine (DSR) - This routine processes the interrupt
794                       from the device.
795
796  INPUT:
797     vector - The interrupt vector number
798     count  - The nunber of DSR requests.
799     data   - Device specific information
800
801 */
802
803 static void MCF5272_uart_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
804 {
805     serial_channel *chan = (serial_channel *)data;
806     MCF5272_uart_info_t *port = (MCF5272_uart_info_t *)chan->dev_priv;
807     volatile u8_t isr;
808
809
810     /* Retrieve the interrupt status bits. We use these status bits to figure out
811        what process shouled we perform: read from the UART or inform of a completion
812        of a data transmission.
813     */
814
815     /* Retrieve the interrupt status register so
816      * the DSR can look it up.
817      */
818
819
820     while((isr = (MCF5272_UART_READ(port->base->uisr_uimr) & port->imr_mirror)))
821     {
822        switch (port->autobaud_state)
823        {
824        default:
825        case AB_IDLE:
826            if (isr & MCF5272_UART_UISR_DB)
827            {
828                /* Detected the begin of a break, set the state to AB_BEGIN_BREAK
829                */
830                port->autobaud_state = AB_BEGIN_BREAK;
831
832                /* Reset the Delta Break bit in the UISR */
833                MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_BKCHGINT);
834
835            }
836            break;
837        case AB_BEGIN_BREAK:
838            if (isr & MCF5272_UART_UISR_DB)
839            {
840                /* Detected the end of a break, set the state to AB_BEGIN, and
841                   setup autobaud detection.
842                */
843                port->autobaud_state = AB_BEGIN;
844
845                /* Reset the Delta Break bit in the UISR and Enable autobaud */
846                MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_RESET_BKCHGINT |
847                                   MCF5272_UART_UCR_ENAB);
848
849                /* Enable autobaud completion interrupt */
850                port->imr_mirror |= MCF5272_UART_UIMR_ABC;
851                /* Disable the delta break interrupt so we can't receive
852                   anymore break interrupt.
853                */
854                port->imr_mirror &= ~MCF5272_UART_UIMR_DB;
855
856            }
857            break;
858
859        case AB_BEGIN:
860            if (isr & MCF5272_UART_UISR_ABC)
861            {
862                int count;
863                // Retrieve the baudrate that we're using now.
864                u16_t divider = (port->base->uabu << 8) + port->base->uabl;
865                // Search in the list to find a match.
866                for (count = sizeof(dividers_table)/sizeof(unsigned long) - 1;
867                     count >= 0;
868                     count--)
869                {
870                    if (divider < dividers_table[count]) break;
871                }
872
873                // Set the baud.
874                port->config.baud = count;
875
876                /* Autobaud completion */
877                port->autobaud_state = AB_IDLE;
878
879                /* Disable autobaud */
880                MCF5272_UART_WRITE(port->base->ucr, MCF5272_UART_UCR_NONE);
881
882                /* Ignore autobaud completion interrupt. */
883                port->imr_mirror &= ~MCF5272_UART_UIMR_ABC;
884
885                /* Reenable begin break change and receive interrupt. */
886                port->imr_mirror |= MCF5272_UART_UIMR_DB;
887
888            }
889            break;
890
891        }
892
893
894         /* Receive character interrupt */
895         if ((isr & MCF5272_UART_UISR_RXRDY))
896             /* Ignore all receive interrupt when we're autobauding. */
897         {
898             // Read all the characters in the fifo.
899             while ((MCF5272_UART_READ(port->base->uisr_uimr) & MCF5272_UART_UISR_RXRDY))
900             {
901                 char c;
902                 /* Read the character from the UART. */
903                 c = MCF5272_UART_READ(port->base->urb_utb);
904                 /* Pass the read character to the upper layer. */
905                 (chan->callbacks->rcv_char)(chan, c);
906             }
907         }
908
909         /* Transmit  complete interrupt */
910
911         if ((isr & MCF5272_UART_UISR_TXRDY))
912         {
913
914             /*   Transmit holding register is empty                         */
915            (chan->callbacks->xmt_char)(chan);
916
917         }
918
919     }
920
921     /*   Unmask all the DUART interrupts  that were masked  in the ISR,  so */
922     /* that we can receive the next interrupt.                              */
923
924     MCF5272_UART_WRITE(port->base->uisr_uimr, port->imr_mirror);
925
926 }
927
928 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL0
929 unsigned long MCF5272_uart_get_channel_0_baud_rate()
930 {
931     /* return the baud rate for the first serial port */
932
933     return baud_rates_table[MCF5272_uart_channel_info_0.config.baud];
934 }
935 #endif
936
937 #ifdef CYGPKG_IO_SERIAL_MCF5272_UART_CHANNEL1
938 unsigned long MCF5272_uart_get_channel_1_baud_rate()
939 {
940     /* return the baud rate for the second serial port */
941
942     return baud_rates_table[MCF5272_uart_channel_info_1.config.baud];
943 }
944 #endif
945
946