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

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

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