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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [serial/] [powerpc/] [quicc2/] [v2_0/] [src/] [quicc2_scc_serial.c] - Blame information for rev 454

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      io/serial/powerpc/quicc2_scc_serial.c
4
//
5
//      PowerPC QUICC2 (SCC) 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) 2002 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):    mtek
45
// Contributors: gthomas
46
// Date:         1999-06-20
47
// Purpose:      QUICC2 SCC 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/hal/var_intr.h>
60
#include <cyg/io/devtab.h>
61
#include <cyg/io/serial.h>
62
#include <cyg/infra/diag.h>
63
#include <cyg/hal/hal_cache.h>
64
#include <cyg/hal/mpc8260.h>
65
#include CYGBLD_HAL_PLATFORM_H
66
 
67
#include "quicc2_scc_serial.h"
68
#define QUICC2_VADS_IMM_BASE    0x04700000
69
#define QUICC2_VADS_BCSR_BASE   0x04500000
70
 
71
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
72
 
73
static bool
74
quicc2_scc_serial_init(struct cyg_devtab_entry *tab);
75
static bool
76
quicc2_scc_serial_putc(serial_channel *chan,
77
                       unsigned char c);
78
static Cyg_ErrNo
79
quicc2_scc_serial_lookup(struct cyg_devtab_entry **tab,
80
                         struct cyg_devtab_entry *sub_tab,
81
                         const char *name);
82
static unsigned char
83
quicc2_scc_serial_getc(serial_channel *chan);
84
static Cyg_ErrNo
85
quicc2_scc_serial_set_config(serial_channel *chan,
86
                             cyg_uint32 key, const void *xbuf,
87
                             cyg_uint32 *len);
88
static void
89
quicc2_scc_serial_start_xmit(serial_channel *chan);
90
static void
91
quicc2_scc_serial_stop_xmit(serial_channel *chan);
92
 
93
static cyg_uint32
94
quicc2_scc_serial_ISR(cyg_vector_t vector,
95
                      cyg_addrword_t data);
96
static void
97
quicc2_scc_serial_DSR(cyg_vector_t vector,
98
                      cyg_ucount32 count,
99
                      cyg_addrword_t data);
100
 
101
static SERIAL_FUNS(quicc2_scc_serial_funs,
102
                   quicc2_scc_serial_putc,
103
                   quicc2_scc_serial_getc,
104
                   quicc2_scc_serial_set_config,
105
                   quicc2_scc_serial_start_xmit,
106
                   quicc2_scc_serial_stop_xmit
107
    );
108
 
109
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
110
static quicc2_scc_serial_info quicc2_scc_serial_info1;
111
 
112
#if CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE > 0
113
static unsigned char quicc2_scc_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE];
114
static unsigned char quicc2_scc_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BUFSIZE];
115
 
116
static SERIAL_CHANNEL_USING_INTERRUPTS(quicc2_scc_serial_channel1,
117
                                       quicc2_scc_serial_funs,
118
                                       quicc2_scc_serial_info1,
119
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BAUD),
120
                                       CYG_SERIAL_STOP_DEFAULT,
121
                                       CYG_SERIAL_PARITY_DEFAULT,
122
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
123
                                       CYG_SERIAL_FLAGS_DEFAULT,
124
                                       &quicc2_scc_serial_out_buf1[0], sizeof(quicc2_scc_serial_out_buf1),
125
                                       &quicc2_scc_serial_in_buf1[0], sizeof(quicc2_scc_serial_in_buf1)
126
    );
127
#else
128
static SERIAL_CHANNEL(quicc2_scc_serial_channel1,
129
                      quicc2_scc_serial_funs,
130
                      quicc2_scc_serial_info1,
131
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BAUD),
132
                      CYG_SERIAL_STOP_DEFAULT,
133
                      CYG_SERIAL_PARITY_DEFAULT,
134
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
135
                      CYG_SERIAL_FLAGS_DEFAULT
136
    );
137
#endif
138
 
