OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [hal/] [mn10300/] [am33/] [v2_0/] [src/] [am33_serial.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//=============================================================================
2
//
3
//      am33_serial.c
4
//
5
//      Simple driver for the serial controllers on AM33 (MN103E) CPUs
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):   dmoseley, dhowells
44
// Contributors:msalter
45
// Date:        2002-11-15
46
// Description: Simple driver for the AM33 UARTs
47
//
48
//####DESCRIPTIONEND####
49
//
50
//=============================================================================
51
 
52
#include <pkgconf/hal.h>
53
#include CYGBLD_HAL_TARGET_H
54
#include CYGBLD_HAL_PLATFORM_H
55
 
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
62
 
63
#if !defined(CYGSEM_HAL_AM33_PLF_USES_SERIAL0) && !defined(CYGSEM_HAL_AM33_PLF_USES_SERIAL1)
64
#define AM33_NUM_UARTS 0
65
#elif defined(CYGSEM_HAL_AM33_PLF_USES_SERIAL0) && defined(CYGSEM_HAL_AM33_PLF_USES_SERIAL1)
66
#define AM33_NUM_UARTS 2
67
#else
68
#define AM33_NUM_UARTS 1
69
#endif
70
 
71
#if AM33_NUM_UARTS > 0
72
 
73
//-----------------------------------------------------------------------------
74
// Base Registers
75
#define AM33_SER0_BASE      0xD4002000
76
#define AM33_SER1_BASE      0xD4002010
77
 
78
/*---------------------------------------------------------------------------*/
79
// AM33 Serial line
80
 
81
#define _SERIAL_CR       0x00
82
#define _SERIAL_ICR      0x04
83
#define _SERIAL_TXR      0x08
84
#define _SERIAL_RXR      0x09
85
#define _SERIAL_SR       0x0c
86
 
87
#define SERIAL0_CR       ((volatile cyg_uint16 *)(AM33_SER0_BASE + _SERIAL_CR))
88
#define SERIAL0_ICR      ((volatile cyg_uint8 *) (AM33_SER0_BASE + _SERIAL_ICR))
89
#define SERIAL0_TXR      ((volatile cyg_uint8 *) (AM33_SER0_BASE + _SERIAL_TXR))
90
#define SERIAL0_RXR      ((volatile cyg_uint8 *) (AM33_SER0_BASE + _SERIAL_RXR))
91
#define SERIAL0_SR       ((volatile cyg_uint16 *)(AM33_SER0_BASE + _SERIAL_SR))
92
 
93
#define SERIAL1_CR       ((volatile cyg_uint16 *)(AM33_SER1_BASE + _SERIAL_CR))
94
#define SERIAL1_ICR      ((volatile cyg_uint8 *) (AM33_SER1_BASE + _SERIAL_ICR))
95
#define SERIAL1_TXR      ((volatile cyg_uint8 *) (AM33_SER1_BASE + _SERIAL_TXR))
96
#define SERIAL1_RXR      ((volatile cyg_uint8 *) (AM33_SER1_BASE + _SERIAL_RXR))
97
#define SERIAL1_SR       ((volatile cyg_uint16 *)(AM33_SER1_BASE + _SERIAL_SR))
98
 
99
// Timer 0 provides a prescaler for lower baud rates
100
#define TIMER0_MD       ((volatile cyg_uint8 *)0xd4003000)
101
#define TIMER0_BR       ((volatile cyg_uint8 *)0xd4003010)
102
 
103
// Timer 2 provides baud rate divisor
104
#define TIMER2_MD       ((volatile cyg_uint8 *)0xd4003002)
105
#define TIMER2_BR       ((volatile cyg_uint8 *)0xd4003012)
106
 
107
// Timer 1 provides a prescaler for lower baud rates
108
#define TIMER1_MD       ((volatile cyg_uint8 *)0xd4003001)
109
#define TIMER1_BR       ((volatile cyg_uint8 *)0xd4003011)
110
 
