1 //=============================================================================
5 // Simple driver for the 16c550c serial controllers on the Malta board
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.
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.
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
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.
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.
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.
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####
43 // Author(s): dmoseley
44 // Contributors:dmoseley, jskov
46 // Description: Simple driver for the 16c550c serial controller
48 //####DESCRIPTIONEND####
50 //=============================================================================
52 #include <pkgconf/hal.h>
53 #include <pkgconf/system.h>
54 #include CYGBLD_HAL_PLATFORM_H
56 #include <cyg/hal/hal_arch.h> // SAVE/RESTORE GP macros
57 #include <cyg/hal/hal_io.h> // IO macros
58 #include <cyg/hal/hal_if.h> // interface API
59 #include <cyg/hal/hal_intr.h> // HAL_ENABLE/MASK/UNMASK_INTERRUPTS
60 #include <cyg/hal/hal_misc.h> // Helper functions
61 #include <cyg/hal/drv_api.h> // CYG_ISR_HANDLED
63 //-----------------------------------------------------------------------------
64 // Define the serial registers. The Malta board is equipped with a 16550C
66 #define MALTA_SER_CLOCK 1843200
67 #define MALTA_SER_16550_BASE_A 0xb80003f8
68 #define MALTA_SER_16550_BASE_B 0xb80002f8
69 #define SER_16550_RBR 0x00 // receiver buffer register, read, dlab = 0
70 #define SER_16550_THR 0x00 // transmitter holding register, write, dlab = 0
71 #define SER_16550_DLL 0x00 // divisor latch (LS), read/write, dlab = 1
72 #define SER_16550_IER 0x01 // interrupt enable register, read/write, dlab = 0
73 #define SER_16550_DLM 0x01 // divisor latch (MS), read/write, dlab = 1
74 #define SER_16550_IIR 0x02 // interrupt identification reg, read, dlab = 0
75 #define SER_16550_FCR 0x02 // fifo control register, write, dlab = 0
76 #define SER_16550_AFR 0x02 // alternate function reg, read/write, dlab = 1
77 #define SER_16550_LCR 0x03 // line control register, read/write
78 #define SER_16550_MCR 0x04 // modem control register, read/write
79 #define SER_16550_LSR 0x05 // line status register, read
80 #define SER_16550_MSR 0x06 // modem status register, read
81 #define SER_16550_SCR 0x07 // scratch pad register
83 // The interrupt enable register bits.
84 #define SIO_IER_ERDAI 0x01 // enable received data available irq
85 #define SIO_IER_ETHREI 0x02 // enable THR empty interrupt
86 #define SIO_IER_ELSI 0x04 // enable receiver line status irq
87 #define SIO_IER_EMSI 0x08 // enable modem status interrupt
89 // The interrupt identification register bits.
90 #define SIO_IIR_IP 0x01 // 0 if interrupt pending
91 #define SIO_IIR_ID_MASK 0x0e // mask for interrupt ID bits
93 // The line status register bits.
94 #define SIO_LSR_DR 0x01 // data ready
95 #define SIO_LSR_OE 0x02 // overrun error
96 #define SIO_LSR_PE 0x04 // parity error
97 #define SIO_LSR_FE 0x08 // framing error
98 #define SIO_LSR_BI 0x10 // break interrupt
99 #define SIO_LSR_THRE 0x20 // transmitter holding register empty
100 #define SIO_LSR_TEMT 0x40 // transmitter register empty
101 #define SIO_LSR_ERR 0x80 // any error condition
103 // The modem status register bits.
104 #define SIO_MSR_DCTS 0x01 // delta clear to send
105 #define SIO_MSR_DDSR 0x02 // delta data set ready
106 #define SIO_MSR_TERI 0x04 // trailing edge ring indicator
107 #define SIO_MSR_DDCD 0x08 // delta data carrier detect
108 #define SIO_MSR_CTS 0x10 // clear to send
109 #define SIO_MSR_DSR 0x20 // data set ready
110 #define SIO_MSR_RI 0x40 // ring indicator
111 #define SIO_MSR_DCD 0x80 // data carrier detect
113 // The line control register bits.
114 #define SIO_LCR_WLS0 0x01 // word length select bit 0
115 #define SIO_LCR_WLS1 0x02 // word length select bit 1
116 #define SIO_LCR_STB 0x04 // number of stop bits
117 #define SIO_LCR_PEN 0x08 // parity enable
118 #define SIO_LCR_EPS 0x10 // even parity select
119 #define SIO_LCR_SP 0x20 // stick parity
120 #define SIO_LCR_SB 0x40 // set break
121 #define SIO_LCR_DLAB 0x80 // divisor latch access bit
123 // The FIFO control register
124 #define SIO_FCR_FCR0 0x01 // enable xmit and rcvr fifos
125 #define SIO_FCR_FCR1 0x02 // clear RCVR FIFO
126 #define SIO_FCR_FCR2 0x04 // clear XMIT FIFO
128 /////////////////////////////////////////
129 // Interrupt Enable Register
135 // Line Control Register
136 #define LCR_WL5 0x00 // Word length
140 #define LCR_SB1 0x00 // Number of stop bits
141 #define LCR_SB1_5 0x04 // 1.5 -> only valid with 5 bit words
143 #define LCR_PN 0x00 // Parity mode - none
144 #define LCR_PE 0x0C // Parity mode - even
145 #define LCR_PO 0x08 // Parity mode - odd
146 #define LCR_PM 0x28 // Forced "mark" parity
147 #define LCR_PS 0x38 // Forced "space" parity
148 #define LCR_DL 0x80 // Enable baud rate latch
150 // Line Status Register
154 // Modem Control Register
157 #define MCR_INT 0x08 // Enable interrupts
160 // Interrupt status register
161 #define ISR_None 0x01
162 #define ISR_Rx_Line_Status 0x06
163 #define ISR_Rx_Avail 0x04
164 #define ISR_Rx_Char_Timeout 0x0C
165 #define ISR_Tx_Empty 0x02
166 #define IRS_Modem_Status 0x00
168 // FIFO control register
169 #define FCR_ENABLE 0x01
170 #define FCR_CLEAR_RCVR 0x02
171 #define FCR_CLEAR_XMIT 0x04
173 #define CYG_DEV_SERIAL_BAUD_DIVISOR (MALTA_SER_CLOCK/16/CYGNUM_HAL_VIRTUAL_VECTOR_CHANNELS_DEFAULT_BAUD)
175 //-----------------------------------------------------------------------------
178 cyg_int32 msec_timeout;
182 static channel_data_t channels[2] = {
183 { (cyg_uint8*)MALTA_SER_16550_BASE_A, 1000, CYGNUM_HAL_INTERRUPT_TTY0},
184 { (cyg_uint8*)MALTA_SER_16550_BASE_B, 1000, CYGNUM_HAL_INTERRUPT_TTY1}
187 //-----------------------------------------------------------------------------
191 cyg_hal_plf_serial_set_baud(cyg_uint8* port, cyg_uint16 baud_divisor)
195 HAL_READ_UINT8(port+SER_16550_LCR, _lcr);
197 HAL_WRITE_UINT8(port+SER_16550_LCR, _lcr);
199 HAL_WRITE_UINT8(port+SER_16550_DLM, baud_divisor >> 8);
200 HAL_WRITE_UINT8(port+SER_16550_DLL, baud_divisor & 0xff);
203 HAL_WRITE_UINT8(port+SER_16550_LCR, _lcr);
206 //-----------------------------------------------------------------------------
207 // The minimal init, get and put functions. All by polling.
210 cyg_hal_plf_serial_init_channel(void* __ch_data)
215 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
216 // Go ahead and assume it is channels[0].
218 __ch_data = (void*)&channels[0];
220 port = ((channel_data_t*)__ch_data)->base;
222 // Disable port interrupts while changing hardware
223 HAL_WRITE_UINT8(port+SER_16550_IER, 0);
225 // Set databits, stopbits and parity.
226 _lcr = LCR_WL8 | LCR_SB1 | LCR_PN;
227 HAL_WRITE_UINT8(port+SER_16550_LCR, _lcr);
230 cyg_hal_plf_serial_set_baud(port, CYG_DEV_SERIAL_BAUD_DIVISOR);
232 // Enable and clear FIFO
233 HAL_WRITE_UINT8(port+SER_16550_FCR, (FCR_ENABLE | FCR_CLEAR_RCVR | FCR_CLEAR_XMIT));
235 // enable RTS to keep host side happy. Also allow interrupts
236 HAL_WRITE_UINT8( port+SER_16550_MCR, MCR_DTR | MCR_RTS | MCR_INT);
238 // Don't allow interrupts.
239 HAL_WRITE_UINT8(port+SER_16550_IER, 0);
243 cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 __ch)
248 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
249 // Go ahead and assume it is channels[0].
251 __ch_data = (void*)&channels[0];
253 port = ((channel_data_t*)__ch_data)->base;
255 CYGARC_HAL_SAVE_GP();
258 HAL_READ_UINT8(port+SER_16550_LSR, _lsr);
259 } while ((_lsr & SIO_LSR_THRE) == 0);
261 // Now, the transmit buffer is empty
262 HAL_WRITE_UINT8(port+SER_16550_THR, __ch);
264 // Hang around until the character has been safely sent.
266 HAL_READ_UINT8(port+SER_16550_LSR, _lsr);
267 } while ((_lsr & SIO_LSR_THRE) == 0);
269 CYGARC_HAL_RESTORE_GP();
273 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
278 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
279 // Go ahead and assume it is channels[0].
281 __ch_data = (void*)&channels[0];
283 port = ((channel_data_t*)__ch_data)->base;
285 HAL_READ_UINT8(port+SER_16550_LSR, _lsr);
286 if ((_lsr & SIO_LSR_DR) == 0)
289 HAL_READ_UINT8(port+SER_16550_RBR, *ch);
295 cyg_hal_plf_serial_getc(void* __ch_data)
298 CYGARC_HAL_SAVE_GP();
300 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
301 // Go ahead and assume it is channels[0].
303 __ch_data = (void*)&channels[0];
305 while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
307 CYGARC_HAL_RESTORE_GP();
312 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf,
315 CYGARC_HAL_SAVE_GP();
317 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
318 // Go ahead and assume it is channels[0].
320 __ch_data = (void*)&channels[0];
323 cyg_hal_plf_serial_putc(__ch_data, *__buf++);
325 CYGARC_HAL_RESTORE_GP();
329 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
331 CYGARC_HAL_SAVE_GP();
333 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
334 // Go ahead and assume it is channels[0].
336 __ch_data = (void*)&channels[0];
339 *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
341 CYGARC_HAL_RESTORE_GP();
346 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
349 channel_data_t* chan;
351 CYGARC_HAL_SAVE_GP();
353 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
354 // Go ahead and assume it is channels[0].
356 __ch_data = (void*)&channels[0];
358 chan = (channel_data_t*)__ch_data;
360 delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
363 res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
364 if (res || 0 == delay_count--)
366 CYGACC_CALL_IF_DELAY_US(100);
369 CYGARC_HAL_RESTORE_GP();
374 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
376 static int irq_state = 0;
377 channel_data_t* chan;
380 CYGARC_HAL_SAVE_GP();
382 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
383 // Go ahead and assume it is channels[0].
385 __ch_data = (void*)&channels[0];
387 chan = (channel_data_t*)__ch_data;
390 case __COMMCTL_IRQ_ENABLE:
393 HAL_READ_UINT8(chan->base + SER_16550_IER, ier);
394 ier |= SIO_IER_ERDAI;
395 HAL_WRITE_UINT8(chan->base + SER_16550_IER, ier);
397 HAL_INTERRUPT_SET_LEVEL(chan->isr_vector, 1);
398 HAL_INTERRUPT_UNMASK(chan->isr_vector);
400 case __COMMCTL_IRQ_DISABLE:
404 HAL_READ_UINT8(chan->base + SER_16550_IER, ier);
405 ier &= ~SIO_IER_ERDAI;
406 HAL_WRITE_UINT8(chan->base + SER_16550_IER, ier);
408 HAL_INTERRUPT_MASK(chan->isr_vector);
410 case __COMMCTL_DBG_ISR_VECTOR:
411 ret = chan->isr_vector;
413 case __COMMCTL_SET_TIMEOUT:
417 va_start(ap, __func);
419 ret = chan->msec_timeout;
420 chan->msec_timeout = va_arg(ap, cyg_uint32);
425 case __COMMCTL_SETBAUD:
427 cyg_uint32 baud_rate;
428 cyg_uint16 baud_divisor;
429 cyg_uint8* port = chan->base;
432 va_start(ap, __func);
433 baud_rate = va_arg(ap, cyg_uint32);
436 baud_divisor = (MALTA_SER_CLOCK / 16 / baud_rate);
438 HAL_WRITE_UINT32(HAL_MALTA_BRKRES, 0);
441 // We may need to increase the timeout before causing a break reset.
442 // According to the Malta Users Manual (Document MD00005) The BRKRES
443 // register will need to be programmed with a value larger that 0xA (the default)
444 // if we are going to use a baud rate lower than 2400.
446 if (baud_rate <= 2400)
448 // For now, just disable the break reset entirely.
449 HAL_WRITE_UINT32(HAL_MALTA_BRKRES, 0);
451 // Put the break reset state back to the default
452 HAL_WRITE_UINT32(HAL_MALTA_BRKRES, HAL_MALTA_BRKRES_DEFAULT_VALUE);
455 // Disable port interrupts while changing hardware
456 HAL_READ_UINT8(port+SER_16550_IER, ier);
457 HAL_WRITE_UINT8(port+SER_16550_IER, 0);
460 cyg_hal_plf_serial_set_baud(port, baud_divisor);
462 // Reenable interrupts if necessary
463 HAL_WRITE_UINT8(port+SER_16550_IER, ier);
467 case __COMMCTL_GETBAUD:
472 CYGARC_HAL_RESTORE_GP();
477 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc,
478 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
482 channel_data_t* chan;
483 CYGARC_HAL_SAVE_GP();
485 // Some of the diagnostic print code calls through here with no idea what the ch_data is.
486 // Go ahead and assume it is channels[0].
488 __ch_data = (void*)&channels[0];
490 chan = (channel_data_t*)__ch_data;
492 HAL_INTERRUPT_ACKNOWLEDGE(chan->isr_vector);
494 HAL_READ_UINT8(chan->base + SER_16550_IIR, _iir);
495 _iir &= SIO_IIR_ID_MASK;
498 if ((_iir == ISR_Rx_Avail) || (_iir == ISR_Rx_Char_Timeout)) {
500 HAL_READ_UINT8(chan->base + SER_16550_RBR, c);
502 if( cyg_hal_is_break( &c , 1 ) )
505 res = CYG_ISR_HANDLED;
508 CYGARC_HAL_RESTORE_GP();
513 cyg_hal_plf_serial_init(void)
515 hal_virtual_comm_table_t* comm;
516 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
518 // Disable interrupts.
519 HAL_INTERRUPT_MASK(channels[0].isr_vector);
520 HAL_INTERRUPT_MASK(channels[1].isr_vector);
523 cyg_hal_plf_serial_init_channel((void*)&channels[0]);
524 cyg_hal_plf_serial_init_channel((void*)&channels[1]);
526 // Setup procs in the vector table
529 CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
530 comm = CYGACC_CALL_IF_CONSOLE_PROCS();
531 CYGACC_COMM_IF_CH_DATA_SET(*comm, &channels[0]);
532 CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
533 CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
534 CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
535 CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
536 CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
537 CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
538 CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
541 CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
542 comm = CYGACC_CALL_IF_CONSOLE_PROCS();
543 CYGACC_COMM_IF_CH_DATA_SET(*comm, &channels[1]);
544 CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
545 CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
546 CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
547 CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
548 CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
549 CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
550 CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
552 // Restore original console
553 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
557 cyg_hal_plf_comms_init(void)
559 static int initialized = 0;
566 cyg_hal_plf_serial_init();
569 //-----------------------------------------------------------------------------
570 // end of ser16c550c.c