139
static unsigned char quicc2_scc1_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM]
140
                                      [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
141
static unsigned char quicc2_scc1_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM]
142
                                      [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
143
 
144
DEVTAB_ENTRY(quicc2_scc_serial_io1,
145
             CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_NAME,
146
             0,                     // Does not depend on a lower level interface
147
             &cyg_io_serial_devio,
148
             quicc2_scc_serial_init,
149
             quicc2_scc_serial_lookup,     // Serial driver may need initializing
150
             &quicc2_scc_serial_channel1
151
    );
152
#endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
153
 
154
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
155
static quicc2_scc_serial_info quicc2_scc_serial_info2;
156
 
157
#if CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE > 0
158
static unsigned char quicc2_scc_serial_out_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE];
159
static unsigned char quicc2_scc_serial_in_buf2[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BUFSIZE];
160
 
161
static SERIAL_CHANNEL_USING_INTERRUPTS(quicc2_scc_serial_channel2,
162
                                       quicc2_scc_serial_funs,
163
                                       quicc2_scc_serial_info2,
164
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BAUD),
165
                                       CYG_SERIAL_STOP_DEFAULT,
166
                                       CYG_SERIAL_PARITY_DEFAULT,
167
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
168
                                       CYG_SERIAL_FLAGS_DEFAULT,
169
                                       &quicc2_scc_serial_out_buf2[0], sizeof(quicc2_scc_serial_out_buf2),
170
                                       &quicc2_scc_serial_in_buf2[0], sizeof(quicc2_scc_serial_in_buf2)
171
    );
172
#else
173
static SERIAL_CHANNEL(quicc2_scc_serial_channel2,
174
                      quicc2_scc_serial_funs,
175
                      quicc2_scc_serial_info2,
176
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BAUD),
177
                      CYG_SERIAL_STOP_DEFAULT,
178
                      CYG_SERIAL_PARITY_DEFAULT,
179
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
180
                      CYG_SERIAL_FLAGS_DEFAULT
181
    );
182
#endif
183
static unsigned char quicc2_scc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM]
184
                                      [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE + HAL_DCACHE_LINE_SIZE-1];
185
static unsigned char quicc2_scc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM]
186
                                      [CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE + HAL_DCACHE_LINE_SIZE-1];
187
 
188
DEVTAB_ENTRY(quicc2_scc_serial_io2,
189
             CYGDAT_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_NAME,
190
             0,                     // Does not depend on a lower level interface
191
             &cyg_io_serial_devio,
192
             quicc2_scc_serial_init,
193
             quicc2_scc_serial_lookup,     // Serial driver may need initializing
194
             &quicc2_scc_serial_channel2
195
    );
196
#endif //  CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
197
 
198
#ifdef CYGDBG_DIAG_BUF
199
extern int enable_diag_uart;
200
#endif // CYGDBG_DIAG_BUF
201
 
202
// Internal function to actually configure the hardware to 
203
// desired baud rate, stop bits and parity ...
204
static bool
205
quicc2_scc_serial_config_port(serial_channel *chan,
206
                              cyg_serial_info_t *new_config,
207
                              bool init)
