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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [serial/] [powerpc/] [ec555/] [v2_0/] [src/] [ec555_serial_with_ints.c] - Blame information for rev 446

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

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      ec555_serial_with_ints.c
4
//
5
//      PowerPC 5xx EC555 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
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):   Bob Koninckx
44
// Contributors:
45
// Date:        2002-04-25
46
// Purpose:     EC555 Serial I/O module (interrupt driven version)
47
// Description: 
48
//
49
//   
50
//####DESCRIPTIONEND####
51
//==========================================================================
52
//----------------------------------
53
// Includes and forward declarations
54
//----------------------------------
55
#include <pkgconf/io_serial.h>
56
#include <pkgconf/io.h>
57
 
58
#include <cyg/io/io.h>
59
#include <cyg/hal/hal_intr.h>
60
#include <cyg/hal/hal_arbiter.h>
61
#include <cyg/io/devtab.h>
62
#include <cyg/infra/diag.h>
63
#include <cyg/io/serial.h>
64
 
65
// Only build this driver for the MPC555 based EC555 board
66
#ifdef CYGPKG_IO_SERIAL_POWERPC_EC555
67
 
68
#include "ec555_serial.h"
69
 
70
//-----------------
71
// Type definitions
72
//-----------------
73
typedef struct mpc555_serial_info {
74
  CYG_ADDRWORD   base;                  // The base address of the serial port
75
  CYG_WORD       tx_interrupt_num;      // trivial
76
  CYG_WORD       rx_interrupt_num;      // trivial
77
  cyg_priority_t tx_interrupt_priority; // trivial
78
  cyg_priority_t rx_interrupt_priority; // trivial
79
  bool           tx_interrupt_enable;   // tells if the transmit interrupt may be re-enabled
80
  cyg_interrupt  tx_interrupt;          // the tx interrupt object
81
  cyg_handle_t   tx_interrupt_handle;   // the tx interrupt handle
82
  cyg_interrupt  rx_interrupt;          // the rx interrupt object
83
  cyg_handle_t   rx_interrupt_handle;   // the rx interrupt handle
84
} mpc555_serial_info;
85
 
86
//--------------------
87
// Function prototypes
88
//--------------------
89
static bool mpc555_serial_init(struct cyg_devtab_entry * tab);
90
static bool mpc555_serial_putc(serial_channel * chan, unsigned char c);
91
static Cyg_ErrNo mpc555_serial_lookup(struct cyg_devtab_entry ** tab,
92
                                      struct cyg_devtab_entry * sub_tab,
93
                                      const char * name);
94
static unsigned char mpc555_serial_getc(serial_channel *chan);
95
static Cyg_ErrNo mpc555_serial_set_config(serial_channel *chan, cyg_uint32 key,
96
                                          const void *xbuf, cyg_uint32 *len);
97
static void mpc555_serial_start_xmit(serial_channel *chan);
98
static void mpc555_serial_stop_xmit(serial_channel *chan);
99
 
100
// The interrupt servers
101
static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
102
static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
103
static void       mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
104
static void       mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
105
 
106
//-------------------------------------------
107
// Register the device driver with the kernel
108
//-------------------------------------------
109
static SERIAL_FUNS(mpc555_serial_funs,
110
                   mpc555_serial_putc,
111
                   mpc555_serial_getc,
112
                   mpc555_serial_set_config,
113
                   mpc555_serial_start_xmit,
114
                   mpc555_serial_stop_xmit);
115
 
116
//-------------------
117
// Device driver data
118
//-------------------
119
#ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_A
120
static mpc555_serial_info mpc555_serial_info0 = {MPC555_SERIAL_BASE_A,
121
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX,
122
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX,
123
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX_PRIORITY,
124
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX_PRIORITY,
125
                                                 false};
126
#if CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_A_BUFSIZE > 0
127
static unsigned char mpc555_serial_out_buf0[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_A_BUFSIZE];
128
static unsigned char mpc555_serial_in_buf0[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_A_BUFSIZE];
129
 
130
static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel0,
131
                                       mpc555_serial_funs,
132
                                       mpc555_serial_info0,
133
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_A_BAUD),
134
                                       CYG_SERIAL_STOP_DEFAULT,
135
                                       CYG_SERIAL_PARITY_DEFAULT,
136
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
137
                                       CYG_SERIAL_FLAGS_DEFAULT,
138
                                       &mpc555_serial_out_buf0[0],
139
                                       sizeof(mpc555_serial_out_buf0),
140
                                       &mpc555_serial_in_buf0[0],
141
                                       sizeof(mpc555_serial_in_buf0));