111
// Timer 3 provides baud rate divisor
112
#define TIMER3_MD       ((volatile cyg_uint8 *)0xd4003003)
113
#define TIMER3_BR       ((volatile cyg_uint8 *)0xd4003013)
114
 
115
#define SIO_LSTAT_TRDY  0x20
116
#define SIO_LSTAT_RRDY  0x10
117
 
118
#define SIO_INT_ENABLE  0x11
119
 
120
#define TMR_ENABLE                   0x80
121
#define TMR_SRC_IOCLOCK              0x00
122
#define TMR_SRC_TMR0_UNDERFLOW       0x04
123
 
124
 
125
//-----------------------------------------------------------------------------
126
 
127
typedef struct {
128
    cyg_uint8* base;
129
    cyg_int32 msec_timeout;
130
    int isr_vector;
131
    cyg_int32 baud_rate;
132
} channel_data_t;
133
 
134
static channel_data_t channels[AM33_NUM_UARTS] = {
135
#if defined(CYGSEM_HAL_AM33_PLF_USES_SERIAL0) && !defined(HAL_PLATFORM_SERIAL1_FIRST)
136
    { (cyg_uint8*)AM33_SER0_BASE, 1000, CYGNUM_HAL_INTERRUPT_SERIAL_0_RX },
137
#endif
138
#ifdef CYGSEM_HAL_AM33_PLF_USES_SERIAL1
139
    { (cyg_uint8*)AM33_SER1_BASE, 1000, CYGNUM_HAL_INTERRUPT_SERIAL_1_RX },
140
#endif
141
#if defined(CYGSEM_HAL_AM33_PLF_USES_SERIAL0) && defined(HAL_PLATFORM_SERIAL1_FIRST)
142
    { (cyg_uint8*)AM33_SER0_BASE, 1000, CYGNUM_HAL_INTERRUPT_SERIAL_0_RX },
143
#endif
144
};
145
 
146
//-----------------------------------------------------------------------------
147
// Set the baud rate
148
 
149
static cyg_uint32
150
baud_divisor(int baud, int prescaler)
151
{
152
    cyg_uint32 divisor;
153
 
154
    // divisor == INT(IOCLK/baud/8 + 0.5)
155
    divisor = CYGHWR_HAL_MN10300_IOCLK_SPEED * 10;
156
    divisor /= (baud / 100);
157
    divisor /= prescaler;
158
    divisor /= 8;
159
    divisor += 500;
160
    divisor /= 1000;
161
    return divisor;
162
}
163
 
164
static int
165
cyg_hal_plf_serial_set_baud(cyg_uint8* port, cyg_uint32 baud_rate)
166
{
167
    volatile cyg_uint8 *timer_base_reg;
168
    volatile cyg_uint8 *timer_mode_reg;
169
    cyg_uint32 divisor, prescaler;
170
 
171
    if (port == (cyg_uint8*)AM33_SER0_BASE)
172
    {
173
        // SER0 uses TMR2
174
        timer_base_reg = TIMER2_BR;
175
        timer_mode_reg = TIMER2_MD;
176
    } else if (port == (cyg_uint8*)AM33_SER1_BASE) {
177
        // SER1 uses TMR3
178
        timer_base_reg = TIMER3_BR;
179
        timer_mode_reg = TIMER3_MD;
180
    } else {
181
        // Unknown port.
182
        return -1;
183
    }
184
 
185
    switch (baud_rate)
186
    {
187
    case 1200:
188
    case 2400:
189
    case 4800:
190
    case 9600:
191
    case 19200:
192
    case 38400:
193
    case 57600:
194
    case 115200:
195
    case 230400:
196
        break;
197
 
198
    default:
199
        // Unknown baud.  Don't change anything
200
        return -1;
201
    }
202
 
203
    for (prescaler = 1; prescaler <= 256; prescaler++) {
204
        divisor = baud_divisor(baud_rate, prescaler);
205
        if (divisor <= 256)
206
            break;
207
    }
208
    --divisor;
209
    --prescaler;
210
 
211
    if (prescaler) {
212
        HAL_WRITE_UINT8(TIMER0_BR, prescaler);
213
        HAL_WRITE_UINT8(TIMER0_MD, TMR_ENABLE | TMR_SRC_IOCLOCK);
214
    } else {
215
        HAL_WRITE_UINT8(TIMER0_BR, 0);
216
        HAL_WRITE_UINT8(TIMER0_MD, 0);
217
    }
218
 
219
    HAL_WRITE_UINT8(timer_base_reg, divisor);
220
    HAL_WRITE_UINT8(timer_mode_reg, TMR_ENABLE |
221
                    (prescaler ? TMR_SRC_TMR0_UNDERFLOW : TMR_SRC_IOCLOCK));
222
 
223
    return 0;
224
}
225
 