208
{
209
    quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
210
    volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
211
 
212
    unsigned long b_rate   = select_baud[new_config->baud];
213
 
214
    if (b_rate == 0) return false;
215
 
216
    // Stop the transmitter while changing baud rate
217
    while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
218
    IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_STOP_TX | QUICC2_CPCR_READY;
219
    while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
220
 
221
    // Disable Tx, RX and put them in a reset state
222
    scc_chan->scc_regs->gsmr_l &= ~(QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
223
 
224
    // Set the baud rate
225
    *(scc_chan->brg) = (UART_BIT_RATE(b_rate) << 1) | QUICC2_BRG_EN;
226
 
227
    // Set stop bits, word length and parity
228
    scc_chan->scc_regs->psmr = QUICC2_SCC_PSMR_ASYNC |
229
      select_stop_bits[new_config->stop] |
230
      select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
231
      select_parity[new_config->parity];
232
 
233
    // Support fractional stop bits 
234
    scc_chan->scc_regs->dsr = (new_config->stop & 1) ? QUICC2_SCC_DSR_FULL : QUICC2_SCC_DSR_HALF;
235
 
236
    // Initialize the parameters
237
    while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
238
    IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_INIT_TX_RX | QUICC2_CPCR_READY;
239
    while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
240
 
241
    // Enable Tx and Rx
242
    scc_chan->scc_regs->gsmr_l |= (QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
243
 
244
    if (new_config != &chan->config) {
245
        chan->config = *new_config;
246
    }
247
    return true;
248
}
249
 
250
// Function to set up internal tables for device.
251
static void
252
quicc2_scc_serial_init_info(quicc2_scc_serial_info *scc_chan,
253
                            int SCC_index,
254
                            int BRG_index,
255
                            int TxBD, int TxNUM, int TxSIZE,
256
                            cyg_uint8 *TxBUF,
257
                            int RxBD, int RxNUM, int RxSIZE,
258
                            cyg_uint8 *RxBUF)
259
{
260
  volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
261
#ifdef CYGPKG_HAL_POWERPC_VADS
262
  volatile t_BCSR *bcsr  = (volatile t_BCSR *) QUICC2_VADS_BCSR_BASE;
263
#endif
264
  t_UartScc_Pram *uart_pram;
265
  scc_bd  *txbd, *rxbd;
266
  int i;
267
 
268
  // Disable the channel, just in case 
269
  IMM->scc_regs[SCC_index-1].gsmr_l &= ~(QUICC2_SCC_GSMR_L_ENT | QUICC2_SCC_GSMR_L_ENR);
270
 
271
  switch (SCC_index) {
272
 
273
  case 1:
274
    // Put the data into the info structure 
275
    scc_chan->scc_cpcr = QUICC2_CPCR_SCC1;
276
    scc_chan->scc_regs = &(IMM->scc_regs[0]);
277
    scc_chan->scc_pram = &(IMM->pram.serials.scc_pram[0]);
278
    scc_chan->int_vector = CYGNUM_HAL_INTERRUPT_SCC1;
279
 
280
    // Set-up the PORT D pins
281
    IMM->io_regs[PORT_D].psor &= ~QUICC2_SCC1_PORTD_PPAR;
282
    IMM->io_regs[PORT_D].psor |=  QUICC2_SCC1_PORTD_PDIR;
283
    IMM->io_regs[PORT_D].ppar |=  QUICC2_SCC1_PORTD_PPAR;
284
    IMM->io_regs[PORT_D].pdir &= ~QUICC2_SCC1_PORTD_PPAR;
285
    IMM->io_regs[PORT_D].pdir |=  QUICC2_SCC1_PORTD_PDIR;
286
    IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC1_PORTD_PPAR;
287
 
288
    // Set-up the PORT C pins
289
    IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC1_PORTC_PPAR;
290
    IMM->io_regs[PORT_C].ppar |=  QUICC2_SCC1_PORTC_PPAR;
291
    IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC1_PORTC_PPAR;
292
    IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC1_PORTC_PPAR;
293
 
294
    // Select the baud rate generator and connect it 
295
    IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC1_CLR;
296
 
297
    switch (BRG_index) {
298
    case 1:
299
      scc_chan->brg = &(IMM->brgs_brgc1);
300
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG1;
301
      break;
302
    case 2:
303
      scc_chan->brg = &(IMM->brgs_brgc2);
304
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG2;
305
      break;
306
    case 3:
307
      scc_chan->brg = &(IMM->brgs_brgc3);
308
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG3;
309
      break;
310
    case 4:
311
      scc_chan->brg = &(IMM->brgs_brgc4);
312
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC1_BRG4;
313
      break;
314
    }
315
#ifdef CYGPKG_HAL_POWERPC_VADS     
316
    // Enable the transciever
317
    bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC1);
318
#endif
319
    break;
320
 
321
  case 2:
322
    // Put the data into the info structure 
323
    scc_chan->scc_cpcr = QUICC2_CPCR_SCC2;
324
    scc_chan->scc_regs = &(IMM->scc_regs[1]);
325
    scc_chan->scc_pram = &(IMM->pram.serials.scc_pram[1]);
326
    scc_chan->int_vector = CYGNUM_HAL_INTERRUPT_SCC2;
327
 
328
    // Set-up the PORT D pins
329
    IMM->io_regs[PORT_D].psor &= ~QUICC2_SCC2_PORTD_PPAR;
330
    IMM->io_regs[PORT_D].ppar |=  QUICC2_SCC2_PORTD_PPAR;
331
    IMM->io_regs[PORT_D].pdir &= ~QUICC2_SCC2_PORTD_PPAR;
332
    IMM->io_regs[PORT_D].pdir |=  QUICC2_SCC2_PORTD_PDIR;
333
    IMM->io_regs[PORT_D].podr &= ~QUICC2_SCC2_PORTD_PPAR;
334
 
335
    // Set-up the PORT C pins
336
    IMM->io_regs[PORT_C].psor &= ~QUICC2_SCC2_PORTC_PPAR;
337
    IMM->io_regs[PORT_C].ppar |=  QUICC2_SCC2_PORTC_PPAR;
338
    IMM->io_regs[PORT_C].pdir &= ~QUICC2_SCC2_PORTC_PPAR;
339
    IMM->io_regs[PORT_C].podr &= ~QUICC2_SCC2_PORTC_PPAR;
340
 
341
    // Select the baud rate generator and connect it 
342
    IMM->cpm_mux_cmxscr &= QUICC2_CMX_SCC2_CLR;
343
 
344
    switch (BRG_index) {
345
    case 1:
346
      scc_chan->brg = &(IMM->brgs_brgc1);
347
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG1;
348
      break;
349
    case 2:
350
      scc_chan->brg = &(IMM->brgs_brgc2);
351
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG2;
352
      break;
353
    case 3:
354
      scc_chan->brg = &(IMM->brgs_brgc3);
355
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG3;
356
      break;
357
    case 4:
358
      scc_chan->brg = &(IMM->brgs_brgc4);
359
      IMM->cpm_mux_cmxscr |= QUICC2_CMX_SCC2_BRG4;
360
      break;
361
    }
362
#ifdef CYGPKG_HAL_POWERPC_VADS 
363
    // Enable the transciever
364
    bcsr->bcsr1 &= ~(QUICC2_BCSR_EN_SCC2);
365
#endif
366
    break;
367
 
368
  default:
369
    diag_printf("Incorrect SCC index in quicc2_scc_serial_init_info \n");
370
    break;
371
  }
372
 
373
  // Initialize common SCC PRAM
374
  scc_chan->tbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
375
  scc_chan->rbase = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
376
  scc_chan->txbd  = (scc_bd *) (QUICC2_VADS_IMM_BASE + TxBD);
377
  scc_chan->rxbd  = (scc_bd *) (QUICC2_VADS_IMM_BASE + RxBD);
378
  scc_chan->txsize = TxSIZE;
379
  scc_chan->rxsize = RxSIZE;
380
 
381
  scc_chan->scc_pram->rbase = RxBD;
382
  scc_chan->scc_pram->tbase = TxBD;
383
  scc_chan->scc_pram->rfcr  = 0x10;
384
  scc_chan->scc_pram->tfcr  = 0x10;
385
  scc_chan->scc_pram->mrblr = RxSIZE;
386
 
387
  // Initialize UART PRAM
388
  uart_pram = &(scc_chan->scc_pram->SpecificProtocol.u);
389
 
390
  uart_pram->max_idl = 4;
391
  uart_pram->brkcr   = 1;
392
  uart_pram->brkln   = 0;
393
  uart_pram->parec   = 0;
394
  uart_pram->frmec   = 0;
395
  uart_pram->nosec   = 0;
396
  uart_pram->brkec   = 0;
397
  uart_pram->uaddr1  = 0;
398
  uart_pram->uaddr2  = 0;
399
  uart_pram->toseq   = 0;
400
  uart_pram->cc[0] = 0x8000;
401
  uart_pram->cc[1] = 0x8000;
402
  uart_pram->cc[2] = 0x8000;
403
  uart_pram->cc[3] = 0x8000;
404
  uart_pram->cc[4] = 0x8000;
405
  uart_pram->cc[5] = 0x8000;
406
  uart_pram->cc[6] = 0x8000;
407
  uart_pram->cc[7] = 0x8000;
408
  uart_pram->rccm  = 0xC0FF;
409
 
410
  // Initialize registers
411
  scc_chan->scc_regs->gsmr_l = QUICC2_SCC_GSMR_L_INIT;
412
  scc_chan->scc_regs->gsmr_h = QUICC2_SCC_GSMR_H_INIT;
413
  // scc_chan->scc_regs->psmr   = 0x8000;  // Set by config
414
  scc_chan->scc_regs->todr   = 0;
415
  //  scc_chan->scc_regs->dsr    = 0x7e7e; // Set by config
416
  scc_chan->scc_regs->scce   = 0xffff;
417
  scc_chan->scc_regs->sccm   = (QUICC2_SCCE_BSY | QUICC2_SCCE_TX | QUICC2_SCCE_RX);
418
 
419
  /* setup RX buffer descriptors */
420
  rxbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + RxBD);
421
 
422
  for (i = 0;  i < RxNUM;  i++) {
423
    rxbd->ctrl   = QUICC2_BD_CTL_Ready | QUICC2_BD_CTL_Int;
424
    rxbd->length = 0;
425
    rxbd->buffer = RxBUF;
426
 
427
    RxBUF += RxSIZE;
428
    rxbd++;
429
  }
430
 
431
  rxbd--;
432
  rxbd->ctrl |= QUICC2_BD_CTL_Wrap;  // Last buffer
433
 
434
  /* setup TX buffer descriptors */
435
  txbd = (struct scc_bd *)((char *) QUICC2_VADS_IMM_BASE + TxBD);
436
 
437
  for (i = 0;  i < TxNUM;  i++) {
438
    txbd->ctrl   = 0;
439
    txbd->length = 0;
440
    txbd->buffer = TxBUF;
441
    TxBUF += TxSIZE;
442
    txbd++;
443
  }
444
 
445
  txbd--;
446
  txbd->ctrl |= QUICC2_BD_CTL_Wrap;  // Last buffer
447
 
448
  // Issue Init RX & TX Parameters Command 
449
  while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
450
  IMM->cpm_cpcr = scc_chan->scc_cpcr | QUICC2_CPCR_INIT_TX_RX | QUICC2_CPCR_READY;
451
  while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
452
 
453
  return;
454
 
455
}
456
 
