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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [hal/] [powerpc/] [quicc/] [v2_0/] [src/] [quicc_smc1.c] - Blame information for rev 611

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      quicc_smc1.c
4
//
5
//      PowerPC QUICC basic Serial IO using port(s) SMC1/SMC2/SCC1/SCC2/SCC3
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
// Copyright (C) 2002, 2003 Gary Thomas
13
//
14
// eCos is free software; you can redistribute it and/or modify it under
15
// the terms of the GNU General Public License as published by the Free
16
// Software Foundation; either version 2 or (at your option) any later version.
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
// for more details.
22
//
23
// You should have received a copy of the GNU General Public License along
24
// with eCos; if not, write to the Free Software Foundation, Inc.,
25
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26
//
27
// As a special exception, if other files instantiate templates or use macros
28
// or inline functions from this file, or you compile this file and link it
29
// with other works to produce a work based on this file, this file does not
30
// by itself cause the resulting work to be covered by the GNU General Public
31
// License. However the source code for this file must still be made available
32
// in accordance with section (3) of the GNU General Public License.
33
//
34
// This exception does not invalidate any other reasons why a work based on
35
// this file might be covered by the GNU General Public License.
36
//
37
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38
// at http://sources.redhat.com/ecos/ecos-license/
39
// -------------------------------------------
40
//####ECOSGPLCOPYRIGHTEND####
41
//==========================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):    Red Hat
45
// Contributors: hmt, gthomas
46
// Date:         1999-06-08
47
// Purpose:      Provide basic Serial IO for MPC8xx boards (like Motorola MBX)
48
// Description:  Serial IO for MPC8xx boards which connect their debug channel
49
//               to SMCx or SCCx; or any QUICC user who wants to use SMCx/SCCx
50
// Usage:
51
// Notes:        
52
//
53
//####DESCRIPTIONEND####
54
//
55
//==========================================================================
56
 
57
#include <pkgconf/hal.h>
58
#include <pkgconf/hal_powerpc_quicc.h>
59
#include <cyg/infra/cyg_type.h>
60
#include <cyg/hal/hal_cache.h>
61
 
62
#include <cyg/hal/hal_arch.h>
63
 
64
#ifdef CYGPKG_HAL_POWERPC_MPC860
65
 
66
// eCos headers decribing PowerQUICC:
67
#include <cyg/hal/quicc/ppc8xx.h>
68
 
69
#include <cyg/hal/quicc/quicc_smc1.h>
70
 
71
#include <cyg/hal/hal_stub.h>           // target_register_t
72
#include <cyg/hal/hal_intr.h>           // HAL_INTERRUPT_UNMASK(...)
73
#include <cyg/hal/hal_if.h>             // Calling interface definitions
74
#include <cyg/hal/hal_misc.h>           // Helper functions
75
#include <cyg/hal/drv_api.h>            // CYG_ISR_HANDLED
76
#include <string.h>                     // memset
77
 
78
#define UART_BIT_RATE(n) (((int)(CYGHWR_HAL_POWERPC_BOARD_SPEED*1000000)/16)/n)
79
#define UART_BAUD_RATE CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD
80
 
81
// Note: buffers will be placed just after descriptors
82
// Sufficient space should be provided between descrptors
83
// for the buffers (single characters)
84
 
85
struct port_info {
86
    int                         Txnum;   // Number of Tx buffers
87
    int                         Rxnum;   // Number of Rx buffers
88
    int                         intnum;  // Interrupt bit
89
    int                         timeout; // Timeout in msec
90
    int                         pram;    // [Pointer] to PRAM data
91
    int                         regs;    // [Pointer] to control registers
92
    volatile struct cp_bufdesc *next_rxbd;
93
    int                         irq;     // Interrupt state
94
    int                         init;    // Has port been initialized?
95
};
96
 