226
//-----------------------------------------------------------------------------
227
// The minimal init, get and put functions. All by polling.
228
 
229
static void
230
cyg_hal_plf_serial_init_channel(void* __ch_data)
231
{
232
    cyg_uint8* port;
233
 
234
    // Some of the diagnostic print code calls through here with no idea what the ch_data is.
235
    // Go ahead and assume it is channels[0].
236
    if (__ch_data == 0)
237
      __ch_data = (void*)&channels[0];
238
 
239
    port = ((channel_data_t*)__ch_data)->base;
240
 
241
    // No interrupts for now.
242
    HAL_WRITE_UINT8(port + _SERIAL_ICR, 0x00);
243
 
244
    // Source from timer 2 or 3, 8bit chars, enable tx and rx
245
    HAL_WRITE_UINT16(port + _SERIAL_CR, 0xc085);
246
}
247
 
248
static void
249
cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 __ch)
250
{
251
    cyg_uint8* port;
252
    cyg_uint16 _status;
253
 
254
    // Some of the diagnostic print code calls through here with no idea what the ch_data is.
255
    // Go ahead and assume it is channels[0].
256
    if (__ch_data == 0)
257
      __ch_data = (void*)&channels[0];
258
 
259
    port = ((channel_data_t*)__ch_data)->base;
260
 
261
    do {
262
        HAL_READ_UINT16(port + _SERIAL_SR, _status);
263
    } while ((_status & SIO_LSTAT_TRDY) != 0);
264
 
265
    HAL_WRITE_UINT8(port + _SERIAL_TXR, __ch);
266
}
267
 
268
static cyg_bool
269
cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
270
{
271
    cyg_uint8* port;
272
    cyg_uint8 _status;
273
 
274
    // Some of the diagnostic print code calls through here with no idea what the ch_data is.
275
    // Go ahead and assume it is channels[0].
276
    if (__ch_data == 0)
277
      __ch_data = (void*)&channels[0];
278
 
279
    port = ((channel_data_t*)__ch_data)->base;
280
 
281
    HAL_READ_UINT8(port + _SERIAL_SR, _status);
282
    if ((_status & SIO_LSTAT_RRDY) == 0)
283
        return false;
284
 
285
    HAL_READ_UINT8(port + _SERIAL_RXR, *ch);
286
 
287
    // We must ack the interrupt caused by that read to avoid
288
    // confusing the GDB stub ROM.
289
    HAL_INTERRUPT_ACKNOWLEDGE( CYGNUM_HAL_INTERRUPT_SERIAL_0_RX );
290
 
291
    return true;
292
}
293
 
294
static cyg_uint8
295
cyg_hal_plf_serial_getc(void* __ch_data)
296
{
297
    cyg_uint8 ch;
298
    CYGARC_HAL_SAVE_GP();
299
 
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].
302
    if (__ch_data == 0)
303
      __ch_data = (void*)&channels[0];
304
 
305
    while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
306
 
307
    CYGARC_HAL_RESTORE_GP();
308
    return ch;
309
}
310
 
311
static void
312
cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf,
313
                         cyg_uint32 __len)
314
{
315
    CYGARC_HAL_SAVE_GP();
316
 
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].
319
    if (__ch_data == 0)
320
      __ch_data = (void*)&channels[0];
321
 
322
    while(__len-- > 0)
323
        cyg_hal_plf_serial_putc(__ch_data, *__buf++);
