OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [serial/] [powerpc/] [quicc/] [v2_0/] [src/] [quicc_smc_serial.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      io/serial/powerpc/quicc_smc_serial.c
4
//
5
//      PowerPC QUICC (SMC) Serial I/O Interface Module (interrupt driven)
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) 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):    gthomas
45
// Contributors: gthomas
46
// Date:         1999-06-20
47
// Purpose:      QUICC SMC Serial I/O module (interrupt driven version)
48
// Description: 
49
//
50
//####DESCRIPTIONEND####
51
//
52
//==========================================================================
53
 
54
#include <pkgconf/system.h>
55
#include <pkgconf/io_serial.h>
56
#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>
62
#include <cyg/hal/hal_cache.h>
63
#include <cyg/hal/quicc/ppc8xx.h>
64
#include CYGBLD_HAL_PLATFORM_H
65
 
66
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC
67
 
68
// macro for aligning buffers to cache lines
69
#define ALIGN_TO_CACHELINES(b) ((cyg_uint8 *)(((CYG_ADDRESS)(b) + (HAL_DCACHE_LINE_SIZE-1)) & ~(HAL_DCACHE_LINE_SIZE-1)))
70
 
71
// Buffer descriptor control bits
72
#define QUICC_BD_CTL_Ready 0x8000  // Buffer contains data (tx) or is empty (rx)
73
#define QUICC_BD_CTL_Wrap  0x2000  // Last buffer in list
74
#define QUICC_BD_CTL_Int   0x1000  // Generate interrupt when empty (tx) or full (rx)
75
#define QUICC_BD_CTL_MASK  0xB000  // User settable bits
76
 
77
// SMC Mode Register
78
#define QUICC_SMCMR_CLEN(n)   ((n+1)<<11)   // Character length
79
#define QUICC_SMCMR_SB(n)     ((n-1)<<10)   // Stop bits (1 or 2)
80
#define QUICC_SMCMR_PE(n)     (n<<9)        // Parity enable (0=disable, 1=enable)
81
#define QUICC_SMCMR_PM(n)     (n<<8)        // Parity mode (0=odd, 1=even)
82
#define QUICC_SMCMR_UART      (2<<4)        // UART mode
83
#define QUICC_SMCMR_TEN       (1<<1)        // Enable transmitter
84
#define QUICC_SMCMR_REN       (1<<0)        // Enable receiver
85
 
86
// SMC Events (interrupts)
87
#define QUICC_SMCE_BRK 0x10  // Break received
88
#define QUICC_SMCE_BSY 0x04  // Busy - receive buffer overrun
89
#define QUICC_SMCE_TX  0x02  // Tx interrupt
90
#define QUICC_SMCE_RX  0x01  // Rx interrupt
91
 
92
// SMC Commands
93
#define QUICC_SMC_CMD_InitTxRx  (0<<8)
94
#define QUICC_SMC_CMD_InitTx    (1<<8)
95
#define QUICC_SMC_CMD_InitRx    (2<<8)
96
#define QUICC_SMC_CMD_StopTx    (4<<8)
97
#define QUICC_SMC_CMD_RestartTx (6<<8)
98
#define QUICC_SMC_CMD_Reset     0x8000
99
#define QUICC_SMC_CMD_Go        0x0001
100
 
101
#include "quicc_smc_serial.h"
102
 
103
typedef struct quicc_smc_serial_info {
104
    CYG_ADDRWORD          channel;                   // Which channel SMC1/SMC2
105
    CYG_WORD              int_num;                   // Interrupt number
106
    cyg_uint32            *brg;                      // Which baud rate generator
107
    volatile struct smc_uart_pram  *pram;            // Parameter RAM pointer
108
    volatile struct smc_regs       *ctl;             // SMC control registers
109
    volatile struct cp_bufdesc     *txbd, *rxbd;     // Next Tx,Rx descriptor to use
110
    struct cp_bufdesc     *tbase, *rbase;            // First Tx,Rx descriptor
111
    int                   txsize, rxsize;            // Length of individual buffers
112
    cyg_interrupt         serial_interrupt;
113
    cyg_handle_t          serial_interrupt_handle;
114
} quicc_smc_serial_info;
115
 