457
// Function to initialize the device.  Called at bootstrap time.
458
static bool
459
quicc2_scc_serial_init(struct cyg_devtab_entry *tab)
460
{
461
  serial_channel *chan = (serial_channel *)tab->priv;
462
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
463
  volatile t_PQ2IMM *IMM = (volatile t_PQ2IMM *) QUICC2_VADS_IMM_BASE;
464
  int TxBD, RxBD;
465
  static int first_init = 1;
466
  int cache_state;
467
 
468
  HAL_DCACHE_IS_ENABLED(cache_state);
469
  HAL_DCACHE_SYNC();
470
  HAL_DCACHE_DISABLE();
471
 
472
#ifdef CYGDBG_IO_INIT
473
  diag_printf("QUICC2_SCC SERIAL init - dev: %x\n",
474
              scc_chan->channel);
475
#endif
476
    if (first_init) {
477
        // Set up tables since many fields are dynamic [computed at runtime]
478
        first_init = 0;
479
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1
480
 
481
        // Totally reset the CP
482
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
483
        IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
484
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
485
 
486
        TxBD = 0x2800;  // Note: this should be configurable
487
        RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM*8;
488
        quicc2_scc_serial_init_info(&quicc2_scc_serial_info1,
489
                                    1, // indicates SCC1
490
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_BRG,
491
                                    TxBD,
492
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM,
493
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxSIZE,
494
                                    ALIGN_TO_CACHELINES(&quicc2_scc1_txbuf[0][0]),
495
                                    RxBD,
496
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxNUM,
497
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_RxSIZE,
498
                                    ALIGN_TO_CACHELINES(&quicc2_scc1_rxbuf[0][0])
499
                                    );
500
#else
501
#ifdef CYGPKG_HAL_POWERPC_MPC8260
502
        // Ensure that SCC1 side is initialized first
503
        diag_init(); // (pull in constructor that inits diag channel)
504
        TxBD = 0x2900;  // Note : this should be inferred from the
505
                        // chip state
506
#else
507
        // there is no diag device wanting to use the QUICC, so prepare it
508
        // for SCC2 use only.
509
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY); // Totally reset the CP
510
        IMM->cpm_cpcr = QUICC2_CPCR_RESET | QUICC2_CPCR_READY;
511
        while (IMM->cpm_cpcr & QUICC2_CPCR_READY);
512
        TxBD = 0x2800; // Note: this should be configurable
513
#endif
514
#endif
515
#ifdef CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2
516
 
517
        RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM*8;
518
        quicc2_scc_serial_init_info(&quicc2_scc_serial_info2,
519
                                    2, // indicates SCC2
520
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_BRG,
521
                                    TxBD,
522
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxNUM,
523
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_TxSIZE,
524
                                    ALIGN_TO_CACHELINES(&quicc2_scc2_txbuf[0][0]),
525
                                    RxBD,
526
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxNUM,
527
                                    CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC2_RxSIZE,
528
                                    ALIGN_TO_CACHELINES(&quicc2_scc2_rxbuf[0][0])
529
            );
530
#endif
531
    }