324
 
325
    CYGARC_HAL_RESTORE_GP();
326
}
327
 
328
static void
329
cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
330
{
331
    CYGARC_HAL_SAVE_GP();
332
 
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].
335
    if (__ch_data == 0)
336
      __ch_data = (void*)&channels[0];
337
 
338
    while(__len-- > 0)
339
        *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
340
 
341
    CYGARC_HAL_RESTORE_GP();
342
}
343
 
344
static cyg_bool
345
cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
346
{
347
    int delay_count;
348
    channel_data_t* chan;
349
    cyg_bool res;
350
    CYGARC_HAL_SAVE_GP();
351
 
352
    // Some of the diagnostic print code calls through here with no idea what the ch_data is.
353
    // Go ahead and assume it is channels[0].
354
    if (__ch_data == 0)
355
      __ch_data = (void*)&channels[0];
356
 
357
    chan = (channel_data_t*)__ch_data;
358
 
359
    delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
360
 
361
    for(;;) {
362
        res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
363
        if (res || 0 == delay_count--)
364
            break;
365
        CYGACC_CALL_IF_DELAY_US(100);
366
    }
367
 
368
    CYGARC_HAL_RESTORE_GP();
369
    return res;
370
}
371
 
372
static int
373
cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
374
{
375
    static int irq_state = 0;
376
    channel_data_t* chan;
377
    cyg_uint8 icr;
378
    int ret = 0;
379
    CYGARC_HAL_SAVE_GP();
380
 
381
    // Some of the diagnostic print code calls through here with no idea what the ch_data is.
382
    // Go ahead and assume it is channels[0].
383
    if (__ch_data == 0)
384
      __ch_data = (void*)&channels[0];
385
 
386
    chan = (channel_data_t*)__ch_data;
387
 
388
    switch (__func) {
389
    case __COMMCTL_IRQ_ENABLE:
390
        irq_state = 1;
391
 
392
        HAL_READ_UINT8(chan->base + _SERIAL_ICR, icr);
393
        icr |= SIO_INT_ENABLE;
394
        HAL_WRITE_UINT8(chan->base + _SERIAL_ICR, icr);
395
 
396
        HAL_INTERRUPT_SET_LEVEL(chan->isr_vector, 1);
397
        HAL_INTERRUPT_UNMASK(chan->isr_vector);
398
        break;
399
 
400
    case __COMMCTL_IRQ_DISABLE:
401
        ret = irq_state;
402
        irq_state = 0;
403
 
404
        HAL_READ_UINT8(chan->base + _SERIAL_ICR, icr);
405
        icr &= ~SIO_INT_ENABLE;
406
        HAL_WRITE_UINT8(chan->base + _SERIAL_ICR, icr);
407
 
408
        HAL_INTERRUPT_MASK(chan->isr_vector);
409
        break;
410
 
411
    case __COMMCTL_DBG_ISR_VECTOR:
412
        ret = chan->isr_vector;
413
        break;
414
 
415
    case __COMMCTL_SET_TIMEOUT:
416
    {
417
        va_list ap;
418
 
419
        va_start(ap, __func);
420
 
421
        ret = chan->msec_timeout;
422
        chan->msec_timeout = va_arg(ap, cyg_uint32);
423
 
424
        va_end(ap);
425
    }
426
    break;
427
 
428
    case __COMMCTL_SETBAUD:
429
    {
430
        cyg_uint32 baud_rate;
431
        cyg_uint8* port = chan->base;
432
        va_list ap;
433
 
434
        va_start(ap, __func);
435
        baud_rate = va_arg(ap, cyg_uint32);
436
        va_end(ap);
437
 
438
        // Disable port interrupts while changing hardware
439
        HAL_READ_UINT8(port + _SERIAL_ICR, icr);
440
        HAL_WRITE_UINT8(port + _SERIAL_ICR, 0);
441
 
442
        // Set baud rate.
443
        ret = cyg_hal_plf_serial_set_baud(port, baud_rate);
444
 
445
        // Reenable interrupts if necessary
446
        HAL_WRITE_UINT8(port + _SERIAL_ICR, icr);
447
    }
448
    break;
449
 
450
    case __COMMCTL_GETBAUD:
451
        break;
452
 
453
    default:
454
        break;
455
    }
456
 
457
    CYGARC_HAL_RESTORE_GP();
458
    return ret;
459
}
460
 