142
#else 
143
static SERIAL_CHANNEL(mpc555_serial_channel0,
144
                      mpc555_serial_funs,
145
                      mpc555_serial_info0,
146
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_A_BAUD),
147
                      CYG_SERIAL_STOP_DEFAULT,
148
                      CYG_SERIAL_PARITY_DEFAULT,
149
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
150
                      CYG_SERIAL_FLAGS_DEFAULT);
151
#endif
152
DEVTAB_ENTRY(mpc555_serial_io0,
153
             CYGDAT_IO_SERIAL_POWERPC_EC555_SERIAL_A_NAME,
154
             0, // does not depend on a lower level device driver
155
             &cyg_io_serial_devio,
156
             mpc555_serial_init,
157
             mpc555_serial_lookup,
158
             &mpc555_serial_channel0);
159
#endif // ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_A
160
 
161
#ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_B
162
static mpc555_serial_info mpc555_serial_info1 = {MPC555_SERIAL_BASE_B,
163
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX,
164
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
165
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX_PRIORITY,
166
                                                 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY,
167
                                                 false};
168
#if CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_B_BUFSIZE > 0
169
static unsigned char mpc555_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_B_BUFSIZE];
170
static unsigned char mpc555_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_B_BUFSIZE];
171
 
172
static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel1,
173
                                       mpc555_serial_funs,
174
                                       mpc555_serial_info1,
175
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_B_BAUD),
176
                                       CYG_SERIAL_STOP_DEFAULT,
177
                                       CYG_SERIAL_PARITY_DEFAULT,
178
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
179
                                       CYG_SERIAL_FLAGS_DEFAULT,
180
                                       &mpc555_serial_out_buf1[0],
181
                                       sizeof(mpc555_serial_out_buf1),
182
                                       &mpc555_serial_in_buf1[0],
183
                                       sizeof(mpc555_serial_in_buf1));
184
#else
185
static SERIAL_CHANNEL(mpc555_serial_channel1,
186
                      mpc555_serial_funs,
187
                      mpc555_serial_info1,
188
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_B_BAUD),
189
                      CYG_SERIAL_STOP_DEFAULT,
190
                      CYG_SERIAL_PARITY_DEFAULT,
191
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
192
                      CYG_SERIAL_FLAGS_DEFAULT);
193
#endif
194
DEVTAB_ENTRY(mpc555_serial_io1,
195
             CYGDAT_IO_SERIAL_POWERPC_EC555_SERIAL_B_NAME,
196
             0, // does not depend on a lower level device driver
197
             &cyg_io_serial_devio,
198
             mpc555_serial_init,
199
             mpc555_serial_lookup,
200
             &mpc555_serial_channel1);
201
#endif // ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_B
202
 
203
//-----------------------------
204
// Device driver implementation
205
//-----------------------------
206
 
207
// The arbitration isr. 
208
// I think this is the best place to implement it. The device driver is the only place
209
// in the code where the knowledge is present about how the hardware is used
210
static cyg_uint32 hal_arbitration_isr_qsci(CYG_ADDRWORD a_vector, CYG_ADDRWORD a_data)
211
{
212
  cyg_uint16 status;
213
  cyg_uint16 control;
214
 
215
#ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_A // Do not waist time on unused hardware
216
  HAL_READ_UINT16(CYGARC_REG_IMM_SC1SR, status);
217
  HAL_READ_UINT16(CYGARC_REG_IMM_SCC1R1, control);
218
  if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
219
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX);
220
// Don't waist time on unused interrupts
221
//  if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
222
//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC);
223
  if((status & CYGARC_REG_IMM_SCxSR_RDRF) && (control & CYGARC_REG_IMM_SCCxR1_RIE))
224
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX);
225
// Don't waist time on unused interrupts
226
//  if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
227
//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE);
228
#endif
229
 
230
#ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_B // Do not waist time on unused hardware
231
  HAL_READ_UINT16(CYGARC_REG_IMM_SC2SR, status);
232
  HAL_READ_UINT16(CYGARC_REG_IMM_SCC2R1, control);
233
  if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
234
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX);
235
// Don't waist time on unused interrupts
236
//  if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
237
//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC);
238
  if((status & CYGARC_REG_IMM_SCxSR_RDRF) && (control & CYGARC_REG_IMM_SCCxR1_RIE))
239
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX);
240
// Don't waist time on unused interrupts
241
//  if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
242
//    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE);
243
 
244
#if 0
245
  // The driver doesn't use the queue operation of the hardware (It would need different code for serial 1 and 2