532
 
533
    // Really only required for interrupt driven devices
534
    (chan->callbacks->serial_init)(chan);
535
    if (chan->out_cbuf.len != 0) {
536
        cyg_drv_interrupt_create(scc_chan->int_vector,
537
                                 0, // CYGARC_SIU_PRIORITY_HIGH, - unused 
538
                                 (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
539
                                 quicc2_scc_serial_ISR,
540
                                 quicc2_scc_serial_DSR,
541
                                 &scc_chan->serial_interrupt_handle,
542
                                 &scc_chan->serial_interrupt);
543
        cyg_drv_interrupt_attach(scc_chan->serial_interrupt_handle);
544
        cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
545
        cyg_drv_interrupt_unmask(scc_chan->int_vector);
546
    }
547
    quicc2_scc_serial_config_port(chan, &chan->config, true);
548
    if (cache_state)
549
        HAL_DCACHE_ENABLE();
550
    return true;
551
}
552
 
553
// This routine is called when the device is "looked" up (i.e. attached)
554
static Cyg_ErrNo
555
quicc2_scc_serial_lookup(struct cyg_devtab_entry **tab,
556
                  struct cyg_devtab_entry *sub_tab,
557
                  const char *name)
558
{
559
    serial_channel *chan = (serial_channel *)(*tab)->priv;
560
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
561
    return ENOERR;
562
}
563
 
