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

Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on Mar 21, 2017 at 7:39:48 PM

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

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