1 //==========================================================================
3 // io/serial/mips/upd985xx/upd985xx_serial.c
5 // NEC MIPS uPD985xx Serial I/O Interface Module (interrupt driven)
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####
44 // Contributors: gthomas
46 // Purpose: NEC MIPS uPD985xx Serial I/O module (interrupt driven version)
49 //####DESCRIPTIONEND####
51 //==========================================================================
53 #include <pkgconf/system.h>
54 #include <pkgconf/io_serial.h>
55 #include <pkgconf/io.h>
57 #include <cyg/io/io.h>
58 #include <cyg/hal/hal_intr.h>
59 #include <cyg/io/devtab.h>
60 #include <cyg/io/serial.h>
61 #include <cyg/infra/diag.h>
63 #include "upd985xx_serial.h"
65 typedef struct upd985xx_serial_info {
68 cyg_interrupt serial_interrupt;
69 cyg_handle_t serial_interrupt_handle;
70 } upd985xx_serial_info;
72 static bool upd985xx_serial_init(struct cyg_devtab_entry *tab);
73 static bool upd985xx_serial_putc(serial_channel *chan, unsigned char c);
74 static Cyg_ErrNo upd985xx_serial_lookup(struct cyg_devtab_entry **tab,
75 struct cyg_devtab_entry *sub_tab,
77 static unsigned char upd985xx_serial_getc(serial_channel *chan);
78 static Cyg_ErrNo upd985xx_serial_set_config(serial_channel *chan, cyg_uint32 key,
79 const void *xbuf, cyg_uint32 *len);
80 static void upd985xx_serial_start_xmit(serial_channel *chan);
81 static void upd985xx_serial_stop_xmit(serial_channel *chan);
83 static cyg_uint32 upd985xx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
84 static void upd985xx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
86 static SERIAL_FUNS(upd985xx_serial_funs,
89 upd985xx_serial_set_config,
90 upd985xx_serial_start_xmit,
91 upd985xx_serial_stop_xmit
94 #ifdef CYGPKG_IO_SERIAL_MIPS_UPD985XX_SERIAL0
95 static upd985xx_serial_info upd985xx_serial_info0 = {
96 // base: (CYG_ADDRWORD)UPD985XX_UART3_CONTROL0,
97 int_num: CYGNUM_HAL_INTERRUPT_UART,
99 #if CYGNUM_IO_SERIAL_MIPS_UPD985XX_SERIAL0_BUFSIZE > 0
100 static unsigned char upd985xx_serial_out_buf0[CYGNUM_IO_SERIAL_MIPS_UPD985XX_SERIAL0_BUFSIZE];
101 static unsigned char upd985xx_serial_in_buf0[CYGNUM_IO_SERIAL_MIPS_UPD985XX_SERIAL0_BUFSIZE];
103 static SERIAL_CHANNEL_USING_INTERRUPTS(
104 upd985xx_serial_channel0,
105 upd985xx_serial_funs,
106 upd985xx_serial_info0,
107 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MIPS_UPD985XX_SERIAL0_BAUD),
108 CYG_SERIAL_STOP_DEFAULT,
109 CYG_SERIAL_PARITY_DEFAULT,
110 CYG_SERIAL_WORD_LENGTH_DEFAULT,
111 CYG_SERIAL_FLAGS_DEFAULT,
112 &upd985xx_serial_out_buf0[0], sizeof(upd985xx_serial_out_buf0),
113 &upd985xx_serial_in_buf0[0], sizeof(upd985xx_serial_in_buf0)
116 static SERIAL_CHANNEL(
117 upd985xx_serial_channel0,
118 upd985xx_serial_funs,
119 upd985xx_serial_info0,
120 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_MIPS_UPD985XX_SERIAL0_BAUD),
121 CYG_SERIAL_STOP_DEFAULT,
122 CYG_SERIAL_PARITY_DEFAULT,
123 CYG_SERIAL_WORD_LENGTH_DEFAULT,
124 CYG_SERIAL_FLAGS_DEFAULT
128 DEVTAB_ENTRY(upd985xx_serial_io0,
129 CYGDAT_IO_SERIAL_MIPS_UPD985XX_SERIAL0_NAME,
130 0, // Does not depend on a lower level interface
131 &cyg_io_serial_devio,
132 upd985xx_serial_init,
133 upd985xx_serial_lookup, // Serial driver may need initializing
134 &upd985xx_serial_channel0
136 #endif // CYGPKG_IO_SERIAL_MIPS_UPD985XX_SERIAL1
138 // Internal function to actually configure the hardware to desired baud rate, etc.
140 upd985xx_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
142 unsigned char parity;
143 unsigned char word_length;
144 unsigned char stop_bits;
147 parity = select_parity[new_config->parity];
148 word_length = select_word_length[new_config->word_length-CYGNUM_SERIAL_WORD_LENGTH_5];
149 stop_bits = select_stop_bits[new_config->stop];
150 baud = select_baud[new_config->baud];
152 if ((word_length == 0xFF) ||
154 (stop_bits == 0xFF)) {
155 return false; // Unsupported configuration
158 // First ensure we are accessing the right registers.
159 // Clear the divisor latch access bit
160 *UARTLCR &=~UARTLCR_DLAB;
162 // Disable Receiver and Transmitter
163 // No such thing in uPD985xx - but we can mask interrupts:
166 // Clear sticky (writable) status bits.
167 // Ensure it's in 16550 mode at least:
168 *UARTFCR = UARTFCR_16550_MODE;
170 // Set parity, word length, stop bits (keep DLAB clear)
171 *UARTLCR = word_length | parity | stop_bits;
173 // Set the desired baud rate.
174 *UARTLCR |= UARTLCR_DLAB;
175 *UARTDLM = (baud >> 8) & 0xff;
176 *UARTDLL = baud & 0xff;
177 *UARTLCR &=~UARTLCR_DLAB;
179 // Enable the receiver (with interrupts) and the transmitter.
180 *UARTIER = UARTIER_ERBFI;
185 // Function to initialize the device. Called at bootstrap time.
187 upd985xx_serial_init(struct cyg_devtab_entry *tab)
189 serial_channel *chan = (serial_channel *)tab->priv;
190 upd985xx_serial_info *upd985xx_chan = (upd985xx_serial_info *)chan->dev_priv;
192 #ifdef CYGDBG_IO_INIT
193 diag_printf("UPD985XX SERIAL init - dev: %x.%d\n", 0 /* upd985xx_chan->base */,
194 upd985xx_chan->int_num);
196 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
197 if (chan->out_cbuf.len != 0) {
198 cyg_drv_interrupt_create(upd985xx_chan->int_num,
199 99, // Priority - unused
200 (cyg_addrword_t)chan, // Data item passed to interrupt handler
203 &upd985xx_chan->serial_interrupt_handle,
204 &upd985xx_chan->serial_interrupt);
205 cyg_drv_interrupt_attach(upd985xx_chan->serial_interrupt_handle);
206 cyg_drv_interrupt_unmask(upd985xx_chan->int_num);
208 res = upd985xx_serial_config_port(chan, &chan->config, true);
212 // This routine is called when the device is "looked" up (i.e. attached)
214 upd985xx_serial_lookup(struct cyg_devtab_entry **tab,
215 struct cyg_devtab_entry *sub_tab,
218 serial_channel *chan = (serial_channel *)(*tab)->priv;
219 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
223 // Send a character to the device output buffer.
224 // Return 'true' if character is sent to device
226 upd985xx_serial_putc(serial_channel *chan, unsigned char c)
228 if ( 0 == (UARTLSR_THRE & *UARTLSR) )
230 *UARTTHR = (unsigned int)c;
234 // Fetch a character from the device input buffer, waiting if necessary
236 upd985xx_serial_getc(serial_channel *chan)
238 while ( 0 == (UARTLSR_DR & *UARTLSR) )
241 return (char)*UARTRBR;
244 // Set up the device characteristics; baud rate, etc.
246 upd985xx_serial_set_config(serial_channel *chan, cyg_uint32 key,
247 const void *xbuf, cyg_uint32 *len)
250 case CYG_IO_SET_CONFIG_SERIAL_INFO:
252 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
253 if ( *len < sizeof(cyg_serial_info_t) ) {
256 *len = sizeof(cyg_serial_info_t);
257 if ( true != upd985xx_serial_config_port(chan, config, false) )
267 // Enable the transmitter on the device
269 upd985xx_serial_start_xmit(serial_channel *chan)
271 (chan->callbacks->xmt_char)(chan); // Kick transmitter (if necessary)
272 *UARTIER |= UARTIER_ERBEI; // enable interrupts
275 // Disable the transmitter on the device
277 upd985xx_serial_stop_xmit(serial_channel *chan)
279 *UARTIER &=~UARTIER_ERBEI; // disable interrupts
282 // Serial I/O - low level interrupt handler (ISR)
284 upd985xx_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
286 cyg_drv_interrupt_mask(vector);
287 return CYG_ISR_CALL_DSR; // Cause DSR to be run
290 // Serial I/O - high level interrupt handler (DSR)
292 upd985xx_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
294 serial_channel *chan = (serial_channel *)data;
298 stat &= UARTIIR_UIID_MASK;
300 if (stat == UARTIIR_TX_EMPTY) {
301 (chan->callbacks->xmt_char)(chan);
303 if (stat == UARTIIR_RXD_AVAIL) {
304 while (0 != (UARTLSR_DR & *UARTLSR)) {
305 (chan->callbacks->rcv_char)(chan, (char)*UARTRBR);
308 cyg_drv_interrupt_acknowledge(vector);
309 cyg_drv_interrupt_unmask(vector);
312 // ------------------------------------------------------------------------
313 // EOF upd985xx_serial.c