564
// Force the current transmit buffer to be sent
565
static void
566
quicc2_scc_serial_flush(quicc2_scc_serial_info *scc_chan)
567
{
568
  volatile struct scc_bd *txbd = scc_chan->txbd;
569
  int cache_state;
570
 
571
  HAL_DCACHE_IS_ENABLED(cache_state);
572
  if (cache_state) {
573
    HAL_DCACHE_FLUSH(txbd->buffer, scc_chan->txsize);
574
  }
575
 
576
  if ((txbd->length > 0) &&
577
      ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0)) {
578
    txbd->ctrl |= QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int;  // Signal buffer ready
579
    if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
580
      txbd = scc_chan->tbase;
581
    } else {
582
      txbd++;
583
    }
584
    scc_chan->txbd = (scc_bd *) txbd;
585
  }
586
}
587
 
588
// Send a character to the device output buffer.
589
// Return 'true' if character is sent to device
590
static bool
591
quicc2_scc_serial_putc(serial_channel *chan, unsigned char c)
592
{
593
    quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
594
    volatile struct scc_bd *txbd, *txfirst;
595
    bool res;
596
 
597
    cyg_drv_dsr_lock();  // Avoid race condition testing pointers
598
 
599
    txbd = (scc_bd *)(QUICC2_VADS_IMM_BASE + ((int) scc_chan->scc_pram->tbptr));
600
    txfirst = txbd;
601
 
602
    // Scan for a non-busy buffer
603
    while (txbd->ctrl & QUICC2_BD_CTL_Ready) {
604
      // This buffer is busy, move to next one
605
      if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
606
        txbd = scc_chan->tbase;
607
      } else {
608
        txbd++;
609
      }
610
      if (txbd == txfirst) break;  // Went all the way around
611
    }
612
 
613
    scc_chan->txbd = (scc_bd *) txbd;
614
    if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0) {
615
      // Transmit buffer is not full/busy
616
      txbd->buffer[txbd->length++] = c;
617
      if (txbd->length == scc_chan->txsize) {
618
        // This buffer is now full, tell SCC to start processing it
619
        quicc2_scc_serial_flush(scc_chan);
620
      }
621
      res = true;
622
    } else {
623
      // No space
624
      res = false;
625
    }
626
 
627
    cyg_drv_dsr_unlock();
628
    return res;
629
}
630
 
631
// Fetch a character from the device input buffer, waiting if necessary
632
static unsigned char
633
quicc2_scc_serial_getc(serial_channel *chan)
634
{
635
  unsigned char c;
636
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
637
  volatile scc_bd *rxbd = scc_chan->rxbd;
638
 
639
  while ((rxbd->ctrl & QUICC2_BD_CTL_Ready) != 0) ; // WAIT ...
640
 
641
  c = rxbd->buffer[0];
642
  rxbd->length = scc_chan->rxsize;
643
  rxbd->ctrl |= QUICC2_BD_CTL_Ready;
644
  if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
645
    rxbd = scc_chan->rbase;
646
  } else {
647
    rxbd++;
648
  }