461
static int
462
cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc,
463
                       CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
464
{
465
    int res = 0;
466
    channel_data_t* chan;
467
    CYGARC_HAL_SAVE_GP();
468
 
469
    // Some of the diagnostic print code calls through here with no idea what the ch_data is.
470
    // Go ahead and assume it is channels[0].
471
    if (__ch_data == 0)
472
      __ch_data = (void*)&channels[0];
473
 
474
    chan = (channel_data_t*)__ch_data;
475
 
476
    HAL_INTERRUPT_ACKNOWLEDGE(chan->isr_vector);
477
 
478
#if 0
479
    HAL_READ_UINT8(chan->base + SER_16550_IIR, _iir);
480
    _iir &= SIO_IIR_ID_MASK;
481
 
482
    *__ctrlc = 0;
483
    if ((_iir == ISR_Rx_Avail) || (_iir == ISR_Rx_Char_Timeout)) {
484
 
485
        HAL_READ_UINT8(chan->base + SER_16550_RBR, c);
486
 
487
        if( cyg_hal_is_break( &c , 1 ) )
488
            *__ctrlc = 1;
489
 
490
        res = CYG_ISR_HANDLED;
491
    }
492
#endif
493
 
494
    CYGARC_HAL_RESTORE_GP();
495
    return res;
496
}
497
 
498
 
499
void
500
cyg_hal_am33_serial_init(int first_chan)
501
{
502
    hal_virtual_comm_table_t* comm;
503
    int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
504
    int i;
505
 
506
    for (i = 0; i < AM33_NUM_UARTS; i++) {
507
 
508
        // Disable interrupts.
509
        HAL_INTERRUPT_MASK(channels[0].isr_vector);
510
 
511
        // Init channel
512
        cyg_hal_plf_serial_init_channel((void*)&channels[i]);
513
        cyg_hal_plf_serial_set_baud(channels[i].base, CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD);
514
 
515
        // Setup procs in the vector table
516
        CYGACC_CALL_IF_SET_CONSOLE_COMM(i + first_chan);
517
        comm = CYGACC_CALL_IF_CONSOLE_PROCS();
518
        CYGACC_COMM_IF_CH_DATA_SET(*comm, &channels[i]);
519
        CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
520
        CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
521
        CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
522
        CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
523
        CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
524
        CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
525
        CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
526
    }
527
 
528
    // Restore original console
529
    CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
530
}
531
 
532
void
533
cyg_hal_plf_serial_setbaud(void *__ch_data, cyg_uint32 baud_rate)
534
{
535
    cyg_uint8* port;
536
 
537
    // Some of the diagnostic print code calls through here with no idea what the ch_data is.
538
    // Go ahead and assume it is channels[0].
539
    if (__ch_data == 0)
540
      __ch_data = (void*)&channels[0];
541
 
542
    port = ((channel_data_t*)__ch_data)->base;
543
 
544
    cyg_hal_plf_serial_set_baud(port, baud_rate);
545
}
546
 
547
 
548
// If the platform provides some channels of its own, then this function will be
549
// provided by that platform.
550
#if !defined(CYGNUM_HAL_AM33_PLF_SERIAL_CHANNELS) || !CYGNUM_HAL_AM33_PLF_SERIAL_CHANNELS 
551
void
552
cyg_hal_plf_comms_init(void)
553
{
554
    static int initialized = 0;
555
 
556
    if (initialized)
557
        return;
558
 
559
    initialized = 1;
560
 
561
    cyg_hal_am33_serial_init(0);
562
}
563
#endif
564
 
565
#endif // AM33_NUM_UARTS > 0
566
 
567
/*---------------------------------------------------------------------------*/
568
/* End of am33_serial.c */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.