97
static struct port_info ports[] = {
98
#if CYGNUM_HAL_QUICC_SMC1 > 0
99
    { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SMC1, 1000,
100
      (int)&((EPPC *)0)->pram[2].scc.pothers.smc_modem.psmc.u,
101
      (int)&((EPPC *)0)->smc_regs[0]
102
    },
103
#endif
104
#if CYGNUM_HAL_QUICC_SMC2 > 0
105
    { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SMC2_PIP, 1000,
106
      (int)&((EPPC *)0)->pram[3].scc.pothers.smc_modem.psmc.u,
107
      (int)&((EPPC *)0)->smc_regs[1]
108
    },
109
#endif
110
#if CYGNUM_HAL_QUICC_SCC1 > 0
111
    { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SCC1, 1000,
112
      (int)&((EPPC *)0)->pram[0].scc.pscc.u,
113
      (int)&((EPPC *)0)->scc_regs[0]
114
    },
115
#endif
116
#if CYGNUM_HAL_QUICC_SCC2 > 0
117
    { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SCC2, 1000,
118
      (int)&((EPPC *)0)->pram[1].scc.pscc.u,
119
      (int)&((EPPC *)0)->scc_regs[1]
120
    },
121
#endif
122
#if CYGNUM_HAL_QUICC_SCC3 > 0
123
    { 1, 4, CYGNUM_HAL_INTERRUPT_CPM_SCC3, 1000,
124
      (int)&((EPPC *)0)->pram[2].scc.pscc.u,
125
      (int)&((EPPC *)0)->scc_regs[2]
126
    },
127
#endif
128
};
129
 
130
// SMC Events (interrupts)
131
#define QUICC_SMCE_BRK 0x10  // Break received
132
#define QUICC_SMCE_BSY 0x04  // Busy - receive buffer overrun
133
#define QUICC_SMCE_TX  0x02  // Tx interrupt
134
#define QUICC_SMCE_RX  0x01  // Rx interrupt
135
 
136
/*
137
 *  Initialize SMCX as a uart.
138
 *
139
 *  Comments below reference Motorola's "MPC860 User Manual".
140
 *  The basic initialization steps are from Section 16.15.8
141
 *  of that manual.
142
 */
143
static void
144
cyg_hal_smcx_init_channel(struct port_info *info, int port)
145
{
146
    EPPC *eppc = eppc_base();
147
    int i;
148
    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
149
    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
150
    struct cp_bufdesc *txbd, *rxbd;
151
 
152
    if (info->init) return;
153
    info->init = 1;
154
 
155
    switch (port) {
156
#if CYGNUM_HAL_QUICC_SMC1 > 0
157
    case QUICC_CPM_SMC1:
158
        /*
159
         *  Set up the PortB pins for UART operation.
160
         *  Set PAR and DIR to allow SMCTXD1 and SMRXD1
161
         *  (Table 16-39)
162
         */
163
        eppc->pip_pbpar |= 0xc0;
164
        eppc->pip_pbdir &= ~0xc0;
165
 
166
        /* Configure baud rate generator (Section 16.13.2) */
167
        eppc->brgc1 = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
168
 
169
        /*
170
         *  NMSI mode, BRG1 to SMC1
171
         *  (Section 16.12.5.2)
172
         */
173
        eppc->si_simode = 0;
174
        break;
175
#endif
176
#if CYGNUM_HAL_QUICC_SMC2 > 0
177
    case QUICC_CPM_SMC2:
178
        /*
179
         *  Set up the PortA pins for UART operation.
180
         *  Set PAR and DIR to allow SMCTXD2 and SMRXD2
181
         *  (Table 16-39)
182
         */
183
        eppc->pio_papar |= 0xc0;
184
        eppc->pio_padir &= ~0xc0;
185
        eppc->pio_paodr &= ~0xc0;
186
 
187
        /* Configure baud rate generator (Section 16.13.2) */
188
        eppc->brgc1 = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
189
 
190
        /*
191
         *  NMSI mode, BRG1 to SMC2
192
         *  (Section 16.12.5.2)
193
         */
194
        eppc->si_simode = 0x00000000;
195
        break;
196
#endif
197
    }
198
 
199
    /*
200
     *  Set pointers to buffer descriptors.
201
     *  (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
202
     */
203
    uart_pram->rbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Rxnum + info->Rxnum);
204
    uart_pram->tbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Txnum + info->Txnum);
205
 
206
    /*
207
     *  SDMA & LCD bus request level 5
208
     *  (Section 16.10.2.1)
209
     */
210
    eppc->dma_sdcr = 1;
211
 
212
    /*
213
     *  Set Rx and Tx function code
214
     *  (Section 16.15.4.2)
215
     */
216
    uart_pram->rfcr = 0x18;
217
    uart_pram->tfcr = 0x18;
218
 
219
    /* max receive buffer length */
220
    uart_pram->mrblr = 1;
221
 
222
    /* disable max_idle feature */
223
    uart_pram->max_idl = 0;
224
 
225
    /* no last brk char received */
226
    uart_pram->brkln = 0;
227
 
228
    /* no break condition occurred */