649
  scc_chan->rxbd = (scc_bd *) rxbd;
650
  return c;
651
}
652
 
653
// Set up the device characteristics; baud rate, etc.
654
static Cyg_ErrNo
655
quicc2_scc_serial_set_config(serial_channel *chan, cyg_uint32 key,
656
                            const void *xbuf, cyg_uint32 *len)
657
{
658
  switch (key) {
659
  case CYG_IO_SET_CONFIG_SERIAL_INFO:
660
    {
661
      // FIXME - The documentation says that you can't change the baud rate
662
      // again until at least two BRG input clocks have occurred.
663
      cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
664
      if ( *len < sizeof(cyg_serial_info_t) ) {
665
        return -EINVAL;
666
      }
667
      *len = sizeof(cyg_serial_info_t);
668
      if ( true != quicc2_scc_serial_config_port(chan, config, false) )
669
        return -EINVAL;
670
    }
671
    break;
672
  default:
673
    return -EINVAL;
674
  }
675
  return ENOERR;
676
}
677
 
678
// Enable the transmitter (interrupt) on the device
679
static void
680
quicc2_scc_serial_start_xmit(serial_channel *chan)
681
{
682
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
683
 
684
  cyg_drv_dsr_lock();
685
 
686
  if (scc_chan->txbd->length == 0) {
687
    // See if there is anything to put in this buffer, just to get it going
688
    (chan->callbacks->xmt_char)(chan);
689
  }
690
  if (scc_chan->txbd->length != 0) {
691
    // Make sure it gets started
692
    quicc2_scc_serial_flush(scc_chan);
693
  }
694
 
695
  cyg_drv_dsr_unlock();
696
}
697
 
698
// Disable the transmitter on the device
699
static void
700
quicc2_scc_serial_stop_xmit(serial_channel *chan)
701
{
702
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
703
  // If anything is in the last buffer, need to get it started
704
  if (scc_chan->txbd->length != 0) {
705
    quicc2_scc_serial_flush(scc_chan);
706
  }
707
}
708
 
709
// Serial I/O - low level interrupt handler (ISR)
710
static cyg_uint32
711
quicc2_scc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
712
{
713
  serial_channel *chan = (serial_channel *)data;
714
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
715
  cyg_drv_interrupt_mask(scc_chan->int_vector);
716
  return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Cause DSR to be run
717
}
718
 
719
// Serial I/O - high level interrupt handler (DSR)
720
static void
721
quicc2_scc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
722
{
723
    serial_channel *chan = (serial_channel *)data;
724
    quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
725
    volatile struct scc_regs_8260 *regs = scc_chan->scc_regs;
726
    volatile scc_bd *txbd;
727
    volatile scc_bd *rxbd = scc_chan->rxbd;
728
    scc_bd *rxlast;
729
    int i, cache_state;
730
 
731
#ifdef CYGDBG_DIAG_BUF
732
    int _time, _stime;
733
    externC cyg_tick_count_t cyg_current_time(void);
734
    cyg_drv_isr_lock();
735
    enable_diag_uart = 0;
736
    HAL_CLOCK_READ(&_time);
737
    _stime = (int)cyg_current_time();
738
    diag_printf("DSR start - CE: %x, time: %x.%x\n",
739
               regs->scce, _stime, _time);
740
    enable_diag_uart = 1;
741
#endif // CYGDBG_DIAG_BUF
742
 
743
    if (regs->scce & QUICC2_SCCE_TX) { // Tx Event
744
 
745
#ifdef XX_CYGDBG_DIAG_BUF
746
      enable_diag_uart = 0;
747
      txbd = scc_chan->tbase;
748
      for (i = 0;  i < CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM;  i++, txbd++) {
749
        diag_printf("Tx BD: %x, length: %d, ctl: %x\n", txbd, txbd->length, txbd->ctrl);
750
      }
751
      enable_diag_uart = 1;
752
#endif // CYGDBG_DIAG_BUF
753
 
754
      regs->scce = QUICC2_SCCE_TX;  // Reset Tx Event
755
      txbd = scc_chan->tbase;  // First buffer
756
      while (true) {
757
        if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == QUICC2_BD_CTL_Int) {
758
#ifdef XX_CYGDBG_DIAG_BUF
759
          enable_diag_uart = 0;
760
          HAL_CLOCK_READ(&_time);
761
          _stime = (int)cyg_current_time();
762
          diag_printf("TX Done - Tx: %x, length: %d, time: %x.%x\n",
763
                      txbd, txbd->length, _stime, _time);
764
          enable_diag_uart = 1;
765
#endif // CYGDBG_DIAG_BUF
766
          txbd->length = 0;
767
          txbd->ctrl &= ~QUICC2_BD_CTL_Int;  // Reset interrupt bit
768
        }
769
 
770
        if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
771
          txbd = scc_chan->tbase;
772
          break;
773
        } else {
774
          txbd++;
775
        }
776
      }