116
static bool quicc_smc_serial_init(struct cyg_devtab_entry *tab);
117
static bool quicc_smc_serial_putc(serial_channel *chan, unsigned char c);
118
static Cyg_ErrNo quicc_smc_serial_lookup(struct cyg_devtab_entry **tab,
119
                                   struct cyg_devtab_entry *sub_tab,
120
                                   const char *name);
121
static unsigned char quicc_smc_serial_getc(serial_channel *chan);
122
static Cyg_ErrNo quicc_smc_serial_set_config(serial_channel *chan,
123
                                             cyg_uint32 key, const void *xbuf,
124
                                             cyg_uint32 *len);
125
static void quicc_smc_serial_start_xmit(serial_channel *chan);
126
static void quicc_smc_serial_stop_xmit(serial_channel *chan);
127
 
128
static cyg_uint32 quicc_smc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
129
static void       quicc_smc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
130
 
131
static SERIAL_FUNS(quicc_smc_serial_funs,
132
                   quicc_smc_serial_putc,
133
                   quicc_smc_serial_getc,
134
                   quicc_smc_serial_set_config,
135
                   quicc_smc_serial_start_xmit,
136
                   quicc_smc_serial_stop_xmit
137
    );
138
 
139
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
140
static quicc_smc_serial_info quicc_smc_serial_info1 = {
141
    0x90,                         // Channel indicator
142
    CYGNUM_HAL_INTERRUPT_CPM_SMC1 // interrupt
143
};
144
#if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE > 0
145
static unsigned char quicc_smc_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
146
static unsigned char quicc_smc_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BUFSIZE];
147
 
148
static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_smc_serial_channel1,
149
                                       quicc_smc_serial_funs,
150
                                       quicc_smc_serial_info1,
151
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BAUD),
152
                                       CYG_SERIAL_STOP_DEFAULT,
153
                                       CYG_SERIAL_PARITY_DEFAULT,
154
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
155
                                       CYG_SERIAL_FLAGS_DEFAULT,
156
                                       &quicc_smc_serial_out_buf1[0], sizeof(quicc_smc_serial_out_buf1),
157
                                       &quicc_smc_serial_in_buf1[0], sizeof(quicc_smc_serial_in_buf1)
158
    );
159
#else
160
static SERIAL_CHANNEL(quicc_smc_serial_channel1,
161
                      quicc_smc_serial_funs,
162
                      quicc_smc_serial_info1,
163
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BAUD),
164
                      CYG_SERIAL_STOP_DEFAULT,
165
                      CYG_SERIAL_PARITY_DEFAULT,
166
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
167
                      CYG_SERIAL_FLAGS_DEFAULT
168
    );
169
#endif
170
 
171
static unsigned char quicc_smc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
172
static unsigned char quicc_smc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
173
 
174
DEVTAB_ENTRY(quicc_smc_serial_io1,
175
             CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_NAME,
176
             0,                     // Does not depend on a lower level interface
177
             &cyg_io_serial_devio,
178
             quicc_smc_serial_init,
179
             quicc_smc_serial_lookup,     // Serial driver may need initializing
180
             &quicc_smc_serial_channel1
181
    );
182
#endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
183
 
184
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
185
static quicc_smc_serial_info quicc_smc_serial_info2 = {
186
    0xD0,                             // Channel indicator
187
    CYGNUM_HAL_INTERRUPT_CPM_SMC2_PIP // interrupt
188
};
189
#if CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE > 0
190
static unsigned char quicc_smc_serial_out_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
191
static unsigned char quicc_smc_serial_in_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BUFSIZE];
192
 
193
static SERIAL_CHANNEL_USING_INTERRUPTS(quicc_smc_serial_channel2,
194
                                       quicc_smc_serial_funs,
195
                                       quicc_smc_serial_info2,
196
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BAUD),
197
                                       CYG_SERIAL_STOP_DEFAULT,
198
                                       CYG_SERIAL_PARITY_DEFAULT,
199
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
200
                                       CYG_SERIAL_FLAGS_DEFAULT,
201
                                       &quicc_smc_serial_out_buf2[0], sizeof(quicc_smc_serial_out_buf2),