229
    uart_pram->brkec = 0;
230
 
231
    /* 1 break char sent on top XMIT */
232
    uart_pram->brkcr = 1;
233
 
234
    /* setup RX buffer descriptors */
235
    rxbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
236
    info->next_rxbd = rxbd;
237
    for (i = 0;  i < info->Rxnum;  i++) {
238
        rxbd->length = 0;
239
        rxbd->buffer = ((char *)eppc + (uart_pram->rbase+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
240
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
241
        rxbd++;
242
    }
243
    rxbd--;
244
    rxbd->ctrl   |= QUICC_BD_CTL_Wrap;
245
 
246
    /* setup TX buffer descriptor */
247
    txbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
248
    txbd->length = 1;
249
    txbd->buffer = ((char *)eppc + (uart_pram->tbase+(info->Txnum*sizeof(struct cp_bufdesc))));
250
    txbd->ctrl   = 0x2000;
251
 
252
    /*
253
     *  Clear any previous events. Mask interrupts.
254
     *  (Section 16.15.7.14 and 16.15.7.15)
255
     */
256
    regs->smc_smce = 0xff;
257
    regs->smc_smcm = 1; // RX interrupts only, for ctrl-c
258
 
259
    /*
260
     *  Set 8,n,1 characters, then also enable rx and tx.
261
     *  (Section 16.15.7.11)
262
     */
263
    regs->smc_smcmr = 0x4820;
264
    regs->smc_smcmr = 0x4823;
265
 
266
    /*
267
     *  Init Rx & Tx params for SMCx
268
     */
269
    eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | port | QUICC_CPM_CR_BUSY;
270
 
271
    info->irq = 0;  // Interrupts not enabled
272
}
273
 
274
 
275
//#define UART_BUFSIZE 32
276
 
277
//static bsp_queue_t uart_queue;
278
//static char uart_buffer[UART_BUFSIZE];
279
 
280
#define QUICC_SMCE_TX     0x02    // Tx interrupt
281
#define QUICC_SMCE_RX     0x01    // Rx interrupt
282
#define QUICC_SMCMR_TEN       (1<<1)        // Enable transmitter
283
#define QUICC_SMCMR_REN       (1<<0)        // Enable receiver
284
 
285
#ifdef CYGDBG_DIAG_BUF
286
extern int enable_diag_uart;
287
#endif // CYGDBG_DIAG_BUF
288
 
289
static void
290
cyg_hal_smcx_putc(void* __ch_data, cyg_uint8 ch)
291
{
292
    volatile struct cp_bufdesc *bd, *first;
293
    EPPC *eppc = eppc_base();
294
    struct port_info *info = (struct port_info *)__ch_data;
295
    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
296
    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
297
    int timeout;
298
    int cache_state;
299
    CYGARC_HAL_SAVE_GP();
300
 
301
    /* tx buffer descriptor */
302
    bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbptr);
303
 
304
    // Scan for a free buffer
305
    first = bd;
306
    while (bd->ctrl & QUICC_BD_CTL_Ready) {
307
        if (bd->ctrl & QUICC_BD_CTL_Wrap) {
308
            bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
309
        } else {
310
            bd++;
311
        }
312
        if (bd == first) break;
313
    }
314
 
315
    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait for buffer free
316
    if (bd->ctrl & QUICC_BD_CTL_Int) {
317
        // This buffer has just completed interrupt output.  Reset bits
318
        bd->ctrl &= ~QUICC_BD_CTL_Int;
319
        bd->length = 0;
320
    }
321
 
322
    bd->length = 1;
323
    bd->buffer[0] = ch;
324
    bd->ctrl      |= QUICC_BD_CTL_Ready;
325
    // Flush cache if necessary - buffer may be in cacheable memory
326
    HAL_DCACHE_IS_ENABLED(cache_state);
327
    if (cache_state) {
328
      HAL_DCACHE_FLUSH(bd->buffer, 1);
329
    }
330
 
331
#ifdef CYGDBG_DIAG_BUF
332
        enable_diag_uart = 0;
333
#endif // CYGDBG_DIAG_BUF
334
    timeout = 0;
335
    while (bd->ctrl & QUICC_BD_CTL_Ready) {
336
// Wait until buffer free
337
        if (++timeout == 0x7FFFF) {
338
            // A really long time!
339
#ifdef CYGDBG_DIAG_BUF
340
            diag_printf("bd fail? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
341
#endif // CYGDBG_DIAG_BUF
342
            regs->smc_smcmr &= ~QUICC_SMCMR_TEN;  // Disable transmitter
343
            bd->ctrl &= ~QUICC_BD_CTL_Ready;
344
            regs->smc_smcmr |= QUICC_SMCMR_TEN;   // Enable transmitter
345
            bd->ctrl |= QUICC_BD_CTL_Ready;
346
            timeout = 0;
347
#ifdef CYGDBG_DIAG_BUF
348
            diag_printf("bd retry? bd: %x, ctrl: %x, tx state: %x\n", bd, bd->ctrl, uart_pram->tstate);
349
            first = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
350
            while (true) {
351
                diag_printf("bd: %x, ctrl: %x, length: %x\n", first, first->ctrl, first->length);
352
                if (first->ctrl & QUICC_BD_CTL_Wrap) break;
353
                first++;
354
            }
355
#endif // CYGDBG_DIAG_BUF
356
        }
357
    }
358
    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait until buffer free
359
    bd->length = 0;
360
#ifdef CYGDBG_DIAG_BUF
361
    enable_diag_uart = 1;
362
#endif // CYGDBG_DIAG_BUF
363
 
364
    CYGARC_HAL_RESTORE_GP();
365
}
366
 
367
 
368
/*
369
 * Get a character from a port, non-blocking
370
 * This function can be called on either an SMC or SCC port
371
 */
372
static cyg_bool
373
cyg_hal_sxx_getc_nonblock(void* __ch_data, cyg_uint8* ch)
374
{
375
    volatile struct cp_bufdesc *bd;
376
    EPPC *eppc = eppc_base();
377
    struct port_info *info = (struct port_info *)__ch_data;
378
    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
379
    int cache_state;
380
 
381
    /* rx buffer descriptor */
382
    bd = info->next_rxbd;
383
 
384
    if (bd->ctrl & QUICC_BD_CTL_Ready)
385
        return false;
386
 
387
    *ch = bd->buffer[0];
388
 
389
    bd->length = 0;
390
    bd->buffer[0] = '\0';
391
    bd->ctrl |= QUICC_BD_CTL_Ready;
392
    if (bd->ctrl & QUICC_BD_CTL_Wrap) {
393
        bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
394
    } else {
395
        bd++;
396
    }
397
    info->next_rxbd = bd;
398
 
399
    // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
400
    HAL_DCACHE_IS_ENABLED(cache_state);
401
    if (cache_state) {
402
        HAL_DCACHE_INVALIDATE(bd->buffer, uart_pram->mrblr);  // Make sure no stale data
403
    }
404
 
405
    return true;
406
}
407
 
408
/*
409
 * Get a character from a port, blocking
410
 * This function can be called on either an SMC or SCC port
411
 */
412
static cyg_uint8
413
cyg_hal_sxx_getc(void* __ch_data)
414
{
415
    cyg_uint8 ch;
416
    CYGARC_HAL_SAVE_GP();
417
 
418
    while(!cyg_hal_sxx_getc_nonblock(__ch_data, &ch));
419
 
420
    CYGARC_HAL_RESTORE_GP();
421
    return ch;
422
}
423
 
424
 
425
static void
426
cyg_hal_smcx_write(void* __ch_data, const cyg_uint8* __buf,
427
                         cyg_uint32 __len)
428
{
429
    CYGARC_HAL_SAVE_GP();
430
 
431
    while(__len-- > 0)
432
        cyg_hal_smcx_putc(__ch_data, *__buf++);
433
 
434
    CYGARC_HAL_RESTORE_GP();
435
}
436
 
437
/*
438
 * Read a sequence of characters from a port
439
 * This function can be called on either an SMC or SCC port
440
 */
441
static void
442
cyg_hal_sxx_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
443
{
444
    CYGARC_HAL_SAVE_GP();
445
 
446
    while(__len-- > 0)
447
        *__buf++ = cyg_hal_sxx_getc(__ch_data);
448
 
449
    CYGARC_HAL_RESTORE_GP();
450
}
451
 
452
/*
453
 * Read a character from a port, with a timeout
454
 * This function can be called on either an SMC or SCC port
455
 */
456
static cyg_bool
457
cyg_hal_sxx_getc_timeout(void* __ch_data, cyg_uint8* ch)
458
{
459
    struct port_info *info = (struct port_info *)__ch_data;
460
    int delay_count = info->timeout * 10; // delay in .1 ms steps
461
    cyg_bool res;
462
    CYGARC_HAL_SAVE_GP();
463
 
464
    for(;;) {
465
        res = cyg_hal_sxx_getc_nonblock(__ch_data, ch);
466
        if (res || 0 == delay_count--)
467
            break;
468
 
469
        CYGACC_CALL_IF_DELAY_US(100);
470
    }
471
 
472
    CYGARC_HAL_RESTORE_GP();
473
    return res;
474
}
475
 
476
/*
477
 * Control/query the state of a port
478
 * This function can be called on either an SMC or SCC port
479
 */
480
static int
481
cyg_hal_sxx_control(void *__ch_data, __comm_control_cmd_t __func, ...)
482
{
483
    struct port_info *info = (struct port_info *)__ch_data;
484
    int ret = 0;
485
    CYGARC_HAL_SAVE_GP();
486
 
487
    switch (__func) {
488
    case __COMMCTL_IRQ_ENABLE:
489
        HAL_INTERRUPT_UNMASK(info->intnum);
490
        info->irq = 1;
491
        break;
492
    case __COMMCTL_IRQ_DISABLE:
493
        ret = info->irq;
494
        info->irq = 0;
495
        HAL_INTERRUPT_MASK(info->intnum);
496
        break;
497
    case __COMMCTL_DBG_ISR_VECTOR:
498
        ret = info->intnum;
499
        break;
500
    case __COMMCTL_SET_TIMEOUT:
501
    {
502
        va_list ap;
503
 
504
        va_start(ap, __func);
505
 
506
        ret = info->timeout;
507
        info->timeout = va_arg(ap, cyg_uint32);
508
 
509
        va_end(ap);
510
    }
511
    default:
512
        break;
513
    }
514
    CYGARC_HAL_RESTORE_GP();
515
    return ret;
516
}
517
 
518
/*
519
 * Low-level interrupt (ISR) handler
520
 * This function can be called on only an SMC port
521
 */
522
static int
523
cyg_hal_smcx_isr(void *__ch_data, int* __ctrlc,
524
                 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
525
{
526
    EPPC *eppc = eppc_base();
527
    volatile struct cp_bufdesc *bd;
528
    struct port_info *info = (struct port_info *)__ch_data;
529
    volatile struct smc_regs *regs = (volatile struct smc_regs *)((char *)eppc + info->regs);
530
    volatile struct smc_uart_pram *uart_pram = (volatile struct smc_uart_pram *)((char *)eppc + info->pram);
531
    char ch;
532
    int res = 0;
533
    CYGARC_HAL_SAVE_GP();
534
 
535
    *__ctrlc = 0;
536
    if (regs->smc_smce & QUICC_SMCE_RX) {
537
 
538
        regs->smc_smce = QUICC_SMCE_RX;
539
 
540
        /* rx buffer descriptors */
541
        bd = info->next_rxbd;
542
 
543
        if ((bd->ctrl & QUICC_BD_CTL_Ready) == 0) {
544
 
545
            // then there be a character waiting
546
            ch = bd->buffer[0];
547
            bd->length = 1;
548
            bd->ctrl   |= QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
549
            if (bd->ctrl & QUICC_BD_CTL_Wrap) {
550
                bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
551
            } else {
552
                bd++;
553
            }
554
            info->next_rxbd = bd;
555
 
556
            if( cyg_hal_is_break( &ch , 1 ) )
557
                *__ctrlc = 1;
558
        }
559
 
560
        // Interrupt handled. Acknowledge it.
561
        HAL_INTERRUPT_ACKNOWLEDGE(info->intnum);
562
        res = CYG_ISR_HANDLED;
563
    }
564
 
565
    CYGARC_HAL_RESTORE_GP();
566
    return res;
567
}
568
 
569
#if (CYGNUM_HAL_QUICC_SCC1+CYGNUM_HAL_QUICC_SCC2+CYGNUM_HAL_QUICC_SCC3) > 0
570
/*
571
 *  Initialize an SCC as a uart.
572
 *
573
 *  Comments below reference Motorola's "MPC860 User Manual".
574
 *  The basic initialization steps are from Section 16.15.8
575
 *  of that manual.
576
 */
577
static void
578
cyg_hal_sccx_init_channel(struct port_info *info, int port)
579
{
580
    EPPC *eppc = eppc_base();
581
    int i;
582
    volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
583
    volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
584
    struct cp_bufdesc *txbd, *rxbd;
585
 
586
    if (info->init) return;
587
    info->init = 1;
588
 
589
    /*
590
     *  Set up the Port pins for UART operation.
591
     */
592
    switch (port) {
593
#if CYGNUM_HAL_QUICC_SCC1 > 0
594
    case QUICC_CPM_SCC1:
595
        eppc->pio_papar |= 0x03;
596
        eppc->pio_padir &= ~0x03;
597
        eppc->pio_paodr &= ~0x03;
598
 
599
        /* CTS on PortC.11 */
600
        eppc->pio_pcdir &= 0x800;
601
        eppc->pio_pcpar &= 0x800;
602
        eppc->pio_pcso  |= 0x800;
603
 
604
        /* RTS on PortB.19 */
605
        eppc->pip_pbpar |= 0x1000;
606
        eppc->pip_pbdir |= 0x1000;
607
 
608
        /* Configure baud rate generator (Section 16.13.2) */
609
        eppc->brgc2 = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
610
 
611
        /*
612
         *  NMSI mode, BRG2 to SCC1
613
         */
614
        eppc->si_sicr |= (1<<3)|(1<<0);
615
        break;
616
#endif
617
#if CYGNUM_HAL_QUICC_SCC2 > 0
618
    case QUICC_CPM_SCC2:
619
#error FIXME
620
        eppc->pio_papar |= 0x0C;
621
        eppc->pio_padir &= ~0x0C;
622
        eppc->pio_paodr &= ~0x0C;
623
 
624
        /* CTS on PortC.11 */
625
        eppc->pio_pcdir &= 0xC00;
626
        eppc->pio_pcpar &= 0xC00;
627
        eppc->pio_pcso  |= 0xC00;
628
 
629
        /* RTS on PortB.19 */
630
        eppc->pip_pbpar |= 0x2000;
631
        eppc->pip_pbdir |= 0x2000;
632
 
633
        /* Configure baud rate generator (Section 16.13.2) */
634
        eppc->brgc2 = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
635
 
636
        /*
637
         *  NMSI mode, BRG2 to SCC2
638
         */
639
        eppc->si_sicr |= (1<<11)|(1<<8);
640
        break;
641
#endif
642
#if CYGNUM_HAL_QUICC_SCC3 > 0
643
    case QUICC_CPM_SCC3:
644
#if 0
645
// CAUTION!  Enabling these bits made the port get stuck :-(
646
        /* CTS/RTS/CD on PortC.4/5/13 */
647
        eppc->pio_pcdir &= 0x0C04;
648
        eppc->pio_pcpar &= 0x0C00;
649
//        eppc->pio_pcpar |= 0x0004;
650
        eppc->pio_pcso  |= 0x0C00;
651
#endif
652
 
653
        /* RxD/TxD on PortB.24/25 */
654
        eppc->pip_pbpar |= 0x00C0;
655
        eppc->pip_pbdir |= 0x00C0;
656
        eppc->pip_pbodr &= ~0x00C0;
657
 
658
        /* Configure baud rate generator (Section 16.13.2) */
659
        eppc->brgc4 = 0x10000 | (UART_BIT_RATE(UART_BAUD_RATE)<<1);
660
 
661
        /*
662
         *  NMSI mode, BRG4 to SCC3
663
         */
664
        eppc->si_sicr &= ~(0xFF << 16);
665
        eppc->si_sicr |= (3<<19)|(3<<16);
666
        break;
667
#endif
668
    }
669
 
670
    /*
671
     *  Set pointers to buffer descriptors.
672
     */
673
    memset((void *)uart_pram, 0xFF, 0x100);
674
    uart_pram->rbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Rxnum + info->Rxnum);
675
    uart_pram->tbase = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*info->Txnum + info->Txnum);
676
 
677
    /*
678
     *  SDMA & LCD bus request level 5
679
     */
680
    eppc->dma_sdcr = 1;
681
 
682
    /*
683
     *  Set Rx and Tx function code
684
     */
685
    uart_pram->rfcr = 0x18;
686
    uart_pram->tfcr = 0x18;
687
 
688
    /* max receive buffer length */
689
    uart_pram->mrblr = 1;
690
 
691
    /* disable max_idle feature */
692
    uart_pram->max_idl = 0;
693
 
694
    /* no last brk char received */
695
    uart_pram->brkln = 0;
696
 
697
    /* no break condition occurred */
698
    uart_pram->brkec = 0;
699
 
700
    /* 1 break char sent on top XMIT */
701
    uart_pram->brkcr = 1;
702
 
703
    /* character mask */
704
    uart_pram->rccm  = 0xC0FF;
705
 
706
    /* control characters */
707
    for (i = 0;  i < 8;  i++) {
708
        uart_pram->cc[i] = 0x8000;  // Mark unused
709
    }
710
 
711
    /* setup RX buffer descriptors */
712
    rxbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
713
    info->next_rxbd = rxbd;
714
    for (i = 0;  i < info->Rxnum;  i++) {
715
        rxbd->length = 0;
716
        rxbd->buffer = ((char *)eppc + (uart_pram->rbase+(info->Rxnum*sizeof(struct cp_bufdesc))))+i;
717
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
718
        rxbd++;
719
    }
720
    rxbd--;
721
    rxbd->ctrl   |= QUICC_BD_CTL_Wrap;
722
 
723
    /* setup TX buffer descriptor */
724
    txbd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
725
    txbd->length = 0;
726
    txbd->buffer = ((char *)eppc + (uart_pram->tbase+(info->Txnum*sizeof(struct cp_bufdesc))));
727
    txbd->ctrl   = 0x2000;
728
 
729
    /*
730
     *  Clear any previous events. Mask interrupts.
731
     *  (Section 16.15.7.14 and 16.15.7.15)
732
     */
733
    regs->scc_scce = 0xffff;
734
    regs->scc_sccm = 1; // RX interrupts only, for ctrl-c
735
 
736
    /*
737
     *  Set 8,n,1 characters
738
     */
739
    regs->scc_psmr = (3<<12);
740
    regs->scc_gsmr_h = 0x20;          // 8bit FIFO
741
    regs->scc_gsmr_l = 0x00028004;    // 16x TxCLK, 16x RxCLK, UART
742
 
743
    /*
744
     *  Init Rx & Tx params for SCCX
745
     */
746
    eppc->cp_cr = QUICC_CPM_CR_INIT_TXRX | port | QUICC_CPM_CR_BUSY;
747
 
748
    regs->scc_gsmr_l |= 0x30;         // Enable Rx, Tx
749
 
750
    info->irq = 0;
751
}
752
 
