]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/hal/mn10300/asb2305/v2_0/src/ser_asb.c
Initial revision
[karo-tx-redboot.git] / packages / hal / mn10300 / asb2305 / v2_0 / src / ser_asb.c
1 //=============================================================================
2 //
3 //      ser_asb.c
4 //
5 //      Simple driver for the serial controllers on the AM33 ASB305 board
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 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):   dhowells
44 // Contributors:dmoseley, nickg, gthomas
45 // Date:        2001-05-18
46 // Description: Simple driver for the ASB2305 debug serial port
47 //
48 //####DESCRIPTIONEND####
49 //
50 //=============================================================================
51
52 #include <pkgconf/hal.h>
53
54 #include <cyg/hal/hal_arch.h>           // SAVE/RESTORE GP macros
55 #include <cyg/hal/hal_io.h>             // IO macros
56 #include <cyg/hal/hal_if.h>             // interface API
57 #include <cyg/hal/hal_intr.h>           // HAL_ENABLE/MASK/UNMASK_INTERRUPTS
58 #include <cyg/hal/hal_misc.h>           // Helper functions
59 #include <cyg/hal/drv_api.h>            // CYG_ISR_HANDLED
60
61 #if defined(CYGNUM_HAL_AM33_PLF_SERIAL_CHANNELS) && CYGNUM_HAL_AM33_PLF_SERIAL_CHANNELS > 0
62
63 /*---------------------------------------------------------------------------*/
64 /* From serial_16550.h */
65 #if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==9600
66 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
67 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x78
68 #endif
69 #if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==19200
70 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
71 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x3C
72 #endif
73 #if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==38400
74 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
75 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x1E
76 #endif
77 #if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==57600
78 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
79 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x14
80 #endif
81 #if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==115200
82 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
83 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x0A
84 #endif
85
86 #ifndef CYG_DEVICE_SERIAL_BAUD_MSB
87 #error Missing/incorrect serial baud rate defined - CDL error?
88 #endif
89
90 /*---------------------------------------------------------------------------*/
91 // Define the serial registers.
92 #define CYG_DEV_RBR 0x00   // receiver buffer register, read, dlab = 0
93 #define CYG_DEV_THR 0x00   // transmitter holding register, write, dlab = 0
94 #define CYG_DEV_DLL 0x00   // divisor latch (LS), read/write, dlab = 1
95 #define CYG_DEV_IER 0x04   // interrupt enable register, read/write, dlab = 0
96 #define CYG_DEV_DLM 0x04   // divisor latch (MS), read/write, dlab = 1
97 #define CYG_DEV_IIR 0x08   // interrupt identification register, read, dlab = 0
98 #define CYG_DEV_FCR 0x08   // fifo control register, write, dlab = 0
99 #define CYG_DEV_LCR 0x0C   // line control register, read/write
100 #define CYG_DEV_MCR 0x10   // modem control register, read/write
101 #define CYG_DEV_LSR 0x14   // line status register, read
102 #define CYG_DEV_MSR 0x18   // modem status register, read
103
104 // Interrupt Enable Register
105 #define SIO_IER_RCV 0x01
106 #define SIO_IER_XMT 0x02
107 #define SIO_IER_LS  0x04
108 #define SIO_IER_MS  0x08
109
110 // The line status register bits.
111 #define SIO_LSR_DR      0x01            // data ready
112 #define SIO_LSR_OE      0x02            // overrun error
113 #define SIO_LSR_PE      0x04            // parity error
114 #define SIO_LSR_FE      0x08            // framing error
115 #define SIO_LSR_BI      0x10            // break interrupt
116 #define SIO_LSR_THRE    0x20            // transmitter holding register empty
117 #define SIO_LSR_TEMT    0x40            // transmitter register empty
118 #define SIO_LSR_ERR     0x80            // any error condition
119
120 // The modem status register bits.
121 #define SIO_MSR_DCTS  0x01              // delta clear to send
122 #define SIO_MSR_DDSR  0x02              // delta data set ready
123 #define SIO_MSR_TERI  0x04              // trailing edge ring indicator
124 #define SIO_MSR_DDCD  0x08              // delta data carrier detect
125 #define SIO_MSR_CTS   0x10              // clear to send
126 #define SIO_MSR_DSR   0x20              // data set ready
127 #define SIO_MSR_RI    0x40              // ring indicator
128 #define SIO_MSR_DCD   0x80              // data carrier detect
129
130 // The line control register bits.
131 #define SIO_LCR_WLS0   0x01             // word length select bit 0
132 #define SIO_LCR_WLS1   0x02             // word length select bit 1
133 #define SIO_LCR_STB    0x04             // number of stop bits
134 #define SIO_LCR_PEN    0x08             // parity enable
135 #define SIO_LCR_EPS    0x10             // even parity select
136 #define SIO_LCR_SP     0x20             // stick parity
137 #define SIO_LCR_SB     0x40             // set break
138 #define SIO_LCR_DLAB   0x80             // divisor latch access bit
139
140 // Modem Control Register
141 #define SIO_MCR_DTR 0x01
142 #define SIO_MCR_RTS 0x02
143 #define SIO_MCR_INT 0x08   // Enable interrupts
144
145 #define LSR_WAIT_FOR(STATE) do { cyg_uint8 lsr; do { HAL_READ_UINT8(base+CYG_DEV_LSR, lsr); } while (!(lsr&SIO_LSR_##STATE)); } while(0)
146 #define LSR_QUERY(STATE) ({ cyg_uint8 lsr; HAL_READ_UINT8(base+CYG_DEV_LSR, lsr); (lsr&SIO_LSR_##STATE); })
147
148 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_RTSCTS
149 #define FLOWCTL_QUERY(LINE) ({ cyg_uint8 msr; HAL_READ_UINT8(base+CYG_DEV_MSR, msr); (msr&SIO_MSR_##LINE); })
150 #define FLOWCTL_WAIT_FOR(LINE) do { cyg_uint8 msr; do { HAL_READ_UINT8(base+CYG_DEV_MSR, msr); } while (!(msr&SIO_MSR_##LINE)); } while(0)
151 #define FLOWCTL_CLEAR(LINE) do { cyg_uint8 mcr; HAL_READ_UINT8(base+CYG_DEV_MCR,mcr); mcr &= ~SIO_MCR_##LINE; HAL_WRITE_UINT8(base+CYG_DEV_MCR, mcr); } while (0);
152 #define FLOWCTL_SET(LINE) do { cyg_uint8 mcr; HAL_READ_UINT8(base+CYG_DEV_MCR,mcr); mcr |= SIO_MCR_##LINE; HAL_WRITE_UINT8(base+CYG_DEV_MCR, mcr); } while (0);
153
154 #else
155 #define FLOWCTL_QUERY(LINE) 1
156 #define FLOWCTL_WAIT_FOR(LINE) do { ; } while(0)
157 #define FLOWCTL_CLEAR(LINE) do { ; } while(0)
158 #define FLOWCTL_SET(LINE) do { ; } while(0)
159
160 #endif
161
162 //-----------------------------------------------------------------------------
163 typedef struct {
164     cyg_uint8* base;
165     cyg_int32 msec_timeout;
166     int isr_vector;
167 } channel_data_t;
168
169 static channel_data_t asb2305_serial_channels[] = {
170     { (cyg_uint8*)0xA6FB0000, 1000, CYGNUM_HAL_INTERRUPT_SERIAL_0_RX }
171 };
172
173 //-----------------------------------------------------------------------------
174
175 static void
176 cyg_hal_plf_serial_init_channel(const void* __ch_data)
177 {
178     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
179     cyg_uint8 lcr;
180
181     // 8-1-no parity.
182     HAL_WRITE_UINT8(base+CYG_DEV_LCR, SIO_LCR_WLS0 | SIO_LCR_WLS1);
183
184     HAL_READ_UINT8(base+CYG_DEV_LCR, lcr);
185     lcr |= SIO_LCR_DLAB;
186     HAL_WRITE_UINT8(base+CYG_DEV_LCR, lcr);
187     HAL_WRITE_UINT8(base+CYG_DEV_DLL, CYG_DEVICE_SERIAL_BAUD_LSB);
188     HAL_WRITE_UINT8(base+CYG_DEV_DLM, CYG_DEVICE_SERIAL_BAUD_MSB);
189     lcr &= ~SIO_LCR_DLAB;
190     HAL_WRITE_UINT8(base+CYG_DEV_LCR, lcr);
191     HAL_WRITE_UINT8(base+CYG_DEV_FCR, 0x07);  // Enable & clear FIFO
192
193     FLOWCTL_CLEAR(DTR);
194     FLOWCTL_CLEAR(RTS);
195 }
196
197 static void
198 cyg_hal_plf_serial_putc_aux(cyg_uint8* base, char c)
199 {
200     LSR_WAIT_FOR(THRE);
201
202     FLOWCTL_WAIT_FOR(CTS);
203
204     HAL_WRITE_UINT8(base+CYG_DEV_THR, c);
205 }
206
207 void
208 cyg_hal_plf_serial_putc(void *__ch_data, char c)
209 {
210     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
211     CYGARC_HAL_SAVE_GP();
212
213     FLOWCTL_SET(DTR);
214
215     cyg_hal_plf_serial_putc_aux(base,c);
216
217     FLOWCTL_CLEAR(DTR);
218
219     CYGARC_HAL_RESTORE_GP();
220 }
221
222 static cyg_bool
223 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
224 {
225     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
226
227     if (!LSR_QUERY(DR))
228         return false;
229
230     HAL_READ_UINT8(base+CYG_DEV_RBR, *ch);
231
232     return true;
233 }
234
235 cyg_uint8
236 cyg_hal_plf_serial_getc(void* __ch_data)
237 {
238     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
239     cyg_uint8 ch;
240     CYGARC_HAL_SAVE_GP();
241
242     /* see if there's some cached data in the FIFO */
243     if (!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch)) {
244         /* there isn't - open the flood gates */
245         FLOWCTL_WAIT_FOR(DSR);
246         FLOWCTL_SET(RTS);
247
248         while (!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
249
250         FLOWCTL_CLEAR(RTS);
251     }
252
253     CYGARC_HAL_RESTORE_GP();
254     return ch;
255 }
256
257 static void
258 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf,
259                          cyg_uint32 __len)
260 {
261     cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
262     CYGARC_HAL_SAVE_GP();
263
264     FLOWCTL_SET(DTR);
265
266     while(__len-- > 0)
267         cyg_hal_plf_serial_putc_aux(__ch_data, *__buf++);
268
269     FLOWCTL_CLEAR(DTR);
270
271     CYGARC_HAL_RESTORE_GP();
272 }
273
274 static void
275 cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
276 {
277     CYGARC_HAL_SAVE_GP();
278
279     while(__len-- > 0)
280         *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
281
282     CYGARC_HAL_RESTORE_GP();
283 }
284
285 #define TM0MD 0xD4003000
286 #define TM0BR 0xD4003010
287 #define TM0BC 0xD4003020
288
289 cyg_bool
290 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
291 {
292 #if 1
293     int delay_count;
294     channel_data_t* chan = (channel_data_t*)__ch_data;
295     cyg_uint8* base = chan->base;
296     cyg_uint8 last, val;
297     cyg_bool res;
298     CYGARC_HAL_SAVE_GP();
299
300     /* see if there's any cached data in the FIFO */
301     res = cyg_hal_plf_serial_getc_nonblock(__ch_data,ch);
302     if (!res) {
303         /* there isn't - open the flood gates */
304         delay_count = chan->msec_timeout * 125; // want delay in 8uS steps
305
306         HAL_WRITE_UINT8(TM0BR,200); // IOCLK is 25MHz, we want 125KHz
307         HAL_WRITE_UINT8(TM0MD,0x40); // stop and load
308         HAL_WRITE_UINT8(TM0MD,0x80); // set source to be IOCLK and go
309         HAL_READ_UINT8(TM0BC,last);
310
311         while (delay_count>0 && !FLOWCTL_QUERY(DSR)) {
312                 HAL_READ_UINT8(TM0BC,val);
313                 if (val==last) continue;
314                 if (val>last)
315                         delay_count--; // count the underflows
316                 last = val;
317         }
318         if (delay_count==0)
319             goto timeout;
320
321         FLOWCTL_SET(RTS);
322
323         while (delay_count>0 && !LSR_QUERY(DR)) {
324                 HAL_READ_UINT8(TM0BC,val);
325                 if (val==last) continue;
326                 if (val>last)
327                         delay_count--; // count the underflows
328                 last = val;
329         }
330
331         FLOWCTL_CLEAR(RTS);
332
333         if (LSR_QUERY(DR)) {
334             HAL_READ_UINT8(base+CYG_DEV_RBR, *ch);
335             res = true;
336         }
337
338     timeout:
339         HAL_WRITE_UINT8(TM0MD,0x00); // stop h/w timer
340     }
341
342     CYGARC_HAL_RESTORE_GP();
343     return res;
344
345 #else
346     int delay_count;
347     channel_data_t* chan = (channel_data_t*)__ch_data;
348     cyg_uint8* base = chan->base;
349     cyg_bool res;
350     CYGARC_HAL_SAVE_GP();
351
352     /* see if there's some cached data in the FIFO */
353     res = cyg_hal_plf_serial_getc_nonblock(__ch_data,ch);
354     if (!res) {
355         /* there isn't - open the flood gates */
356         delay_count = chan->msec_timeout * 1000; // want delay in uS steps
357
358         for (; delay_count>0 && !FLOWCTL_QUERY(DSR); delay_count--)
359             CYGACC_CALL_IF_DELAY_US(1);
360         if (delay_count==0)
361             goto timeout;
362
363         FLOWCTL_SET(RTS);
364
365         for (; delay_count>0 && !LSR_QUERY(DR); delay_count--)
366             CYGACC_CALL_IF_DELAY_US(1);
367
368         FLOWCTL_CLEAR(RTS);
369
370         if (LSR_QUERY(DR)) {
371             HAL_READ_UINT8(base+CYG_DEV_RBR, *ch);
372             res = true;
373         }
374
375     }
376
377 timeout:
378     CYGARC_HAL_RESTORE_GP();
379     return res;
380 #endif
381 }
382
383 static int
384 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
385 {
386     static int irq_state = 0;
387     channel_data_t* chan = (channel_data_t*)__ch_data;
388     int ret = 0;
389     CYGARC_HAL_SAVE_GP();
390
391     switch (__func) {
392     case __COMMCTL_IRQ_ENABLE:
393         irq_state = 1;
394
395         HAL_WRITE_UINT8(chan->base+CYG_DEV_IER, SIO_IER_RCV);
396         HAL_WRITE_UINT8(chan->base+CYG_DEV_MCR, SIO_MCR_INT|SIO_MCR_DTR|SIO_MCR_RTS);
397
398         HAL_INTERRUPT_UNMASK(chan->isr_vector);
399         break;
400     case __COMMCTL_IRQ_DISABLE:
401         ret = irq_state;
402         irq_state = 0;
403
404         HAL_WRITE_UINT8(chan->base+CYG_DEV_IER, 0);
405
406         HAL_INTERRUPT_MASK(chan->isr_vector);
407         break;
408     case __COMMCTL_DBG_ISR_VECTOR:
409         ret = chan->isr_vector;
410         break;
411     case __COMMCTL_SET_TIMEOUT:
412     {
413         va_list ap;
414
415         va_start(ap, __func);
416
417         ret = chan->msec_timeout;
418         chan->msec_timeout = va_arg(ap, cyg_uint32);
419
420         va_end(ap);
421     }
422     default:
423         break;
424     }
425     CYGARC_HAL_RESTORE_GP();
426     return ret;
427 }
428
429 static int
430 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc,
431                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
432 {
433     int res = 0;
434     channel_data_t* chan = (channel_data_t*)__ch_data;
435     char c;
436     cyg_uint8 lsr;
437     CYGARC_HAL_SAVE_GP();
438
439     cyg_drv_interrupt_acknowledge(chan->isr_vector);
440
441     *__ctrlc = 0;
442     HAL_READ_UINT8(chan->base+CYG_DEV_LSR, lsr);
443     if ( (lsr & SIO_LSR_DR) != 0 ) {
444
445         HAL_READ_UINT8(chan->base+CYG_DEV_RBR, c);
446         if( cyg_hal_is_break( &c , 1 ) )
447             *__ctrlc = 1;
448
449         res = CYG_ISR_HANDLED;
450     }
451
452     CYGARC_HAL_RESTORE_GP();
453     return res;
454 }
455
456 static void
457 cyg_hal_plf_serial_init(void)
458 {
459     hal_virtual_comm_table_t* comm;
460     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
461
462     // Disable interrupts.
463     HAL_INTERRUPT_MASK(asb2305_serial_channels[0].isr_vector);
464
465     // Init channels
466     cyg_hal_plf_serial_init_channel(&asb2305_serial_channels[0]);
467
468     // Setup procs in the vector table
469
470     // Set channel 0
471     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
472     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
473     CYGACC_COMM_IF_CH_DATA_SET(*comm, &asb2305_serial_channels[0]);
474     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
475     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
476     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
477     CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
478     CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
479     CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
480     CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
481
482     // Restore original console
483     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
484 }
485
486 void
487 cyg_hal_plf_comms_init(void)
488 {
489     static int initialized = 0;
490
491     if (initialized)
492         return;
493
494     initialized = 1;
495
496     cyg_hal_plf_serial_init();
497
498 #if defined(CYGNUM_HAL_AM33_SERIAL_CHANNELS) && CYGNUM_HAL_AM33_SERIAL_CHANNELS > 0
499     cyg_hal_am33_serial_init(1);
500 #endif
501 }
502
503 #endif // defined(CYGNUM_HAL_AM33_PLF_SERIAL_CHANNELS) && CYGNUM_HAL_AM33_PLF_SERIAL_CHANNELS > 0
504
505 /*---------------------------------------------------------------------------*/
506 /* End of ser_asb.c */