source: rtems/c/src/lib/libcpu/sh/sh7045/sci/sci.c @ a5fb3d1b

4.104.115
Last change on this file since a5fb3d1b was a5fb3d1b, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/15/10 at 08:39:26

Reflect termios API changes.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*
2 * /dev/sci[0|1] for Hitachi SH 704X
3 *
4 * The SH doesn't have a designated console device. Therefore we "alias"
5 * another device as /dev/console and revector all calls to /dev/console
6 * to this device.
7 *
8 * This approach is similar to installing a sym-link from one device to
9 * another device. If rtems once will support sym-links for devices files,
10 * this implementation could be dropped.
11 *
12 *  Author: Ralf Corsepius (corsepiu@faw.uni-ulm.de)
13 *
14 *  COPYRIGHT (c) 1997-1998, FAW Ulm, Germany
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 *
21 *  COPYRIGHT (c) 1998.
22 *  On-Line Applications Research Corporation (OAR).
23 *
24 *  The license and distribution terms for this file may be
25 *  found in the file LICENSE in this distribution or at
26 *  http://www.rtems.com/license/LICENSE.
27 *
28 *  Modified to reflect sh7045 processor:
29 *  John M. Mills (jmills@tga.com)
30 *  TGA Technologies, Inc.
31 *  100 Pinnacle Way, Suite 140
32 *  Norcross, GA 30071 U.S.A.
33 *
34 *  This modified file may be copied and distributed in accordance
35 *  the above-referenced license. It is provided for critique and
36 *  developmental purposes without any warranty nor representation
37 *  by the authors or by TGA Technologies.
38 *
39 *  $Id$
40 */
41
42#include <rtems.h>
43
44
45#include <stdlib.h>
46
47#include <rtems/libio.h>
48#include <rtems/iosupp.h>
49#include <rtems/score/sh_io.h>
50#include <rtems/score/ispsh7045.h>
51#include <rtems/score/iosh7045.h>
52#include <sh/sh7_sci.h>
53#include <sh/sh7_pfc.h>
54
55#include <sh/sci.h>
56
57#ifndef STANDALONE_EVB
58#define STANDALONE_EVB 0
59#endif
60
61/*
62 * NOTE: Some SH variants have 3 sci devices
63 */
64
65#define SCI_MINOR_DEVICES       2
66
67/*
68 * FIXME: sh7045 register names match Hitachi data book,
69 *  but conflict with RTEMS sh7032 usage.
70 */
71
72#define SH_SCI_BASE_0   SCI_SMR0
73#define SH_SCI_BASE_1   SCI_SMR1
74
75#define SH_SCI_DEF_COMM_0   B9600 | CS8
76#define SH_SCI_DEF_COMM_1   B38400 | CS8
77/*  #define SH_SCI_DEF_COMM_1   B9600 | CS8 */
78
79struct scidev_t {
80  char *                        name;
81  uint32_t                      addr;
82  rtems_device_minor_number     minor;
83  unsigned short                opened;
84  tcflag_t                      cflags;
85} sci_device[SCI_MINOR_DEVICES] =
86{
87  { "/dev/sci0", SH_SCI_BASE_0, 0, 0, SH_SCI_DEF_COMM_0 },
88  { "/dev/sci1", SH_SCI_BASE_1, 1, 0, SH_SCI_DEF_COMM_1 }
89};
90
91/*  local data structures maintain hardware configuration */
92#if UNUSED
93static sci_setup_t sio_param[2];
94#endif
95
96/*  imported from scitab.rel */
97extern int _sci_get_brparms(
98  tcflag_t      cflag,
99  unsigned char *smr,
100  unsigned char *brr
101);
102
103/* Translate termios' tcflag_t into sci settings */
104static int _sci_set_cflags(
105  struct scidev_t  *sci_dev,
106  tcflag_t          c_cflag
107)
108{
109  uint8_t       smr;
110  uint8_t       brr;
111
112  if ( c_cflag & CBAUD )
113  {
114    if ( _sci_get_brparms( c_cflag, &smr, &brr ) != 0 )
115      return -1;
116  }
117
118  if ( c_cflag & CSIZE )
119  {
120    if ( c_cflag & CS8 )
121      smr &= ~SCI_SEVEN_BIT_DATA;
122    else if ( c_cflag & CS7 )
123      smr |= SCI_SEVEN_BIT_DATA;
124    else
125      return -1;
126  }
127
128  if ( c_cflag & CSTOPB )
129    smr |= SCI_STOP_BITS_2;
130  else
131    smr &= ~SCI_STOP_BITS_2;
132
133  if ( c_cflag & PARENB )
134    smr |= SCI_PARITY_ON;
135  else
136    smr &= ~SCI_PARITY_ON;
137
138  if ( c_cflag & PARODD )
139    smr |= SCI_ODD_PARITY;
140  else
141    smr &= ~SCI_ODD_PARITY;
142
143  write8( smr, sci_dev->addr + SCI_SMR );
144  write8( brr, sci_dev->addr + SCI_BRR );
145
146  return 0;
147}
148
149/*
150 * local functions operate SCI ports 0 and 1
151 * called from polling routines or ISRs
152 */
153bool wrtSCI0(unsigned char ch)
154{
155  uint8_t   temp;
156  bool result = false;
157
158  if ((read8(SCI_SSR0) & SCI_TDRE) != 0x00) {
159    /* Write the character to the TDR */
160    write8(ch, SCI_TDR0);
161    /* Clear the TDRE bit */
162    temp = read8(SCI_SSR0) & ~SCI_TDRE;
163    write8(temp, SCI_SSR0);
164    result = true;
165  }
166  return result;
167} /* wrtSCI0 */
168
169bool wrtSCI1(unsigned char ch)
170{
171  uint8_t   temp;
172  bool result = false;
173
174  if ((read8(SCI_SSR1) & SCI_TDRE) != 0x00) {
175     /* Write the character to the TDR */
176     write8(ch, SCI_TDR1);
177     /* Clear the TDRE bit */
178     temp = read8(SCI_SSR1) & ~SCI_TDRE;
179     write8(temp, SCI_SSR1);
180     result = true;
181  }
182  return result;
183} /* wrtSCI1 */
184
185/* polled output steers byte to selected port */
186void sh_sci_outbyte_polled(
187  rtems_device_minor_number  minor,
188  char ch )
189{
190        if (minor == 0) /* blocks until port ready */
191                while (wrtSCI0(ch) != true); /* SCI0*/
192        else
193                while (wrtSCI1(ch) != true); /* SCI1*/
194} /* sh_sci_outbyte_polled */
195
196/*
197 * Initial version calls polled output driver and blocks
198 */
199void outbyte(
200  rtems_device_minor_number  minor,
201  char ch)
202{
203        sh_sci_outbyte_polled(minor, (unsigned char)ch);
204} /* outbyte */
205
206bool rdSCI0(unsigned char *ch)
207{
208  uint8_t   temp;
209  bool result = false;
210
211  if ((read8(SCI_SSR0) & SCI_RDRF) != 0x00) {
212    /* read input */
213    *ch = read8(SCI_RDR0);
214    /* Clear RDRF flag */
215    temp = read8(SCI_SSR0) & ~SCI_RDRF;
216    write8(temp, SCI_SSR0);
217    /* Check for transmission errors */
218    if (temp & (SCI_ORER | SCI_FER | SCI_PER)) {
219        /* TODO: report to RTEMS transmission error */
220
221        /* clear error flags*/
222        temp &= ~(SCI_ORER | SCI_FER | SCI_PER);
223        write8(temp, SCI_SSR0);
224    }
225    result = true;
226  }
227  return result;
228} /* rdSCI0 */
229
230bool rdSCI1(unsigned char *ch)
231{
232  uint8_t   temp;
233  bool result = false;
234
235  if ((read8(SCI_SSR1) & SCI_RDRF) != 0x00) {
236    /* read input */
237    *ch = read8(SCI_RDR1);
238    /* Clear RDRF flag */
239    temp= read8(SCI_SSR1) & ~SCI_RDRF;
240    write8(temp, SCI_SSR1);
241    /* Check for transmission errors */
242    if (temp & (SCI_ORER | SCI_FER | SCI_PER)) {
243        /* TODO: report to RTEMS transmission error */
244
245        /* clear error flags*/
246        temp &= ~(SCI_ORER | SCI_FER | SCI_PER);
247        write8(temp, SCI_SSR1);
248    }
249    result = true;
250  }
251  return result;
252} /* rdSCI1 */
253
254
255/* initial version pulls byte from selected port */
256char sh_sci_inbyte_polled( rtems_device_minor_number  minor )
257{
258  uint8_t ch = 0;
259
260  if (minor == 0) /* blocks until char.ready */
261    while (rdSCI0(&ch) != true); /* SCI0 */
262  else
263    while (rdSCI1(&ch) != true); /* SCI1 */
264  return ch;
265} /* sh_sci_inbyte_polled */
266
267/* Initial version calls polled input driver */
268char inbyte( rtems_device_minor_number  minor )
269{
270  char ch;
271
272  ch = sh_sci_inbyte_polled(minor);
273  return ch;
274} /* inbyte */
275
276
277/*  sh_sci_initialize
278 *
279 *  This routine initializes (registers) the sh_sci IO drivers.
280 *
281 *  Input parameters: ignored
282 *
283 *  Output parameters:  NONE
284 *
285 *  Return values: RTEMS_SUCCESSFUL
286 *   if all sci[...] register, else calls
287 *   rtems_fatal_error_occurred(status)
288 *
289 */
290
291rtems_device_driver sh_sci_initialize(
292  rtems_device_major_number  major,
293  rtems_device_minor_number  minor,
294  void                      *arg )
295{
296  rtems_device_driver status;
297  rtems_device_minor_number i;
298  rtems_driver_name_t driver;
299
300
301  /*
302   * register all possible devices.
303   * the initialization of the hardware is done by sci_open
304   *
305   * One of devices could be previously registered by console
306   * initialization therefore we check it everytime
307   */
308
309  for ( i = 0 ; i < SCI_MINOR_DEVICES ; i++ )
310  {
311    status = rtems_io_lookup_name(
312        sci_device[i].name,
313        &driver);
314    if ( status != RTEMS_SUCCESSFUL )
315    {
316        /* OK. We assume it is not registered yet. */
317        status = rtems_io_register_name(
318            sci_device[i].name,
319            major,
320            sci_device[i].minor );
321        if (status != RTEMS_SUCCESSFUL)
322            rtems_fatal_error_occurred(status);
323    }
324  }
325
326  /* non-default hardware setup occurs in sh_sci_open() */
327
328  return RTEMS_SUCCESSFUL;
329}
330
331
332/*
333 *  Open entry point
334 *   Sets up port and pins for selected sci.
335 */
336
337rtems_device_driver sh_sci_open(
338  rtems_device_major_number major,
339  rtems_device_minor_number minor,
340  void                    * arg )
341{
342  uint8_t   temp8;
343  uint16_t   temp16;
344
345  unsigned      a;
346
347 /* check for valid minor number */
348   if (( minor > ( SCI_MINOR_DEVICES -1 )) || ( minor < 0 ))
349   {
350     return RTEMS_INVALID_NUMBER;
351   }
352
353  /* device already opened */
354  if ( sci_device[minor].opened > 0 )
355  {
356    sci_device[minor].opened++;
357    return RTEMS_SUCCESSFUL;
358  }
359
360  /* set PFC registers to enable I/O pins */
361
362  if ((minor == 0)) {
363    temp16 = read16(PFC_PACRL2);         /* disable SCK0, DMA, IRQ */
364    temp16 &= ~(PA2MD1 | PA2MD0);
365    temp16 |= (PA_TXD0 | PA_RXD0);       /* enable pins for Tx0, Rx0 */
366    write16(temp16, PFC_PACRL2);
367
368  } else if (minor == 1) {
369    temp16 = read16(PFC_PACRL2);          /* disable SCK1, DMA, IRQ */
370    temp16 &= ~(PA5MD1 | PA5MD0);
371    temp16 |= (PA_TXD1 | PA_RXD1);        /* enable pins for Tx1, Rx1 */
372    write16(temp16, PFC_PACRL2);
373
374  } /* add other devices and pins as req'd. */
375
376  /* set up SCI registers */
377      write8(0x00, sci_device[minor].addr + SCI_SCR);    /* Clear SCR */
378                                                   /* set SMR and BRR */
379    _sci_set_cflags( &sci_device[minor], sci_device[minor].cflags );
380
381    for (a=0; a < 10000L; a++) {                      /* Delay */
382      asm volatile ("nop");
383    }
384
385    write8((SCI_RE | SCI_TE),              /* enable async. Tx and Rx */
386           sci_device[minor].addr + SCI_SCR);
387
388    /* clear error flags */
389    temp8 = read8(sci_device[minor].addr + SCI_SSR);
390    while (temp8 & (SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER)) {
391        temp8 = read8(sci_device[minor].addr + SCI_RDR);   /* flush input */
392        temp8 = read8(sci_device[minor].addr + SCI_SSR); /* clear some flags */
393        write8(temp8 & ~(SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER),
394               sci_device[minor].addr + SCI_SSR);
395        temp8 = read8(sci_device[minor].addr + SCI_SSR); /* check if everything is OK */
396    }
397    /* Clear RDRF flag */
398    write8(0x00, sci_device[minor].addr + SCI_TDR);    /* force output */
399     /* Clear the TDRE bit */
400     temp8 = read8(sci_device[minor].addr + SCI_SSR) & ~SCI_TDRE;
401     write8(temp8, sci_device[minor].addr + SCI_SSR);
402
403    /* add interrupt setup if required */
404
405
406  sci_device[minor].opened++;
407
408  return RTEMS_SUCCESSFUL;
409}
410
411/*
412 *  Close entry point
413 */
414
415rtems_device_driver sh_sci_close(
416  rtems_device_major_number major,
417  rtems_device_minor_number minor,
418  void                    * arg
419)
420{
421  /* FIXME: Incomplete */
422  if ( sci_device[minor].opened > 0 )
423    sci_device[minor].opened--;
424  else
425    return RTEMS_INVALID_NUMBER;
426
427  return RTEMS_SUCCESSFUL;
428}
429
430/*
431 * read bytes from the serial port. We only have stdin.
432 */
433
434rtems_device_driver sh_sci_read(
435  rtems_device_major_number major,
436  rtems_device_minor_number minor,
437  void                    * arg
438)
439{
440  rtems_libio_rw_args_t *rw_args;
441  char *buffer;
442  int maximum;
443  int count = 0;
444
445  rw_args = (rtems_libio_rw_args_t *) arg;
446
447  buffer = rw_args->buffer;
448  maximum = rw_args->count;
449
450  for (count = 0; count < maximum; count++) {
451    buffer[ count ] = inbyte(minor);
452    if (buffer[ count ] == '\n' || buffer[ count ] == '\r') {
453      buffer[ count++ ]  = '\n';
454      break;
455    }
456  }
457
458  rw_args->bytes_moved = count;
459  return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
460}
461
462/*
463 * write bytes to the serial port. Stdout and stderr are the same.
464 */
465
466rtems_device_driver sh_sci_write(
467  rtems_device_major_number major,
468  rtems_device_minor_number minor,
469  void                    * arg
470)
471{
472  int count;
473  int maximum;
474  rtems_libio_rw_args_t *rw_args;
475  char *buffer;
476
477  rw_args = (rtems_libio_rw_args_t *) arg;
478
479  buffer = rw_args->buffer;
480  maximum = rw_args->count;
481
482  for (count = 0; count < maximum; count++) {
483    if ( buffer[ count ] == '\n') {
484      outbyte(minor, '\r');
485    }
486    outbyte( minor, buffer[ count ] );
487  }
488
489  rw_args->bytes_moved = maximum;
490  return 0;
491}
492
493/*
494 *  IO Control entry point
495 */
496
497rtems_device_driver sh_sci_control(
498  rtems_device_major_number major,
499  rtems_device_minor_number minor,
500  void                    * arg
501)
502{
503  /* Not yet supported */
504  return RTEMS_SUCCESSFUL;
505}
506
507/*
508 * Termios polled first open
509 */
510static int _sh_sci_poll_first_open(int major, int minor, void *arg)
511{
512    return sh_sci_open(major, minor, arg);
513}
514
515/*
516 * Termios general last close
517 */
518static int _sh_sci_last_close(int major, int minor, void *arg)
519{
520    return sh_sci_close(major, minor, arg);
521}
522
523/*
524 * Termios polled read
525 */
526static int _sh_sci_poll_read(int minor)
527{
528  int value = -1;
529  uint8_t ch = 0;
530
531  if ( minor == 0 ) {
532    if ( rdSCI0( &ch ) )
533      value = (int) ch;
534  } else if ( minor == 1 ) {
535    if ( rdSCI1( &ch ) )
536      value = (int) ch;
537  }
538  return value;
539}
540
541/*
542 * Termios polled write
543 */
544static ssize_t _sh_sci_poll_write(int minor, const char *buf, size_t len)
545{
546    size_t count;
547
548    for (count = 0; count < len; count++)
549        outbyte( minor, buf[count] );
550    return count;
551}
552
553/*
554 * Termios set attributes
555 */
556static int _sh_sci_set_attributes( int minor, const struct termios *t)
557{
558    return _sci_set_cflags( &sci_device[ minor ], t->c_cflag);
559}
560
561
562const rtems_termios_callbacks sci_poll_callbacks = {
563    _sh_sci_poll_first_open,    /* FirstOpen*/
564    _sh_sci_last_close,         /* LastClose*/
565    _sh_sci_poll_read,          /* PollRead  */
566    _sh_sci_poll_write,         /* Write */
567    _sh_sci_set_attributes,     /* setAttributes */
568    NULL,                       /* stopRemoteTX */
569    NULL,                       /* StartRemoteTX */
570    0                           /* outputUsesInterrupts */
571};
572
573/* FIXME: not yet supported */
574const rtems_termios_callbacks sci_interrupt_callbacks;
575
576const rtems_termios_callbacks* sh_sci_get_termios_handlers( bool poll )
577{
578    return poll ?
579        &sci_poll_callbacks :
580        &sci_interrupt_callbacks;
581}
Note: See TracBrowser for help on using the repository browser.