753
static void
754
cyg_hal_sccx_putc(void* __ch_data, cyg_uint8 ch)
755
{
756
    volatile struct cp_bufdesc *bd, *first;
757
    EPPC *eppc = eppc_base();
758
    struct port_info *info = (struct port_info *)__ch_data;
759
    volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
760
    CYGARC_HAL_SAVE_GP();
761
 
762
    /* tx buffer descriptor */
763
    bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbptr);
764
 
765
    // Scan for a free buffer
766
    first = bd;
767
    while (bd->ctrl & QUICC_BD_CTL_Ready) {
768
        if (bd->ctrl & QUICC_BD_CTL_Wrap) {
769
            bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->tbase);
770
        } else {
771
            bd++;
772
        }
773
        if (bd == first) break;
774
    }
775
 
776
    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait for buffer free
777
    if (bd->ctrl & QUICC_BD_CTL_Int) {
778
        // This buffer has just completed interrupt output.  Reset bits
779
        bd->ctrl &= ~QUICC_BD_CTL_Int;
780
        bd->length = 0;
781
    }
782
 
783
    bd->length = 0;
784
    bd->buffer[bd->length++] = ch;
785
    bd->ctrl      |= QUICC_BD_CTL_Ready;
786
 
787
    while (bd->ctrl & QUICC_BD_CTL_Ready) ;  // Wait until buffer free