202
                                       &quicc_smc_serial_in_buf2[0], sizeof(quicc_smc_serial_in_buf2)
203
    );
204
#else
205
static SERIAL_CHANNEL(quicc_smc_serial_channel2,
206
                      quicc_smc_serial_funs,
207
                      quicc_smc_serial_info2,
208
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BAUD),
209
                      CYG_SERIAL_STOP_DEFAULT,
210
                      CYG_SERIAL_PARITY_DEFAULT,
211
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
212
                      CYG_SERIAL_FLAGS_DEFAULT
213
    );
214
#endif
215
static unsigned char quicc_smc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
216
static unsigned char quicc_smc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
217
 
218
DEVTAB_ENTRY(quicc_smc_serial_io2,
219
             CYGDAT_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_NAME,
220
             0,                     // Does not depend on a lower level interface
221
             &cyg_io_serial_devio,
222
             quicc_smc_serial_init,
223
             quicc_smc_serial_lookup,     // Serial driver may need initializing
224
             &quicc_smc_serial_channel2
225
    );
226
#endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
227
 
228
#ifdef CYGDBG_DIAG_BUF
229
extern int enable_diag_uart;
230
#endif // CYGDBG_DIAG_BUF
231
 
232
// Internal function to actually configure the hardware to desired baud rate, etc.
233
static bool
234
quicc_smc_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
235
{
236
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
237
    unsigned int baud_divisor = select_baud[new_config->baud];
238
    cyg_uint32 _lcr;
239
    EPPC *eppc = eppc_base();
240
    if (baud_divisor == 0) return false;
241
    // Disable channel during setup
242
    smc_chan->ctl->smc_smcmr = QUICC_SMCMR_UART;  // Disabled, UART mode
243
    // Disable port interrupts while changing hardware
244
    _lcr = select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
245
        select_stop_bits[new_config->stop] |
246
        select_parity[new_config->parity];
247
    // Stop transmitter while changing baud rate
248
    eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_StopTx;
249
    // Set baud rate generator
250
    *smc_chan->brg = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
251
#ifdef XX_CYGDBG_DIAG_BUF
252
        enable_diag_uart = 0;
253
        diag_printf("Set BAUD RATE[%x], %d = %x, tstate = %x\n", smc_chan->brg, baud_divisor, *smc_chan->brg, smc_chan->pram->tstate);
254
        enable_diag_uart = 1;
255
#endif // CYGDBG_DIAG_BUF
256
 
257
    // Enable channel with new configuration
258
    smc_chan->ctl->smc_smcmr = QUICC_SMCMR_UART|QUICC_SMCMR_TEN|QUICC_SMCMR_REN|_lcr;
259
    eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_RestartTx;
260
    if (new_config != &chan->config) {
261
        chan->config = *new_config;
262
    }
263
    return true;
264
}
265
 
266
// Function to set up internal tables for device.
267
static void
268
quicc_smc_serial_init_info(quicc_smc_serial_info *smc_chan,
269
                           volatile struct smc_uart_pram *uart_pram,
270
                           volatile struct smc_regs *ctl,
271
                           int TxBD, int TxNUM, int TxSIZE,
272
                           cyg_uint8 *TxBUF,
273
                           int RxBD, int RxNUM, int RxSIZE,
274
                           cyg_uint8 *RxBUF,
275
                           int portBmask,
276
                           int BRG, int SIpos)
