source: rtems/bsps/powerpc/ss555/dev/console-generic.c @ 65f868c

5
Last change on this file since 65f868c was 09dd82a5, checked in by Sebastian Huber <sebastian.huber@…>, on 03/13/18 at 15:43:25

bsp/ss555: Move libcpu content to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 *  General Serial I/O functions.
3 *
4 *  This file contains the functions for performing serial I/O.  The actual
5 *  system calls (console_*) should be in the BSP part of the source tree.
6 *  That way different BSPs can use whichever SCI they wish for /dev/console.
7 *
8 *  On-chip resources used:
9 *   resource   minor                note
10 *      SCI1      0
11 *      SCI2      1
12 */
13
14/*
15 *  MPC5xx port sponsored by Defence Research and Development Canada - Suffield
16 *  Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
17 *
18 *  Derived from
19 *    c/src/lib/libcpu/powerpc/mpc8xx/console_generic/console_generic.c:
20 *  Author: Jay Monkman (jmonkman@frasca.com)
21 *  Copyright (C) 1998 by Frasca International, Inc.
22 *
23 *  Derived from c/src/lib/libbsp/m68k/gen360/console/console.c written by:
24 *    W. Eric Norum
25 *    Saskatchewan Accelerator Laboratory
26 *    University of Saskatchewan
27 *    Saskatoon, Saskatchewan, CANADA
28 *    eric@skatter.usask.ca
29 *
30 *  COPYRIGHT (c) 1989-1998.
31 *  On-Line Applications Research Corporation (OAR).
32 *
33 *  Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
34 *  and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
35 *  Copyright (c) 1999, National Research Council of Canada
36 *
37 *  The license and distribution terms for this file may be
38 *  found in the file LICENSE in this distribution or at
39 *  http://www.rtems.org/license/LICENSE.
40 */
41
42#include <stdlib.h>
43#include <unistd.h>
44#include <termios.h>
45#include <rtems.h>
46#include <rtems/libio.h>
47#include <rtems/bspIo.h>   /* for printk */
48#include <mpc5xx.h>
49#include <mpc5xx/console.h>
50#include <bsp/irq.h>
51
52
53/*
54 * SCI port descriptor table.
55 */
56typedef struct
57{
58  volatile m5xxSCIRegisters_t *regs;    /* hardware registers */
59  struct rtems_termios_tty *ttyp;       /* termios data for this port */
60} sci_desc;
61
62static sci_desc sci_descs[] = {
63  { &imb.qsmcm.sci1, 0 },               /* SCI 1 */
64  { &imb.qsmcm.sci2, 0 },               /* SCI 2 */
65};
66
67/*
68 * Number of SCI port initialization calls made so far.  Used to avoid
69 * installing the common interrupt handler more than once.
70 */
71int init_calls = 0;
72
73/*
74 * Default configuration.
75 */
76static struct termios default_termios = {
77  0,                                    /* input mode flags */
78  0,                                    /* output mode flags */
79  0,                                    /* local mode flags */
80  0,                                    /* line discipline */
81  { 0 },                                /* control characters */
82  CS8 | CREAD | CLOCAL | B9600,         /* control mode flags */
83};
84
85
86extern uint32_t bsp_clock_speed;
87
88/*
89 * Termios callback functions
90 */
91
92int
93m5xx_uart_firstOpen(
94  int major,
95  int minor,
96  void *arg
97)
98{
99  rtems_libio_open_close_args_t *args = arg;
100  sci_desc* desc = &sci_descs[minor];
101  struct rtems_termios_tty *tty = args->iop->data1;
102
103  desc->ttyp = tty;                             /* connect tty */
104  if ( tty->device.outputUsesInterrupts == TERMIOS_IRQ_DRIVEN)
105    desc->regs->sccr1 |= QSMCM_SCI_RIE;         /* enable rx interrupt */
106
107  return RTEMS_SUCCESSFUL;
108}
109
110int
111m5xx_uart_lastClose(
112  int major,
113  int minor,
114  void* arg
115)
116{
117  sci_desc* desc = &sci_descs[minor];
118
119  desc->regs->sccr1 &= ~(QSMCM_SCI_RIE | QSMCM_SCI_TIE);  /* disable all */
120  desc->ttyp = NULL;                                      /* disconnect tty */
121
122  return RTEMS_SUCCESSFUL;
123}
124
125int
126m5xx_uart_pollRead(
127  int minor
128)
129{
130  volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs;
131  int c = -1;
132
133  if ( regs ) {
134    while ( (regs->scsr & QSMCM_SCI_RDRF) == 0 )
135      ;
136    c = regs->scdr;
137  }
138
139  return c;
140}
141
142ssize_t m5xx_uart_write(
143  int minor,
144  const char *buf,
145  size_t len
146)
147{
148  if (len > 0) {
149    volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs;
150
151    regs->scdr = *buf;                  /* start transmission */
152    regs->sccr1 |= QSMCM_SCI_TIE;               /* enable interrupt */
153  }
154
155  return 0;
156}
157
158ssize_t m5xx_uart_pollWrite(
159  int minor,
160  const char *buf,
161  size_t len
162)
163{
164  volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs;
165  size_t retval = len;
166
167  while ( len-- ) {
168    while ( (regs->scsr & QSMCM_SCI_TDRE) == 0 )
169      ;
170    regs->scdr = *buf++;
171  }
172
173  return retval;
174}
175
176int
177m5xx_uart_setAttributes(
178  int minor,
179  const struct termios *t
180)
181{
182  uint16_t sccr0 = sci_descs[minor].regs->sccr0;
183  uint16_t sccr1 = sci_descs[minor].regs->sccr1;
184  int baud;
185
186  /*
187   * Check that port number is valid
188   */
189  if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) )
190    return RTEMS_INVALID_NUMBER;
191
192  /* Baud rate */
193  baud = rtems_termios_baud_to_number( t->c_ospeed );
194  if (baud > 0) {
195    sccr0 &= ~QSMCM_SCI_BAUD(-1);
196    sccr0 |= QSMCM_SCI_BAUD((bsp_clock_speed + (16 * baud)) / (32 * baud));
197  }
198
199  /* Number of data bits -- not available with MPC5xx SCI */
200  switch ( t->c_cflag & CSIZE ) {
201    case CS5:     break;
202    case CS6:     break;
203    case CS7:     break;
204    case CS8:     break;
205  }
206
207  /* Stop bits -- not easily available with MPC5xx SCI */
208  if ( t->c_cflag & CSTOPB ) {
209    /* Two stop bits */
210  } else {
211    /* One stop bit */
212  }
213
214  /* Parity */
215  if ( t->c_cflag & PARENB )
216    sccr1 |= QSMCM_SCI_PE;
217  else
218    sccr1 &= ~QSMCM_SCI_PE;
219
220  if ( t->c_cflag & PARODD )
221    sccr1 |= QSMCM_SCI_PT;
222  else
223    sccr1 &= ~QSMCM_SCI_PT;
224
225  /* Transmitter and receiver enable */
226  sccr1 |= QSMCM_SCI_TE;
227  if ( t->c_cflag & CREAD )
228    sccr1 |= QSMCM_SCI_RE;
229  else
230    sccr1 &= ~QSMCM_SCI_RE;
231
232  /* Write hardware registers */
233  sci_descs[minor].regs->sccr0 = sccr0;
234  sci_descs[minor].regs->sccr1 = sccr1;
235
236  return RTEMS_SUCCESSFUL;
237}
238
239
240/*
241 * Interrupt handling.
242 */
243static void
244m5xx_sci_interrupt_handler (rtems_irq_hdl_param unused)
245{
246  int minor;
247
248  for ( minor = 0; minor < NUM_PORTS; minor++ ) {
249    sci_desc *desc = &sci_descs[minor];
250    int sccr1 = desc->regs->sccr1;
251    int scsr = desc->regs->scsr;
252
253    /*
254     * Character received?
255     */
256    if ((sccr1 & QSMCM_SCI_RIE) && (scsr & QSMCM_SCI_RDRF)) {
257      char c = desc->regs->scdr;
258      rtems_termios_enqueue_raw_characters(desc->ttyp, &c, 1);
259    }
260    /*
261     * Transmitter empty?
262     */
263    if ((sccr1 & QSMCM_SCI_TIE) && (scsr & QSMCM_SCI_TDRE)) {
264      desc->regs->sccr1 &= ~QSMCM_SCI_TIE;
265      rtems_termios_dequeue_characters (desc->ttyp, 1);
266    }
267  }
268}
269
270static void m5xx_sci_nop(const rtems_irq_connect_data* ptr)
271{
272}
273
274static int m5xx_sci_isOn(const rtems_irq_connect_data* ptr)
275{
276  return 1;
277}
278
279/*
280 * Basic initialization.
281 */
282
283void
284m5xx_uart_initialize (int minor)
285{
286  /*
287   * Check that minor number is valid.
288   */
289  if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) )
290    return;
291
292  /*
293   * Configure and enable receiver and transmitter.
294   */
295  m5xx_uart_setAttributes(minor, &default_termios);
296
297  /*
298   * Connect interrupt if not yet done.
299   */
300  if ( init_calls++ == 0 ) {
301    rtems_irq_connect_data irq_data;
302
303    irq_data.name = CPU_IRQ_SCI;
304    irq_data.hdl  = m5xx_sci_interrupt_handler;
305    irq_data.on   = m5xx_sci_nop;       /* can't enable both channels here */
306    irq_data.off  = m5xx_sci_nop;       /* can't disable both channels here */
307    irq_data.isOn = m5xx_sci_isOn;
308
309    if (!CPU_install_rtems_irq_handler (&irq_data)) {
310      printk("Unable to connect SCI Irq handler\n");
311      rtems_fatal_error_occurred(1);
312    }
313
314    imb.qsmcm.qdsci_il =                /* set interrupt level in port */
315      QSMCM_ILDSCI(CPU_irq_level_from_symbolic_name(CPU_IRQ_SCI));
316  }
317}
Note: See TracBrowser for help on using the repository browser.