788
 
789
    CYGARC_HAL_RESTORE_GP();
790
}
791
 
792
static void
793
cyg_hal_sccx_write(void* __ch_data, const cyg_uint8* __buf,
794
                         cyg_uint32 __len)
795
{
796
    CYGARC_HAL_SAVE_GP();
797
 
798
    while(__len-- > 0)
799
        cyg_hal_sccx_putc(__ch_data, *__buf++);
800
 
801
    CYGARC_HAL_RESTORE_GP();
802
}
803
 
804
static int
805
cyg_hal_sccx_isr(void *__ch_data, int* __ctrlc,
806
                 CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
807
{
808
    EPPC *eppc = eppc_base();
809
    volatile struct cp_bufdesc *bd;
810
    struct port_info *info = (struct port_info *)__ch_data;
811
    volatile struct scc_regs *regs = (volatile struct scc_regs *)((char *)eppc + info->regs);
812
    volatile struct uart_pram *uart_pram = (volatile struct uart_pram *)((char *)eppc + info->pram);
813
    char ch;
814
    int res = 0;
815
    CYGARC_HAL_SAVE_GP();
816
 
817
    *__ctrlc = 0;
818
    if (regs->scc_scce & QUICC_SMCE_RX) {
819
 
820
        regs->scc_scce = QUICC_SMCE_RX;
821
 
822
        /* rx buffer descriptors */
823
        bd = info->next_rxbd;
824
 
825
        if ((bd->ctrl & QUICC_BD_CTL_Ready) == 0) {
826
 
827
            // then there be a character waiting
828
            ch = bd->buffer[0];
829
            bd->length = 1;
830
            bd->ctrl   |= QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
831
            if (bd->ctrl & QUICC_BD_CTL_Wrap) {
832
                bd = (struct cp_bufdesc *)((char *)eppc + uart_pram->rbase);
833
            } else {
834
                bd++;
835
            }
836
            info->next_rxbd = bd;
837
 
838
            if( cyg_hal_is_break( &ch , 1 ) )
839
                *__ctrlc = 1;
840
        }
841
 
842
        // Interrupt handled. Acknowledge it.
843
        HAL_INTERRUPT_ACKNOWLEDGE(info->intnum);
844
        res = CYG_ISR_HANDLED;
845
    }
846
 
847
    CYGARC_HAL_RESTORE_GP();
848
    return res;
849
}
850
#endif // CYGNUM_HAL_QUICC_SCCX
851
 
852
/*
853
 * Early initialization of comm channels. Must not rely
854
 * on interrupts, yet. Interrupt operation can be enabled
855
 * in _bsp_board_init().
856
 */
857
void
858
cyg_hal_plf_serial_init(void)
859
{
860
    hal_virtual_comm_table_t* comm;
861
    int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
862
 
863
    static int init = 0;  // It's wrong to do this more than once
864
    int chan = 0;
865
    if (init) return;
866
    init++;
867
 
868
    // Setup procs in the vector table
869
 
870
#if CYGNUM_HAL_QUICC_SMC1 > 0
871
    // Set up SMC1
872
    cyg_hal_smcx_init_channel(&ports[chan], QUICC_CPM_SMC1);
873
    CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
874
    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
875
    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
876
    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_smcx_write);
877
    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
878
    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_smcx_putc);