277
{
278
    EPPC *eppc = eppc_base();
279
    struct cp_bufdesc *txbd, *rxbd;
280
    cyg_uint32 simode = 0;
281
    int i;
282
 
283
    // Disable channel during setup
284
    ctl->smc_smcmr = QUICC_SMCMR_UART;  // Disabled, UART mode
285
    smc_chan->pram = uart_pram;
286
    smc_chan->ctl = ctl;
287
    /*
288
     *  SDMA & LCD bus request level 5
289
     *  (Section 16.10.2.1)
290
     */
291
    eppc->dma_sdcr = 1;
292
    switch (BRG) {
293
    case 1:
294
        smc_chan->brg = (cyg_uint32 *)&eppc->brgc1;
295
        simode = 0;
296
        break;
297
    case 2:
298
        smc_chan->brg = (cyg_uint32 *)&eppc->brgc2;
299
        simode = 1;
300
        break;
301
    case 3:
302
        smc_chan->brg = (cyg_uint32 *)&eppc->brgc3;
303
        simode = 2;
304
        break;
305
    case 4:
306
        smc_chan->brg = (cyg_uint32 *)&eppc->brgc4;
307
        simode = 3;
308
        break;
309
    }
310
    // NMSI mode, BRGn to SMCm  (Section 16.12.5.2)
311
    eppc->si_simode = (eppc->si_simode & ~(0xF<<SIpos)) | (simode<<SIpos);
312
    /*
313
     *  Set up the PortB pins for UART operation.
314
     *  Set PAR and DIR to allow SMCTXDx and SMRXDx
315
     *  (Table 16-39)
316
     */
317
    eppc->pip_pbpar |= portBmask;
318
    eppc->pip_pbdir &= ~portBmask;
319
    /*
320
     *  SDMA & LCD bus request level 5
321
     *  (Section 16.10.2.1)
322
     */
323
    eppc->dma_sdcr = 1;
324
    /*
325
     *  Set Rx and Tx function code
326
     *  (Section 16.15.4.2)
327
     */
328
    uart_pram->rfcr = 0x18;
329
    uart_pram->tfcr = 0x18;
330
    /*
331
     *  Set pointers to buffer descriptors.
332
     *  (Sections 16.15.4.1, 16.15.7.12, and 16.15.7.13)
333
     */
334
    uart_pram->rbase = RxBD;
335
    uart_pram->tbase = TxBD;
336
    /* tx and rx buffer descriptors */
337
    txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
338
    rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
339
    smc_chan->txbd = txbd;
340
    smc_chan->tbase = txbd;
341
    smc_chan->txsize = TxSIZE;
342
    smc_chan->rxbd = rxbd;
343
    smc_chan->rbase = rxbd;
344
    smc_chan->rxsize = RxSIZE;
345
    /* max receive buffer length */
346
    uart_pram->mrblr = RxSIZE;
347
    /* set max_idle feature - generate interrupt after 4 chars idle period */
348
    uart_pram->max_idl = 4;
349
    /* no last brk char received */
350
    uart_pram->brkln = 0;
351
    /* no break condition occurred */
352
    uart_pram->brkec = 0;
353
    /* 1 break char sent on top XMIT */
354
    uart_pram->brkcr = 1;
355
    /* setup RX buffer descriptors */
356
    for (i = 0;  i < RxNUM;  i++) {
357
        rxbd->length = 0;
358
        rxbd->buffer = RxBUF;
359
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
360
        if (i == (RxNUM-1)) rxbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
361
        RxBUF += RxSIZE;
362
        rxbd++;
363
    }
364
    /* setup TX buffer descriptors */
365
    for (i = 0;  i < TxNUM;  i++) {
366
        txbd->length = 0;
367
        txbd->buffer = TxBUF;
368
        txbd->ctrl   = 0;
369
        if (i == (TxNUM-1)) txbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
370
        TxBUF += TxSIZE;
371
        txbd++;
372
    }
373
    /*
374
     *  Reset Rx & Tx params
375
     */
376
    eppc->cp_cr = smc_chan->channel | QUICC_SMC_CMD_Go | QUICC_SMC_CMD_InitTxRx;
377
    /*
378
     *  Clear any previous events. Enable interrupts.
379
     *  (Section 16.15.7.14 and 16.15.7.15)
380
     */
381
    ctl->smc_smce = 0xFF;
382
    ctl->smc_smcm = QUICC_SMCE_BSY|QUICC_SMCE_TX|QUICC_SMCE_RX;
383
}
384
 