246
  // since oly one port supports queue mode). So the following is not needed.
247
  // Leave it there. It is easyer for later implementations to remove the comments than finding
248
  // out how the hardware works again.
249
  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, status);
250
  HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, control);
251
  if((status & CYGARC_REG_IMM_QSCI1SR_QTHF) && (control & CYGARC_REG_IMM_QSCI1CR_QTHFI))
252
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQTHF);
253
  if((status & CYGARC_REG_IMM_QSCI1SR_QBHF) && (control & CYGARC_REG_IMM_QSCI1CR_QBHFI))
254
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQBHF);
255
  if((status & CYGARC_REG_IMM_QSCI1SR_QTHE) && (control & CYGARC_REG_IMM_QSCI1CR_QTHEI))
256
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQTHE);
257
  if((status & CYGARC_REG_IMM_QSCI1SR_QBHE) && (control & CYGARC_REG_IMM_QSCI1CR_QBHEI))
258
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE);
259
 
260
  cyg_uint16 status;
261
  cyg_uint16 control;
262
 
263
  HAL_READ_UINT16(CYGARC_REG_IMM_SPSR, status);
264
  HAL_READ_UINT16(CYGARC_REG_IMM_SPCR2, control);
265
  if((status & CYGARC_REG_IMM_SPSR_SPIF) && (control & CYGARC_REG_IMM_SPCR2_SPIFIE))
266
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_FI);
267
 
268
  HAL_READ_UINT16(CYGARC_REG_IMM_SPCR3, control);
269
  if((status & CYGARC_REG_IMM_SPSR_MODF) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
270
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_MODF);
271
 
272
  if((status & CYGARC_REG_IMM_SPSR_HALTA) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
273
    return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_HALTA);
274
#endif
275
 
276
#endif
277
 
278
  return 0;
279
}
280
 
281
//--------------------------------------------------------------------------------
282
// Internal function to actually configure the hardware to desired baud rate, etc.
283
//--------------------------------------------------------------------------------
284
static bool mpc555_serial_config_port(serial_channel * chan, cyg_serial_info_t * new_config, bool init)
285
{
286
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)(chan->dev_priv);
287
 
288
  cyg_addrword_t port = mpc555_chan->base;
289
  cyg_uint16 baud_rate = select_baud[new_config->baud];
290
  unsigned char frame_length = 1; // The start bit
291
 
292
  cyg_uint16 old_isrstate;
293
  cyg_uint16 sccxr;
294
 
295
  if(!baud_rate)
296
    return false;    // Invalid baud rate selected
297
 
298
  if((new_config->word_length != CYGNUM_SERIAL_WORD_LENGTH_7) &&
299
     (new_config->word_length != CYGNUM_SERIAL_WORD_LENGTH_8))
300
    return false;    // Invalid word length selected
301
 
302
  if((new_config->parity != CYGNUM_SERIAL_PARITY_NONE) &&
303
     (new_config->parity != CYGNUM_SERIAL_PARITY_EVEN) &&
304
     (new_config->parity != CYGNUM_SERIAL_PARITY_ODD))
305
    return false;    // Invalid parity selected
306
 
307
  if((new_config->stop != CYGNUM_SERIAL_STOP_1) &&
308
     (new_config->stop != CYGNUM_SERIAL_STOP_2))
309
    return false;    // Invalid stop bits selected
310
 
311
  frame_length += select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
312
  frame_length += select_stop_bits[new_config->stop];
313
  frame_length += select_parity[new_config->parity];
314
 
315
  if((frame_length != 10) && (frame_length != 11))
316
    return false;    // Invalid frame format selected
317
 
318
  // Disable port interrupts while changing hardware
319
  HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
320
  old_isrstate = sccxr;
321
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_LOOPS);
322
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_WOMS);
323
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_ILT);
324
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PT);
325
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
326
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
327
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_WAKE);
328
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TE);
329
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RE);
330
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RWU);
331
  old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_SBK);
332
  sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TIE);
333
  sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TCIE);
334
  sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RIE);
335
  sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_ILIE);
336
  HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
337
 
338
  // Set databits, stopbits and parity.
339
  HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
340
 
341
  if(frame_length == 11)
342
    sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_M;
343
  else
344
    sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
345
 
346
  switch(new_config->parity)
347
  {
348
    case CYGNUM_SERIAL_PARITY_NONE:
349
      sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
350
      break;
351
    case CYGNUM_SERIAL_PARITY_EVEN:
352
      sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
353
      sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PT);
354
      break;
355
    case CYGNUM_SERIAL_PARITY_ODD:
356
      sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
357
      sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PT;
358
      break;
359
    default:
360
      break;
361
  }
362
  HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
363
 
364
  // Set baud rate.
365
  baud_rate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR0_OTHR);
366
  baud_rate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR0_LINKBD);
367
  HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR0, sccxr);
368
  sccxr &= ~(MPC555_SERIAL_SCCxR0_SCxBR);
369
  sccxr |= baud_rate;
370
  HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR0, sccxr);
371
 
372
  // Enable the device
373
  HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
374
  sccxr |= MPC555_SERIAL_SCCxR1_TE;
375
  sccxr |= MPC555_SERIAL_SCCxR1_RE;
376
  HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
377
 
378
  if(init)
379
  { // enable the receiver interrupt
380
    HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
381
    sccxr |= MPC555_SERIAL_SCCxR1_RIE;
382
    HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
383
  }
384
  else // Restore the old interrupt state
385
  {
386
    HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
387
    sccxr |= old_isrstate;
388
    HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
389
  }
390
 
391
  if(new_config != &chan->config)
392
    chan->config = *new_config;
393
 
394
  return true;
395
}
396
 
397
//--------------------------------------------------------------
398
// Function to initialize the device.  Called at bootstrap time.
399
//--------------------------------------------------------------
400
static hal_mpc5xx_arbitration_data arbiter;
401
 
402
static bool mpc555_serial_init(struct cyg_devtab_entry * tab)
403
{
404
   serial_channel * chan = (serial_channel *)tab->priv;
405
   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
406
 
407
   if(!mpc555_serial_config_port(chan, &chan->config, true))
408
     return false;
409
 
410
   (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
411
   if(chan->out_cbuf.len != 0)
412
   {
413
     arbiter.priority = CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI;
414
     arbiter.data     = 0;
415
     arbiter.arbiter  = hal_arbitration_isr_qsci;
416
 
417
     // Install the arbitration isr, Make sure that is is not installed twice
418
     hal_mpc5xx_remove_arbitration_isr(&arbiter);
419
     hal_mpc5xx_install_arbitration_isr(&arbiter);
420
 
421
     // Create the Tx interrupt, do not enable it yet
422
     cyg_drv_interrupt_create(mpc555_chan->tx_interrupt_num,
423
                              mpc555_chan->tx_interrupt_priority,
424
                              (cyg_addrword_t)chan,   //  Data item passed to interrupt handler
425
                              mpc555_serial_tx_ISR,
426
                              mpc555_serial_tx_DSR,
427
                              &mpc555_chan->tx_interrupt_handle,
428
                              &mpc555_chan->tx_interrupt);
429
     cyg_drv_interrupt_attach(mpc555_chan->tx_interrupt_handle);
430
 
431
     // Create the Rx interrupt, this can be safely unmasked now
432
     cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_num,
433
                              mpc555_chan->rx_interrupt_priority,
434
                              (cyg_addrword_t)chan,
435
                              mpc555_serial_rx_ISR,
436
                              mpc555_serial_rx_DSR,
437
                              &mpc555_chan->rx_interrupt_handle,
438
                              &mpc555_chan->rx_interrupt);
439
     cyg_drv_interrupt_attach(mpc555_chan->rx_interrupt_handle);
440
     cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
441
    }
442
 
443
    return true;
444
}
445
 
446
//----------------------------------------------------------------------
447
// This routine is called when the device is "looked" up (i.e. attached)
448
//----------------------------------------------------------------------
449
static Cyg_ErrNo mpc555_serial_lookup(struct cyg_devtab_entry ** tab,
450
                                      struct cyg_devtab_entry * sub_tab,
451
                                      const char * name)