879
    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
880
    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
881
    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_smcx_isr);
882
    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
883
    chan++;
884
#endif
885
 
886
#if CYGNUM_HAL_QUICC_SMC2 > 0
887
    // Set up SMC2
888
    cyg_hal_smcx_init_channel(&ports[chan], QUICC_CPM_SMC2);
889
    CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
890
    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
891
    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
892
    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_smcx_write);
893
    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
894
    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_smcx_putc);
895
    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
896
    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
897
    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_smcx_isr);
898
    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
899
    chan++;
900
#endif
901
 
902
#if CYGNUM_HAL_QUICC_SCC1 > 0
903
    // Set  up SCC1
904
    cyg_hal_sccx_init_channel(&ports[chan], QUICC_CPM_SCC1);
905
    CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
906
    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
907
    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
908
    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sccx_write);
909
    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
910
    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sccx_putc);
911
    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
912
    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
913
    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_sccx_isr);
914
    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
915
    chan++;
916
#endif
917
 
918
#if CYGNUM_HAL_QUICC_SCC2 > 0
919
    // Set  up SCC2
920
    cyg_hal_sccx_init_channel(&ports[chan], QUICC_CPM_SCC2);
921
    CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
922
    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
923
    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
924
    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sccx_write);
925
    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
926
    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sccx_putc);
927
    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
928
    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
929
    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_sccx_isr);
930
    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
931
    chan++;
932
#endif
933
 
934
#if CYGNUM_HAL_QUICC_SCC3 > 0
935
    // Set  up SCC3
936
    cyg_hal_sccx_init_channel(&ports[chan], QUICC_CPM_SCC3);
937
    CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);// Should be configurable!
938
    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
939
    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ports[chan]);
940
    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_sccx_write);
941
    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_sxx_read);
942
    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_sccx_putc);
943
    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_sxx_getc);
944
    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_sxx_control);
945
    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_sccx_isr);
946
    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_sxx_getc_timeout);
947
    chan++;
948
#endif
949
 
950
    // Restore original console
951
    CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
952
}
953
 
954
#endif // CYGPKG_HAL_POWERPC_MPC860
955
// EOF quicc_smc1.c

powered by: WebSVN 2.1.0

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