385
// Function to initialize the device.  Called at bootstrap time.
386
static bool
387
quicc_smc_serial_init(struct cyg_devtab_entry *tab)
388
{
389
    serial_channel *chan = (serial_channel *)tab->priv;
390
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
391
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
392
    int TxBD, RxBD;
393
    static int first_init = 1;
394
    int cache_state;
395
 
396
    HAL_DCACHE_IS_ENABLED(cache_state);
397
    HAL_DCACHE_SYNC();
398
    HAL_DCACHE_DISABLE();
399
#ifdef CYGDBG_IO_INIT
400
    diag_printf("QUICC_SMC SERIAL init - dev: %x.%d\n", smc_chan->channel, smc_chan->int_num);
401
#endif
402
    if (first_init) {
403
        // Set up tables since many fields are dynamic [computed at runtime]
404
        first_init = 0;
405
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC1
406
        eppc->cp_cr = QUICC_SMC_CMD_Reset | QUICC_SMC_CMD_Go;  // Totally reset CP
407
        while (eppc->cp_cr & QUICC_SMC_CMD_Reset) ;
408
        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM);
409
        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM);
410
        quicc_smc_serial_init_info(&quicc_smc_serial_info1,
411
                                   &eppc->pram[2].scc.pothers.smc_modem.psmc.u, // PRAM
412
                                   &eppc->smc_regs[0], // Control registers
413
                                   TxBD,
414
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM,
415
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxSIZE,
416
                                   ALIGN_TO_CACHELINES(&quicc_smc1_txbuf[0][0]),
417
                                   RxBD,
418
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxNUM,
419
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_RxSIZE,
420
                                   ALIGN_TO_CACHELINES(&quicc_smc1_rxbuf[0][0]),
421
                                   0xC0, // PortB mask
422
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_BRG,
423
                                   12  // SI mask position
424
            );
425
#else
426
#ifdef CYGPKG_HAL_POWERPC_MBX
427
        // Ensure the SMC1 side is initialized first and use shared mem
428
        // above where it plays:
429
        diag_init();    // (pull in constructor that inits diag channel)
430
        TxBD = 0x2830;  // Note: this should be inferred from the chip state
431
#else
432
        // there is no diag device wanting to use the QUICC, so prepare it
433
        // for SMC2 use only.
434
        eppc->cp_cr = QUICC_SMC_CMD_Reset | QUICC_SMC_CMD_Go;  // Totally reset CP
435
        while (eppc->cp_cr & QUICC_SMC_CMD_Reset) ;
436
        TxBD = 0x2800;  // Note: this should be configurable
437
#endif        
438
#endif
439
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC_SMC2
440
        TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM);
441
        RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM);
442
        quicc_smc_serial_init_info(&quicc_smc_serial_info2,
443
                                   &eppc->pram[3].scc.pothers.smc_modem.psmc.u, // PRAM
444
                                   &eppc->smc_regs[1], // Control registers
445
                                   TxBD,
446
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxNUM,
447
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_TxSIZE,
448
                                   ALIGN_TO_CACHELINES(&quicc_smc2_txbuf[0][0]),
449
                                   RxBD,
450
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxNUM,
451
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_RxSIZE,
452
                                   ALIGN_TO_CACHELINES(&quicc_smc2_rxbuf[0][0]),
453
                                   0xC00, // PortB mask
454
                                   CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC2_BRG,
455
                                   28  // SI mask position
456
            );
457
#endif
458
    }
459
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
460
    if (chan->out_cbuf.len != 0) {
461
        cyg_drv_interrupt_create(smc_chan->int_num,
462
                                 CYGARC_SIU_PRIORITY_HIGH, // Priority - unused (but asserted)
463
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
464
                                 quicc_smc_serial_ISR,
465
                                 quicc_smc_serial_DSR,
466
                                 &smc_chan->serial_interrupt_handle,
467
                                 &smc_chan->serial_interrupt);
468
        cyg_drv_interrupt_attach(smc_chan->serial_interrupt_handle);
469
        cyg_drv_interrupt_unmask(smc_chan->int_num);
470
    }
471
    quicc_smc_serial_config_port(chan, &chan->config, true);
472
    if (cache_state)
473
        HAL_DCACHE_ENABLE();
474
    return true;
475
}
476
 
477
// This routine is called when the device is "looked" up (i.e. attached)
478
static Cyg_ErrNo
479
quicc_smc_serial_lookup(struct cyg_devtab_entry **tab,
480
                  struct cyg_devtab_entry *sub_tab,
481
                  const char *name)
