1 //==========================================================================
3 // devs/serial/arm/ebsa285/current/src/ebsa285_serial.c
5 // ARM EBSA285 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####
46 // Purpose: EBSA285 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 #ifdef CYGPKG_IO_SERIAL_ARM_EBSA285
59 #include <cyg/io/io.h>
60 #include <cyg/hal/hal_intr.h>
61 #include <cyg/io/devtab.h>
62 #include <cyg/io/serial.h>
63 #include <cyg/infra/diag.h>
65 #include <cyg/hal/hal_ebsa285.h> // Hardware definitions
67 // ------------------------------------------------------------------------
68 // Baud rates and the like, table-driven setup
72 unsigned char divisor_high, divisor_low;
75 // The indexing of this table must match the enum in serialio.h
76 // The arithmetic is (clock/4)/(baud * 16) - 1
79 const static struct _baud bauds[] = {
88 { 0xA, 0x2B }, // 300 2603 = 0x0A2B
89 { 0x5, 0x15 }, // 600 1301 = 0x0515
90 { 0x2, 0x8A }, // 1200 650 = 0x028A
91 { 0x1, 0xB1 }, // 1800 433 = 0x01B1
92 { 0x1, 0x45 }, // 2400 325 = 0x0145
93 { 0x0, 0xD8 }, // 3600 216 = 0x00D8
94 { 0x0, 0xA2 }, // 4800 162 = 0x00A2
95 { 0x0, 0x6B }, // 7200 107 = 0x006B
96 { 0x0, 0x50 }, // 9600 80 = 0x0050
97 { 0x0, 0x35 }, // 14400 53 = 0x0035
98 { 0x0, 0x28 }, // 19200 40 = 0x0028
99 { 0x0, 0x13 }, // 38400 19 = 0x0013
103 #elif (FCLK_MHZ == 60)
104 #error NOT SUPPORTED - these figures are more for documentation
105 { /* 300, */ 0xC, 0x34}, /* 2603 = 0x0A2B */
106 { /* 600, */ 0x6, 0x19}, /* 1301 = 0x0515 */
107 { /* 1200, */ 0x3, 0x0C}, /* 650 = 0x028A */
108 { /* 2400, */ 0x1, 0x86}, /* 325 = 0x0145 */
109 { /* 4800, */ 0x0, 0xC2}, /* 162 = 0x00A2 */
110 { /* 9600, */ 0x0, 0x61}, /* 80 = 0x0050 */
111 { /* 19200, */ 0x0, 0x30}, /* 40 = 0x0028 */
112 { /* 38400, */ 0x0, 0x17}, /* 19 = 0x0013 */
116 static int select_word_length[] = {
117 SA110_UART_DATA_LENGTH_5_BITS, // 5 bits
118 SA110_UART_DATA_LENGTH_6_BITS, // 6 bits
119 SA110_UART_DATA_LENGTH_7_BITS, // 7 bits
120 SA110_UART_DATA_LENGTH_8_BITS // 8 bits
123 static int select_stop_bits[] = {
125 SA110_UART_STOP_BITS_ONE, // 1 stop bit
127 SA110_UART_STOP_BITS_TWO // 2 stop bits
130 static int select_parity[] = {
131 SA110_UART_PARITY_DISABLED, // No parity
132 SA110_UART_PARITY_ENABLED | SA110_UART_PARITY_EVEN, // Even parity
133 SA110_UART_PARITY_ENABLED | SA110_UART_PARITY_ODD, // Odd parity
138 // ------------------------------------------------------------------------
139 // some forward references
141 struct ebsa285_serial_interrupt {
143 cyg_interrupt serial_interrupt;
144 cyg_handle_t serial_interrupt_handle;
147 typedef struct ebsa285_serial_info {
148 struct ebsa285_serial_interrupt rx;
149 struct ebsa285_serial_interrupt tx;
151 } ebsa285_serial_info;
153 static bool ebsa285_serial_init(struct cyg_devtab_entry *tab);
154 static bool ebsa285_serial_putc(serial_channel *chan, unsigned char c);
155 static Cyg_ErrNo ebsa285_serial_lookup(struct cyg_devtab_entry **tab,
156 struct cyg_devtab_entry *sub_tab,
158 static unsigned char ebsa285_serial_getc(serial_channel *chan);
159 static Cyg_ErrNo ebsa285_serial_set_config(serial_channel *chan, cyg_uint32 key,
160 const void *xbuf, cyg_uint32 *len);
162 static void ebsa285_serial_start_xmit(serial_channel *chan);
163 static void ebsa285_serial_stop_xmit(serial_channel *chan);
165 static cyg_uint32 ebsa285_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
166 static void ebsa285_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
167 static cyg_uint32 ebsa285_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
168 static void ebsa285_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
170 static SERIAL_FUNS(ebsa285_serial_funs,
173 ebsa285_serial_set_config,
174 ebsa285_serial_start_xmit,
175 ebsa285_serial_stop_xmit
179 // ------------------------------------------------------------------------
180 // this is dummy in config: there is only one device on the EBSA285
181 #ifdef CYGPKG_IO_SERIAL_ARM_EBSA285_SERIAL
183 static ebsa285_serial_info ebsa285_serial_info1 = {
184 { CYGNUM_HAL_INTERRUPT_SERIAL_RX },
185 { CYGNUM_HAL_INTERRUPT_SERIAL_TX },
189 #if CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BUFSIZE > 0
190 static unsigned char ebsa285_serial_out_buf[CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BUFSIZE];
191 static unsigned char ebsa285_serial_in_buf[CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BUFSIZE];
193 static SERIAL_CHANNEL_USING_INTERRUPTS(ebsa285_serial_channel,
195 ebsa285_serial_info1,
196 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BAUD),
197 CYG_SERIAL_STOP_DEFAULT,
198 CYG_SERIAL_PARITY_DEFAULT,
199 CYG_SERIAL_WORD_LENGTH_DEFAULT,
200 CYG_SERIAL_FLAGS_DEFAULT,
201 &ebsa285_serial_out_buf[0], sizeof(ebsa285_serial_out_buf),
202 &ebsa285_serial_in_buf[0], sizeof(ebsa285_serial_in_buf)
205 static SERIAL_CHANNEL(ebsa285_serial_channel,
207 ebsa285_serial_info1,
208 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BAUD),
209 CYG_SERIAL_STOP_DEFAULT,
210 CYG_SERIAL_PARITY_DEFAULT,
211 CYG_SERIAL_WORD_LENGTH_DEFAULT,
212 CYG_SERIAL_FLAGS_DEFAULT
216 DEVTAB_ENTRY(ebsa285_serial_io,
217 CYGDAT_IO_SERIAL_ARM_EBSA285_SERIAL_NAME,
218 0, // Does not depend on a lower level interface
219 &cyg_io_serial_devio,
221 ebsa285_serial_lookup, // Serial driver may need initializing
222 &ebsa285_serial_channel
224 #endif // CYGPKG_IO_SERIAL_ARM_EBSA285_SERIAL
226 // ------------------------------------------------------------------------
229 // ------------------------------------------------------------------------
230 // Internal function to actually configure the hardware to desired baud rate, etc.
232 ebsa285_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
236 // Make sure everything is off
237 *SA110_UART_CONTROL_REGISTER = SA110_UART_DISABLED | SA110_SIR_DISABLED;
239 // Read the RXStat to drain the fifo
240 dummy = *SA110_UART_RXSTAT;
242 // Set the baud rate - this also turns the uart on.
244 // Note that the ordering of these writes is critical,
245 // and the writes to the H_BAUD_CONTROL and CONTROL_REGISTER
246 // are necessary to force the UART to update its register
249 l = bauds[new_config->baud].divisor_low; // zeros in unused slots here
250 m = bauds[new_config->baud].divisor_high; // and here
251 h = SA110_UART_BREAK_DISABLED |
252 select_stop_bits[new_config->stop] | // -1s in unused slots for these
253 select_parity[new_config->parity] | // and these
254 SA110_UART_FIFO_ENABLED | // and these below
255 select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
257 if ( 0 != (l + m) && h >= 0 && h < 256 ) {
258 *SA110_UART_L_BAUD_CONTROL = l;
259 *SA110_UART_M_BAUD_CONTROL = m;
260 *SA110_UART_H_BAUD_CONTROL = h;
264 // put in some sensible defaults
265 *SA110_UART_L_BAUD_CONTROL = 0x13; // bp->divisor_low;
266 *SA110_UART_M_BAUD_CONTROL = 0x00; // bp->divisor_high;
267 *SA110_UART_H_BAUD_CONTROL = SA110_UART_BREAK_DISABLED |
268 SA110_UART_PARITY_DISABLED |
269 SA110_UART_STOP_BITS_ONE |
270 SA110_UART_FIFO_ENABLED |
271 SA110_UART_DATA_LENGTH_8_BITS;
274 // All set, re-enable the device:
275 *SA110_UART_CONTROL_REGISTER = SA110_UART_ENABLED | SA110_SIR_DISABLED;
277 if (init && new_config != &chan->config) {
278 // record the new setup
279 chan->config = *new_config;
285 // Function to initialize the device. Called at bootstrap time.
287 ebsa285_serial_init(struct cyg_devtab_entry *tab)
289 serial_channel *chan = (serial_channel *)tab->priv;
290 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
291 #ifdef CYGDBG_IO_INIT
292 diag_printf("EBSA285 SERIAL init - dev: %x\n", ebsa285_chan);
294 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
295 if (chan->out_cbuf.len != 0) {
298 cyg_drv_interrupt_create(ebsa285_chan->rx.int_num,
299 99, // Priority - unused
300 (cyg_addrword_t)chan, // Data item passed to interrupt handler
301 ebsa285_serial_rx_ISR,
302 ebsa285_serial_rx_DSR,
303 &ebsa285_chan->rx.serial_interrupt_handle,
304 &ebsa285_chan->rx.serial_interrupt);
305 cyg_drv_interrupt_attach(ebsa285_chan->rx.serial_interrupt_handle);
306 cyg_drv_interrupt_unmask(ebsa285_chan->rx.int_num);
309 cyg_drv_interrupt_create(ebsa285_chan->tx.int_num,
310 99, // Priority - unused
311 (cyg_addrword_t)chan, // Data item passed to interrupt handler
312 ebsa285_serial_tx_ISR,
313 ebsa285_serial_tx_DSR,
314 &ebsa285_chan->tx.serial_interrupt_handle,
315 &ebsa285_chan->tx.serial_interrupt);
316 cyg_drv_interrupt_attach(ebsa285_chan->tx.serial_interrupt_handle);
317 // DO NOT cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
318 ebsa285_chan->tx_active = 0;
320 (void)ebsa285_serial_config_port(chan, &chan->config, true);
324 // This routine is called when the device is "looked" up (i.e. attached)
326 ebsa285_serial_lookup(struct cyg_devtab_entry **tab,
327 struct cyg_devtab_entry *sub_tab,
330 serial_channel *chan = (serial_channel *)(*tab)->priv;
331 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
335 // Send a character to the device output buffer.
336 // Return 'true' if character is sent to device
338 ebsa285_serial_putc(serial_channel *chan, unsigned char c)
340 if ((*SA110_UART_FLAG_REGISTER & SA110_TX_FIFO_STATUS_MASK) == SA110_TX_FIFO_BUSY)
341 return false; // No space
343 *SA110_UART_DATA_REGISTER = c; // Transmit buffer is empty
347 // Fetch a character from the device input buffer, waiting if necessary
349 ebsa285_serial_getc(serial_channel *chan)
352 while ((*SA110_UART_FLAG_REGISTER & SA110_RX_FIFO_STATUS_MASK) == SA110_RX_FIFO_EMPTY)
354 c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
355 // no error checking... no way to return the info
359 // Set up the device characteristics; baud rate, etc.
361 ebsa285_serial_set_config(serial_channel *chan, cyg_uint32 key,
362 const void *xbuf, cyg_uint32 *len)
365 case CYG_IO_SET_CONFIG_SERIAL_INFO:
367 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
368 if ( *len < sizeof(cyg_serial_info_t) ) {
371 *len = sizeof(cyg_serial_info_t);
372 if ( true != ebsa285_serial_config_port(chan, config, false) )
382 // Enable the transmitter on the device (nope, already in use by hal_diag)
384 ebsa285_serial_start_xmit(serial_channel *chan)
386 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
387 ebsa285_chan->tx_active = 1;
388 cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
391 // Disable the transmitter on the device (nope, remains in use by hal_diag)
393 ebsa285_serial_stop_xmit(serial_channel *chan)
395 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
396 cyg_drv_interrupt_mask(ebsa285_chan->tx.int_num);
397 ebsa285_chan->tx_active = 0;
400 // Serial I/O - low level interrupt handlers (ISR)
402 ebsa285_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
404 serial_channel *chan = (serial_channel *)data;
405 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
406 cyg_drv_interrupt_mask(ebsa285_chan->rx.int_num);
407 cyg_drv_interrupt_acknowledge(ebsa285_chan->rx.int_num);
408 return CYG_ISR_CALL_DSR; // Cause DSR to be run
412 ebsa285_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
414 serial_channel *chan = (serial_channel *)data;
415 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
416 cyg_drv_interrupt_mask(ebsa285_chan->tx.int_num);
417 cyg_drv_interrupt_acknowledge(ebsa285_chan->tx.int_num);
418 return CYG_ISR_CALL_DSR; // Cause DSR to be run
421 // Serial I/O - high level interrupt handlers (DSR)
423 ebsa285_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
425 serial_channel *chan = (serial_channel *)data;
426 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
427 if ((*SA110_UART_FLAG_REGISTER & SA110_RX_FIFO_STATUS_MASK) != SA110_RX_FIFO_EMPTY) {
430 c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
431 status = *SA110_UART_RXSTAT;
432 if ( 0 == (status & (SA110_UART_FRAMING_ERROR_MASK |
433 SA110_UART_PARITY_ERROR_MASK |
434 SA110_UART_OVERRUN_ERROR_MASK)) )
435 (chan->callbacks->rcv_char)(chan, c);
437 cyg_drv_interrupt_unmask(ebsa285_chan->rx.int_num);
441 ebsa285_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
443 serial_channel *chan = (serial_channel *)data;
444 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
445 if ((*SA110_UART_FLAG_REGISTER & SA110_TX_FIFO_STATUS_MASK) != SA110_TX_FIFO_BUSY) {
446 (chan->callbacks->xmt_char)(chan);
448 if ( ebsa285_chan->tx_active ) // it might be halted in callback above
449 cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
451 #endif // CYGPKG_IO_SERIAL_ARM_EBSA285
453 // ------------------------------------------------------------------------
454 // EOF ebsa285_serial.c