452
{
453
  serial_channel * chan = (serial_channel *)(*tab)->priv;
454
  (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
455
 
456
  return ENOERR;
457
}
458
 
459
//----------------------------------------------
460
// Send a character to the device output buffer.
461
// Return 'true' if character is sent to device
462
//----------------------------------------------
463
static bool mpc555_serial_putc(serial_channel * chan, unsigned char c)
464
{
465
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
466
  cyg_addrword_t port = mpc555_chan->base;
467
 
468
  cyg_uint16 scsr;
469
  cyg_uint16 scdr;
470
 
471
  HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
472
  if(scsr & MPC555_SERIAL_SCxSR_TDRE)
473
  { // Ok, we have space, write the character and return success
474
    scdr = (cyg_uint16)c;
475
    HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
476
    return true;
477
  }
478
  else
479
    // We cannot write to the transmitter, return failure
480
    return false;
481
}
482
 
483
//---------------------------------------------------------------------
484
// Fetch a character from the device input buffer, waiting if necessary
485
//---------------------------------------------------------------------
486
static unsigned char mpc555_serial_getc(serial_channel * chan)
487
{
488
  unsigned char c;
489
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
490
  cyg_addrword_t port = mpc555_chan->base;
491
 
492
  cyg_uint16 scsr;
493
  cyg_uint16 scdr;
494
 
495
  do {
496
    HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
497
  } while(!(scsr & MPC555_SERIAL_SCxSR_RDRF));
498
 
499
  // Ok, data is received, read it out and return
500
  HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
501
  c = (unsigned char)scdr;
502
 
503
  return c;
504
}
505
 
506
//---------------------------------------------------
507
// Set up the device characteristics; baud rate, etc.
508
//---------------------------------------------------
509
static bool mpc555_serial_set_config(serial_channel * chan, cyg_uint32 key,
510
                                     const void *xbuf, cyg_uint32 * len)
511
{
512
  switch(key) {
513
  case CYG_IO_SET_CONFIG_SERIAL_INFO:
514
    {
515
      cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
516
      if(*len < sizeof(cyg_serial_info_t)) {
517
        return -EINVAL;
518
      }
519
      *len = sizeof(cyg_serial_info_t);
520
      if(true != mpc555_serial_config_port(chan, config, false))
521
        return -EINVAL;
522
    }
523
    break;
524
  default:
525
    return -EINVAL;
526
  }
527
  return ENOERR;
528
}
529
 
530
//-------------------------------------
531
// Enable the transmitter on the device
532
//-------------------------------------
533
static void mpc555_serial_start_xmit(serial_channel * chan)
534
{
535
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
536
 
537
  mpc555_chan->tx_interrupt_enable = true;
538
  cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
539
 
540
  // No need to call xmt_char, this will generate an interrupt immediately.
541
}
542
 
543
//--------------------------------------
544
// Disable the transmitter on the device
545
//--------------------------------------
546
static void mpc555_serial_stop_xmit(serial_channel * chan)
547
{
548
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
549
 
550
  cyg_drv_dsr_lock();
551
  mpc555_chan->tx_interrupt_enable = false;
552
  cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
553
  cyg_drv_dsr_unlock();
554
}
555
 
556
//-----------------------------------------
557
// The low level transmit interrupt handler
558
//-----------------------------------------
559
static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
560
{
561
  serial_channel * chan = (serial_channel *)data;
562
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
563
 
564
  cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
565
  cyg_drv_interrupt_acknowledge(mpc555_chan->tx_interrupt_num);
566
 
567
  return CYG_ISR_CALL_DSR; // cause the DSR to run
568
}
569
 
570
//----------------------------------------
571
// The low level receive interrupt handler
572
//----------------------------------------
573
static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
574
{
575
  serial_channel * chan = (serial_channel *)data;
576
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
577
 
578
  cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_num);
579
  cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_num);
580
 
581
  return CYG_ISR_CALL_DSR; // cause the DSR to run
582
}
583
 
584
//------------------------------------------
585
// The high level transmit interrupt handler
586
//------------------------------------------
587
static void mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
588
{
589
  serial_channel * chan = (serial_channel *)data;
590
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
591
 
592
  (chan->callbacks->xmt_char)(chan);
593
  if(mpc555_chan->tx_interrupt_enable)
594
    cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
595
}
596
 
597
//-----------------------------------------
598
// The high level receive interrupt handler
599
//-----------------------------------------
600
#define MPC555_SERIAL_SCxSR_ERRORS (MPC555_SERIAL_SCxSR_OR | \
601
                                    MPC555_SERIAL_SCxSR_NF | \
602
                                    MPC555_SERIAL_SCxSR_FE | \
603
                                    MPC555_SERIAL_SCxSR_PF)
604
 
605
static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
606
{
607
  serial_channel * chan = (serial_channel *)data;
608
  mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
609
  cyg_addrword_t port = mpc555_chan->base;
610
  cyg_uint16 scdr;
611
  cyg_uint16 scsr;
612
 
613
  // Allways read out the received character, in order to clear receiver flags
614
  HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
615
 
616
  HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
617
  if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS)
618
  {
619
    scsr &= ~((cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS);
620
    HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
621
  }
622
  else
623
  {
624
    (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
625
  }
626
 
627
  cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
628
}
629
 
630
#endif // CYGPKG_IO_SERIAL_POWERPC_EC555
631
 
632
// EOF ec555_serial_with_ints.c

powered by: WebSVN 2.1.0

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