482
{
483
    serial_channel *chan = (serial_channel *)(*tab)->priv;
484
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
485
    return ENOERR;
486
}
487
 
488
// Force the current transmit buffer to be sent
489
static void
490
quicc_smc_serial_flush(quicc_smc_serial_info *smc_chan)
491
{
492
    volatile struct cp_bufdesc *txbd = smc_chan->txbd;
493
    int cache_state;
494
 
495
    HAL_DCACHE_IS_ENABLED(cache_state);
496
    if (cache_state) {
497
      HAL_DCACHE_FLUSH(txbd->buffer, smc_chan->txsize);
498
    }
499
 
500
    if ((txbd->length > 0) &&
501
        ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0)) {
502
        txbd->ctrl |= QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int;  // Signal buffer ready
503
        if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
504
            txbd = smc_chan->tbase;
505
        } else {
506
            txbd++;
507
        }
508
        smc_chan->txbd = txbd;
509
    }
510
}
511
 
512
// Send a character to the device output buffer.
513
// Return 'true' if character is sent to device
514
static bool
515
quicc_smc_serial_putc(serial_channel *chan, unsigned char c)
516
{
517
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
518
    volatile struct cp_bufdesc *txbd, *txfirst;
519
    EPPC *eppc = eppc_base();
520
    bool res;
521
    cyg_drv_dsr_lock();  // Avoid race condition testing pointers
522
    txbd = (struct cp_bufdesc *)((char *)eppc + smc_chan->pram->tbptr);
523
    txfirst = txbd;
524
    // Scan for a non-busy buffer
525
    while (txbd->ctrl & QUICC_BD_CTL_Ready) {
526
        // This buffer is busy, move to next one
527
        if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
528
            txbd = smc_chan->tbase;
529
        } else {
530
            txbd++;
531
        }
532
        if (txbd == txfirst) break;  // Went all the way around
533
    }
534
    smc_chan->txbd = txbd;
535
    if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0) {
536
        // Transmit buffer is not full/busy
537
        txbd->buffer[txbd->length++] = c;
538
        if (txbd->length == smc_chan->txsize) {
539
            // This buffer is now full, tell SMC to start processing it
540
            quicc_smc_serial_flush(smc_chan);
541
        }
542
        res = true;
543
    } else {
544
        // No space
545
        res = false;
546
    }
547
    cyg_drv_dsr_unlock();
548
    return res;
549
}
550
 
551
// Fetch a character from the device input buffer, waiting if necessary
552
static unsigned char
553
quicc_smc_serial_getc(serial_channel *chan)
554
{
555
    unsigned char c;
556
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
557
    volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
558
    while ((rxbd->ctrl & QUICC_BD_CTL_Ready) != 0) ;
559
    c = rxbd->buffer[0];
560
    rxbd->length = smc_chan->rxsize;
561
    rxbd->ctrl |= QUICC_BD_CTL_Ready;
562
    if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
563
        rxbd = smc_chan->rbase;
564
    } else {
565
        rxbd++;
566
    }
567
    smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
568
    return c;
569
}
570
 
571
// Set up the device characteristics; baud rate, etc.
572
static Cyg_ErrNo
573
quicc_smc_serial_set_config(serial_channel *chan, cyg_uint32 key,
574
                            const void *xbuf, cyg_uint32 *len)
575
{
576
    switch (key) {
577
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
578
      {
579
          // FIXME - The documentation says that you can't change the baud rate
580
          // again until at least two BRG input clocks have occurred.
581
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
582
        if ( *len < sizeof(cyg_serial_info_t) ) {
583
            return -EINVAL;
584
        }
585
        *len = sizeof(cyg_serial_info_t);
586
        if ( true != quicc_smc_serial_config_port(chan, config, false) )
587
            return -EINVAL;
588
      }
589
      break;
590
    default:
591
        return -EINVAL;
592
    }
593
    return ENOERR;
594
}
595
 