777
      (chan->callbacks->xmt_char)(chan);
778
    }
779
 
780
    while (regs->scce & QUICC2_SCCE_RX) { // Rx Event
781
 
782
      regs->scce = QUICC2_SCCE_RX;  // Reset interrupt state;
783
      rxlast = (scc_bd *) ((char *)QUICC2_VADS_IMM_BASE + scc_chan->scc_pram->rbptr );
784
 
785
#ifdef CYGDBG_DIAG_BUF
786
      enable_diag_uart = 0;
787
      HAL_CLOCK_READ(&_time);
788
      _stime = (int)cyg_current_time();
789
      diag_printf("Scan RX - rxbd: %x, rbptr: %x, time: %x.%x\n",
790
                  rxbd, rxlast, _stime, _time);
791
#endif // CYGDBG_DIAG_BUF
792
      while (rxbd != rxlast) {
793
        if ((rxbd->ctrl & QUICC2_BD_CTL_Ready) == 0) {
794
#ifdef CYGDBG_DIAG_BUF
795
          diag_printf("rxbuf: %x, flags: %x, length: %d\n",
796
                      rxbd, rxbd->ctrl, rxbd->length);
797
          diag_dump_buf(rxbd->buffer, rxbd->length);
798
#endif // CYGDBG_DIAG_BUF
799
 
800
          for (i = 0;  i < rxbd->length;  i++) {
801
            (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
802
          }
803
          // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
804
          HAL_DCACHE_IS_ENABLED(cache_state);
805
          if (cache_state) {
806
            HAL_DCACHE_INVALIDATE(rxbd->buffer, scc_chan->rxsize);  // Make sure no stale data
807
          }
808
 
809
          rxbd->length = 0;
810
          rxbd->ctrl |= QUICC2_BD_CTL_Ready;
811
        }
812
 
813
        if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
814
          rxbd = scc_chan->rbase;
815
        } else {
816
          rxbd++;
817
        }
818
      }
819
#ifdef CYGDBG_DIAG_BUF
820
      enable_diag_uart = 1;
821
#endif // CYGDBG_DIAG_BUF
822
      scc_chan->rxbd = (scc_bd *) rxbd;
823
    }
824
 
825
    if (regs->scce & QUICC2_SCCE_BSY) {
826
#ifdef CYGDBG_DIAG_BUF
827
      enable_diag_uart = 0;
828
      diag_printf("RX BUSY interrupt\n");
829
      enable_diag_uart = 1;
830
#endif // CYGDBG_DIAG_BUF
831
      regs->scce = QUICC2_SCCE_BSY;  // Reset interrupt state;
832
    }
833
#ifdef CYGDBG_DIAG_BUF
834
    enable_diag_uart = 0;
835
    HAL_CLOCK_READ(&_time);
836
    _stime = (int)cyg_current_time();
837
    diag_printf("DSR done - CE: %x, time: %x.%x\n",
838
                regs->scce, _stime, _time);
839
    enable_diag_uart = 1;
840
#endif // CYGDBG_DIAG_BUF
841
    cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
842
    cyg_drv_interrupt_unmask(scc_chan->int_vector);
843
#ifdef CYGDBG_DIAG_BUF
844
    cyg_drv_isr_unlock();
845
#endif // CYGDBG_DIAG_BUF
846
}
847
 
848
#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC
849
 
850
// ------------------------------------------------------------------------
851
// EOF powerpc/quicc2_scc_serial.c

powered by: WebSVN 2.1.0

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