596
// Enable the transmitter (interrupt) on the device
597
static void
598
quicc_smc_serial_start_xmit(serial_channel *chan)
599
{
600
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
601
    cyg_drv_dsr_lock();
602
    if (smc_chan->txbd->length == 0) {
603
        // See if there is anything to put in this buffer, just to get it going
604
        (chan->callbacks->xmt_char)(chan);
605
    }
606
    if (smc_chan->txbd->length != 0) {
607
        // Make sure it gets started
608
        quicc_smc_serial_flush(smc_chan);
609
    }
610
    cyg_drv_dsr_unlock();
611
}
612
 
613
// Disable the transmitter on the device
614
static void
615
quicc_smc_serial_stop_xmit(serial_channel *chan)
616
{
617
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
618
    // If anything is in the last buffer, need to get it started
619
    if (smc_chan->txbd->length != 0) {
620
        quicc_smc_serial_flush(smc_chan);
621
    }
622
}
623
 
624
// Serial I/O - low level interrupt handler (ISR)
625
static cyg_uint32
626
quicc_smc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
627
{
628
    serial_channel *chan = (serial_channel *)data;
629
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
630
    cyg_drv_interrupt_mask(smc_chan->int_num);
631
    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Cause DSR to be run
632
}
633
 
634
// Serial I/O - high level interrupt handler (DSR)
635
static void
636
quicc_smc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
637
{
638
    serial_channel *chan = (serial_channel *)data;
639
    quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info *)chan->dev_priv;
640
    volatile struct smc_regs *ctl = smc_chan->ctl;
641
    volatile struct cp_bufdesc *txbd;
642
    volatile struct cp_bufdesc *rxbd = smc_chan->rxbd;
643
    struct cp_bufdesc *rxlast;
644
    int i, cache_state;
645
#ifdef CYGDBG_DIAG_BUF
646
    int _time, _stime;
647
    externC cyg_tick_count_t cyg_current_time(void);
648
    cyg_drv_isr_lock();
649
    enable_diag_uart = 0;
650
    HAL_CLOCK_READ(&_time);
651
    _stime = (int)cyg_current_time();
652
    diag_printf("DSR start - CE: %x, time: %x.%x\n", ctl->smc_smce, _stime, _time);
653
    enable_diag_uart = 1;
654
#endif // CYGDBG_DIAG_BUF
655
    if (ctl->smc_smce & QUICC_SMCE_TX) {
656
#ifdef XX_CYGDBG_DIAG_BUF
657
        enable_diag_uart = 0;
658
        txbd = smc_chan->tbase;
659
        for (i = 0;  i < CYGNUM_IO_SERIAL_POWERPC_QUICC_SMC_SMC1_TxNUM;  i++, txbd++) {
660
            diag_printf("Tx BD: %x, length: %d, ctl: %x\n", txbd, txbd->length, txbd->ctrl);
661
        }
662
        enable_diag_uart = 1;
663
#endif // CYGDBG_DIAG_BUF
664
        // Transmit interrupt
665
        ctl->smc_smce = QUICC_SMCE_TX;  // Reset interrupt state;
666
        txbd = smc_chan->tbase;  // First buffer
667
        while (true) {
668
            if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) {
669
#ifdef XX_CYGDBG_DIAG_BUF
670
                enable_diag_uart = 0;
671
                HAL_CLOCK_READ(&_time);
672
                _stime = (int)cyg_current_time();
673
                diag_printf("TX Done - Tx: %x, length: %d, time: %x.%x\n", txbd, txbd->length, _stime, _time);
674
                enable_diag_uart = 1;
675
#endif // CYGDBG_DIAG_BUF
676
                txbd->length = 0;
677
                txbd->ctrl &= ~QUICC_BD_CTL_Int;  // Reset interrupt bit
678
            }
679
            if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
680
                txbd = smc_chan->tbase;
681
                break;
682
            } else {
683
                txbd++;
684
            }
685
        }
686
        (chan->callbacks->xmt_char)(chan);
687
    }
688
    while (ctl->smc_smce & QUICC_SMCE_RX) {
689
        // Receive interrupt
690
        ctl->smc_smce = QUICC_SMCE_RX;  // Reset interrupt state;
691
        rxlast = (struct cp_bufdesc *) (
692
            (char *)eppc_base() + smc_chan->pram->rbptr );
693
#ifdef CYGDBG_DIAG_BUF
694
        enable_diag_uart = 0;
695
        HAL_CLOCK_READ(&_time);
696
        _stime = (int)cyg_current_time();
697
        diag_printf("Scan RX - rxbd: %x, rbptr: %x, time: %x.%x\n", rxbd, rxlast, _stime, _time);
698
#endif // CYGDBG_DIAG_BUF
699
        while (rxbd != rxlast) {
700
            if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) {
701
#ifdef CYGDBG_DIAG_BUF
702
                diag_printf("rxbuf: %x, flags: %x, length: %d\n", rxbd, rxbd->ctrl, rxbd->length);
703
                diag_dump_buf(rxbd->buffer, rxbd->length);
704
#endif // CYGDBG_DIAG_BUF
705
                for (i = 0;  i < rxbd->length;  i++) {
706
                    (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
707
                }
708
                // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
709
                HAL_DCACHE_IS_ENABLED(cache_state);
710
                if (cache_state) {
711
                    HAL_DCACHE_INVALIDATE(rxbd->buffer, smc_chan->rxsize);  // Make sure no stale data
712
                }
713
                rxbd->length = 0;
714
                rxbd->ctrl |= QUICC_BD_CTL_Ready;
715
            }
716
            if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
717
                rxbd = smc_chan->rbase;
718
            } else {
719
                rxbd++;
720
            }
721
        }
722
#ifdef CYGDBG_DIAG_BUF
723
        enable_diag_uart = 1;
724
#endif // CYGDBG_DIAG_BUF
725
        smc_chan->rxbd = (struct cp_bufdesc *)rxbd;
726
    }
727
    if (ctl->smc_smce & QUICC_SMCE_BSY) {
728
#ifdef CYGDBG_DIAG_BUF
729
        enable_diag_uart = 0;
730
        diag_printf("RX BUSY interrupt\n");
731
        enable_diag_uart = 1;
732
#endif // CYGDBG_DIAG_BUF
733
        ctl->smc_smce = QUICC_SMCE_BSY;  // Reset interrupt state;
734
    }
735
#ifdef CYGDBG_DIAG_BUF
736
    enable_diag_uart = 0;
737
    HAL_CLOCK_READ(&_time);
738
    _stime = (int)cyg_current_time();
739
    diag_printf("DSR done - CE: %x, time: %x.%x\n", ctl->smc_smce, _stime, _time);
740
    enable_diag_uart = 1;
741
#endif // CYGDBG_DIAG_BUF
742
    cyg_drv_interrupt_acknowledge(smc_chan->int_num);
743
    cyg_drv_interrupt_unmask(smc_chan->int_num);
744
#ifdef CYGDBG_DIAG_BUF
745
    cyg_drv_isr_unlock();
746
#endif // CYGDBG_DIAG_BUF
747
}
748
 
749
void
750
show_rxbd(int dump_all)
751
{
752
#ifdef CYGDBG_DIAG_BUF
753
    EPPC *eppc = eppc_base();
754
    struct smc_uart_pram *pram = &eppc->pram[2].scc.pothers.smc_modem.psmc.u;
755
    struct cp_bufdesc *rxbd = (struct cp_bufdesc *)((char *)eppc+pram->rbase);
756
    int _enable = enable_diag_uart;
757
    enable_diag_uart = 0;
758
#if 1
759
    diag_printf("SMC Mask: %x, Events: %x, Rbase: %x, Rbptr: %x\n",
760
                eppc->smc_regs[0].smc_smcm, eppc->smc_regs[0].smc_smce,
761
                pram->rbase, pram->rbptr);
762
    while (true) {
763
        diag_printf("Rx BD: %x, ctl: %x, length: %d\n", rxbd, rxbd->ctrl, rxbd->length);
764
        if (rxbd->ctrl & QUICC_BD_CTL_Wrap) break;
765
        rxbd++;
766
    }
767
#endif
768
    enable_diag_uart = _enable;
769
    if (dump_all) dump_diag_buf();
770
#endif // CYGDBG_DIAG_BUF
771
}
772
#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC_SMC
773
 
774
// ------------------------------------------------------------------------
775
// EOF powerpc/quicc_smc_serial.c

powered by: WebSVN 2.1.0

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