source: rtems/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c @ 8df196f7

5
Last change on this file since 8df196f7 was 8df196f7, checked in by Pavel Pisa <pisa@…>, on 12/07/15 at 15:59:35

bsp/tms570: include complete peripheral initialization to SCI driver.

Signed-off-by: Pavel Pisa <pisa@…>

  • Property mode set to 100644
File size: 16.1 KB
Line 
1/**
2 * @file tms570-sci.c
3 *
4 * @ingroup tms570
5 *
6 * @brief Serial communication interface (SCI) functions definitions.
7 */
8
9/*
10 * Copyright (c) 2014 Premysl Houdek <kom541000@gmail.com>
11 *
12 * Google Summer of Code 2014 at
13 * Czech Technical University in Prague
14 * Zikova 1903/4
15 * 166 36 Praha 6
16 * Czech Republic
17 *
18 * Based on LPC24xx and LPC1768 BSP
19 * by embedded brains GmbH and others
20 *
21 * The license and distribution terms for this file may be
22 * found in the file LICENSE in this distribution or at
23 * http://www.rtems.org/license/LICENSE.
24 */
25
26#include <bspopts.h>
27#include <termios.h>
28#include <rtems/termiostypes.h>
29#include <bsp/tms570-sci.h>
30#include <bsp/tms570-sci-driver.h>
31#include <rtems/console.h>
32#include <bsp.h>
33#include <bsp/fatal.h>
34#include <bsp/irq.h>
35
36#define TMS570_SCI_BUFFER_SIZE 1
37
38/**
39 * @brief Table including all serial drivers
40 *
41 * Definitions of all serial drivers
42 */
43tms570_sci_context driver_context_table[] = {
44  {
45    .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("TMS570 SCI1"),
46    .device_name = "/dev/console",
47    /* TMS570 UART peripheral use subset of LIN registers which are equivalent
48     * to SCI ones
49     */
50    .regs = (volatile tms570_sci_t *) &TMS570_LIN,
51    .irq = TMS570_IRQ_SCI_LEVEL_0,
52  },
53  {
54    .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("TMS570 SCI2"),
55    .device_name = "/dev/ttyS1",
56    .regs = &TMS570_SCI,
57    .irq = TMS570_IRQ_SCI2_LEVEL_0,
58  }
59};
60
61/**
62 * @brief Serial drivers init function
63 *
64 * Initialize all serial drivers specified in driver_context_table
65 *
66 * @param[in] major
67 * @param[in] minor
68 * @param[in] arg
69 * @retval RTEMS_SUCCESSFUL Initialization completed
70 */
71rtems_device_driver console_initialize(
72  rtems_device_major_number  major,
73  rtems_device_minor_number  minor,
74  void                      *arg
75)
76{
77  rtems_status_code sc;
78#if CONSOLE_USE_INTERRUPTS
79  const rtems_termios_device_handler *handler = &tms570_sci_handler_interrupt;
80#else
81  const rtems_termios_device_handler *handler = &tms570_sci_handler_polled;
82#endif
83
84  /*
85   * Initialize the Termios infrastructure.  If Termios has already
86   * been initialized by another device driver, then this call will
87   * have no effect.
88   */
89  rtems_termios_initialize();
90
91  /* Initialize each device */
92  for (
93    minor = 0;
94    minor < RTEMS_ARRAY_SIZE(driver_context_table);
95    ++minor
96  ) {
97    tms570_sci_context *ctx = &driver_context_table[minor];
98    uint32_t rx_pin = 1 << 1;
99    uint32_t tx_pin = 1 << 2;
100
101    /* Resec SCI peripheral */
102    ctx->regs->GCR0 = TMS570_SCI_GCR0_RESET * 0;
103    ctx->regs->GCR0 = TMS570_SCI_GCR0_RESET * 1;
104
105    /* Clear all interrupt sources */
106    ctx->regs->CLEARINT = 0xffffffff;
107
108    /* Map all interrupts to SCI INT0 line */
109    ctx->regs->CLEARINTLVL = 0xffffffff;
110
111    ctx->regs->GCR1 = TMS570_SCI_GCR1_TXENA * 0 |
112                      TMS570_SCI_GCR1_RXENA * 0 |
113                      TMS570_SCI_GCR1_CONT * 0 | /* continue operation when debugged */
114                      TMS570_SCI_GCR1_LOOP_BACK * 0 |
115                      TMS570_SCI_GCR1_POWERDOWN * 0 |
116                      TMS570_SCI_GCR1_SLEEP * 0 |
117                      TMS570_SCI_GCR1_SWnRST * 0 | /* reset state */
118                      TMS570_SCI_GCR1_CLOCK * 1 | /* internal clock */
119                      TMS570_SCI_GCR1_TIMING_MODE * 1 |
120                      TMS570_SCI_GCR1_COMM_MODE * 0;
121
122    /* Setup connection of SCI peripheral Rx and Tx  pins */
123    ctx->regs->PIO0 = rx_pin * 1 | tx_pin * 1; /* Rx and Tx pins are not GPIO */
124    ctx->regs->PIO3 = rx_pin * 0 | tx_pin * 0; /* Default output low  */
125    ctx->regs->PIO1 = rx_pin * 0 | tx_pin * 0; /* Input when not used by SCI */
126    ctx->regs->PIO6 = rx_pin * 0 | tx_pin * 0; /* No open drain */
127    ctx->regs->PIO7 = rx_pin * 0 | tx_pin * 0; /* Pull-up/down enabled */
128    ctx->regs->PIO8 = rx_pin * 1 | tx_pin * 1; /* Select pull-up */
129
130    /* Bring device out of software reset */
131    ctx->regs->GCR1 |= TMS570_SCI_GCR1_SWnRST;
132
133    /*
134     * Install this device in the file system and Termios.  In order
135     * to use the console (i.e. being able to do printf, scanf etc.
136     * on stdin, stdout and stderr), one device must be registered as
137     * "/dev/console" (CONSOLE_DEVICE_NAME).
138     */
139    sc = rtems_termios_device_install(
140        ctx->device_name,
141        major,
142        minor,
143        handler,
144        NULL,
145        &ctx->base
146    );
147    if ( sc != RTEMS_SUCCESSFUL ) {
148      bsp_fatal(BSP_FATAL_CONSOLE_NO_DEV);
149    }
150  }
151  return RTEMS_SUCCESSFUL;
152}
153
154/**
155 * @brief Reads chars from HW
156 *
157 * Reads chars from HW peripheral specified in driver context.
158 * TMS570 does not have HW buffer for serial line so this function can
159 * return only 0 or 1 char
160 *
161 * @param[in] ctx context of the driver
162 * @param[out] buf read data buffer
163 * @param[in] N size of buffer
164 * @retval x Number of read chars from peripherals
165 */
166static int tms570_sci_read_received_chars(
167  tms570_sci_context * ctx,
168  char * buf,
169  int N)
170{
171  if ( N < 1 ) {
172    return 0;
173  }
174  if ( ctx->regs->RD != 0 ) {
175     buf[0] = ctx->regs->RD;
176    return 1;
177  }
178  return 0;
179}
180
181/**
182 * @brief Enables RX interrupt
183 *
184 * Enables RX interrupt source of SCI peripheral
185 * specified in the driver context.
186 *
187 * @param[in] ctx context of the driver
188 * @retval Void
189 */
190static void tms570_sci_enable_interrupts(tms570_sci_context * ctx)
191{
192  ctx->regs->SETINT = TMS570_SCI_SETINT_SET_RX_INT;
193}
194
195/**
196 * @brief Disables RX interrupt
197 *
198 * Disables RX interrupt source of SCI peripheral specified in the driver
199 * context.
200 *
201 * @param[in] ctx context of the driver
202 * @retval Void
203 */
204static void tms570_sci_disable_interrupts(tms570_sci_context * ctx)
205{
206  ctx->regs->CLEARINT = TMS570_SCI_CLEARINT_CLR_RX_INT;
207}
208
209/**
210 * @brief Check whether driver has put char in HW
211 *
212 * Check whether driver has put char in HW.
213 * This information is read from the driver context not from a peripheral.
214 * TMS570 does not have write data buffer asociated with SCI
215 * so the return can be only 0 or 1.
216 *
217 * @param[in] ctx context of the driver
218 * @retval x
219 */
220static int tms570_sci_transmitted_chars(tms570_sci_context * ctx)
221{
222  int ret;
223
224  ret = ctx->tx_chars_in_hw;
225  if ( ret == 1 ) {
226    ctx->tx_chars_in_hw = 0;
227    return 1;
228  }
229  return ret;
230}
231
232/**
233 * @brief Set attributes of the HW peripheral
234 *
235 * Sets attributes of the HW peripheral (parity, baud rate, etc.)
236 *
237 * @param[in] base context of the driver
238 * @param[in] t termios driver
239 * @retval true peripheral setting is changed
240 */
241static bool tms570_sci_set_attributes(
242  rtems_termios_device_context *base,
243  const struct termios *t
244)
245{
246  tms570_sci_context *ctx = (tms570_sci_context *) base;
247  rtems_interrupt_lock_context lock_context;
248  int32_t bauddiv;
249  int32_t baudrate;
250
251  rtems_termios_device_lock_acquire(base, &lock_context);
252
253  ctx->regs->GCR1 &= ~( TMS570_SCI_GCR1_SWnRST | TMS570_SCI_GCR1_TXENA |
254                        TMS570_SCI_GCR1_RXENA );
255
256  ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_STOP;    /*one stop bit*/
257  ctx->regs->FORMAT = TMS570_SCI_FORMAT_CHAR(0x7);
258
259  switch ( t->c_cflag & ( PARENB|PARODD ) ) {
260    case ( PARENB|PARODD ):
261      /* Odd parity */
262      ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_PARITY;
263      ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY_ENA;
264      break;
265
266    case PARENB:
267      /* Even parity */
268      ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY;
269      ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY_ENA;
270      break;
271
272    default:
273    case 0:
274    case PARODD:
275      /* No Parity */
276      ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_PARITY_ENA;
277  }
278
279  /* Baud rate */
280  baudrate = rtems_termios_baud_to_number(cfgetospeed(t));
281  baudrate *= 2 * 16;
282  bauddiv = (BSP_PLL_OUT_CLOCK + baudrate / 2) / baudrate;
283  ctx->regs->BRS = bauddiv;
284
285  ctx->regs->GCR1 |= TMS570_SCI_GCR1_SWnRST | TMS570_SCI_GCR1_TXENA |
286                     TMS570_SCI_GCR1_RXENA;
287
288  rtems_termios_device_lock_release(base, &lock_context);
289
290  return true;
291}
292
293/**
294 * @brief sci interrupt handler
295 *
296 * Handler checks which interrupt occured and provides nessesary maintenance
297 * dequeue characters in termios driver whether character is send succesfully
298 * enqueue characters in termios driver whether character is recieved
299 *
300 * @param[in] arg rtems_termios_tty
301 * @retval Void
302 */
303static void tms570_sci_interrupt_handler(void * arg)
304{
305  rtems_termios_tty *tty = arg;
306  tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
307  char buf[TMS570_SCI_BUFFER_SIZE];
308  size_t n;
309
310  /*
311   * Check if we have received something.
312   */
313   if ( (ctx->regs->FLR & TMS570_SCI_FLR_RXRDY ) == TMS570_SCI_FLR_RXRDY ) {
314      n = tms570_sci_read_received_chars(ctx, buf, TMS570_SCI_BUFFER_SIZE);
315      if ( n > 0 ) {
316        /* Hand the data over to the Termios infrastructure */
317        rtems_termios_enqueue_raw_characters(tty, buf, n);
318      }
319    }
320  /*
321   * Check if we have something transmitted.
322   */
323  if ( (ctx->regs->FLR & TMS570_SCI_FLR_TXRDY ) == TMS570_SCI_FLR_TXRDY ) {
324    n = tms570_sci_transmitted_chars(ctx);
325    if ( n > 0 ) {
326      /*
327       * Notify Termios that we have transmitted some characters.  It
328       * will call now the interrupt write function if more characters
329       * are ready for transmission.
330       */
331      rtems_termios_dequeue_characters(tty, n);
332    }
333  }
334}
335
336/**
337 * @brief sci write function called from interrupt
338 *
339 * Nonblocking write function. Writes characters to HW peripheral
340 * TMS570 does not have write data buffer asociated with SCI
341 * so only one character can be written.
342 *
343 * @param[in] base context of the driver
344 * @param[in] buf buffer of characters pending to send
345 * @param[in] len size of the buffer
346 * @retval Void
347 */
348static void tms570_sci_interrupt_write(
349  rtems_termios_device_context *base,
350  const char *buf,
351  size_t len
352)
353{
354  tms570_sci_context *ctx = (tms570_sci_context *) base;
355
356  if ( len > 0 ) {
357    /* start UART TX, this will result in an interrupt when done */
358    ctx->regs->TD = *buf;
359    /* character written - raise count*/
360    ctx->tx_chars_in_hw = 1;
361    /* Enable TX interrupt (interrupt is edge-triggered) */
362    ctx->regs->SETINT = (1<<8);
363
364  } else {
365    /* No more to send, disable TX interrupts */
366    ctx->regs->CLEARINT = (1<<8);
367    /* Tell close that we sent everything */
368  }
369}
370
371/**
372 * @brief sci write function
373 *
374 * Blocking write function. Waits until HW peripheral is ready and then writes
375 * character to HW peripheral. Writes all characters in the buffer.
376 *
377 * @param[in] base context of the driver
378 * @param[in] buf buffer of characters pending to send
379 * @param[in] len size of the buffer
380 * @retval Void
381 */
382static void tms570_sci_poll_write(
383  rtems_termios_device_context *base,
384  const char *buf,
385  size_t n
386)
387{
388  tms570_sci_context *ctx = (tms570_sci_context *) base;
389  size_t i;
390
391  /* Write */
392
393  for ( i = 0; i < n; ++i ) {
394    while ( (ctx->regs->FLR & TMS570_SCI_FLR_TX_EMPTY ) == 0) {
395      ;
396    }
397    ctx->regs->TD = buf[i];
398  }
399}
400
401/**
402 * @brief See if there is recieved charakter to read
403 *
404 * read the RX flag from peripheral specified in context
405 *
406 * @param[in] ctx context of the driver
407 * @retval 0 No character to read
408 * @retval x Character ready to read
409 */
410static int TMS570_sci_can_read_char(
411  tms570_sci_context * ctx
412)
413{
414  return ctx->regs->FLR & TMS570_SCI_FLR_RXRDY;
415}
416
417/**
418 * @brief reads character from peripheral
419 *
420 * reads the recieved character from peripheral specified in context
421 *
422 * @param[in] ctx context of the driver
423 * @retval x Character
424 */
425static char TMS570_sci_read_char(
426  tms570_sci_context * ctx
427)
428{
429  return ctx->regs->RD;
430}
431
432/**
433 * @brief sci read function
434 *
435 * check if there is recieved character to be read and reads it.
436 *
437 * @param[in] base context of the driver
438 * @retval -1 No character to be read
439 * @retval x Read character
440 */
441static int tms570_sci_poll_read(rtems_termios_device_context *base)
442{
443  tms570_sci_context *ctx = (tms570_sci_context *) base;
444
445  /* Check if a character is available */
446  if ( TMS570_sci_can_read_char(ctx) ) {
447    return TMS570_sci_read_char(ctx);
448  } else {
449    return -1;
450  }
451}
452
453/**
454 * @brief initialization of the driver
455 *
456 * initialization of the HW peripheral specified in contex of the driver.
457 * This function is called only once when opening the driver.
458 *
459 * @param[in] tty Termios control
460 * @param[in] ctx context of the driver
461 * @param[in] term Termios attributes
462 * @param[in] args
463 * @retval false Error occured during initialization
464 * @retval true Driver is open and ready
465 */
466static bool tms570_sci_poll_first_open(
467  rtems_termios_tty             *tty,
468  rtems_termios_device_context  *ctx,
469  struct termios                *term,
470  rtems_libio_open_close_args_t *args
471)
472{
473  bool ok;
474
475  rtems_termios_set_best_baud(term, TMS570_SCI_BAUD_RATE);
476  ok = tms570_sci_set_attributes(ctx, term);
477  if ( !ok ) {
478    return false;
479  }
480  return true;
481}
482
483/**
484 * @brief initialization of the interrupt driven driver
485 *
486 * calls tms570_sci_poll_first_open function.
487 * install and enables interrupts.
488 *
489 * @param[in] tty Termios control
490 * @param[in] base context of the driver
491 * @param[in] args
492 * @retval false Error occured during initialization
493 * @retval true Driver is open and ready
494 */
495static bool tms570_sci_interrupt_first_open(
496  rtems_termios_tty             *tty,
497  rtems_termios_device_context  *base,
498  struct termios                *term,
499  rtems_libio_open_close_args_t *args
500)
501{
502  tms570_sci_context *ctx = (tms570_sci_context *) base;
503  rtems_status_code sc;
504  bool ret;
505
506  ret = tms570_sci_poll_first_open(tty, base, term, args);
507  if ( ret == false ) {
508    return false;
509  }
510
511  /* Register Interrupt handler */
512  sc = rtems_interrupt_handler_install(ctx->irq,
513      ctx->device_name,
514      RTEMS_INTERRUPT_SHARED,
515      tms570_sci_interrupt_handler,
516      tty
517  );
518  if ( sc != RTEMS_SUCCESSFUL ) {
519    return false;
520  }
521  tms570_sci_enable_interrupts(ctx);
522  return true;
523}
524
525/**
526 * @brief closes sci peripheral
527 *
528 * @param[in] tty Termios control
529 * @param[in] base context of the driver
530 * @param[in] args
531 * @retval false Error occured during initialization
532 * @retval true Driver is open and ready
533 */
534static void tms570_sci_poll_last_close(
535  rtems_termios_tty             *tty,
536  rtems_termios_device_context  *base,
537  rtems_libio_open_close_args_t *args
538)
539{
540  ;
541}
542
543/**
544 * @brief closes sci peripheral of interrupt driven driver
545 *
546 * calls tms570_sci_poll_last_close and disables interrupts
547 *
548 * @param[in] tty Termios control
549 * @param[in] base context of the driver
550 * @param[in] args
551 * @retval false Error occured during initialization
552 * @retval true Driver is open and ready
553 */
554static void tms570_sci_interrupt_last_close(
555  rtems_termios_tty             *tty,
556  rtems_termios_device_context  *base,
557  rtems_libio_open_close_args_t *args
558)
559{
560  tms570_sci_context *ctx = (tms570_sci_context *) base;
561  rtems_interrupt_lock_context lock_context;
562  rtems_interval tw;
563  int32_t baudrate;
564
565  /* Turn off RX interrupts */
566  rtems_termios_device_lock_acquire(base, &lock_context);
567  tms570_sci_disable_interrupts(ctx);
568  rtems_termios_device_lock_release(base, &lock_context);
569
570  tw = rtems_clock_get_ticks_per_second();
571  baudrate = rtems_termios_baud_to_number(cfgetospeed(&tty->termios));
572  tw = tw * 10 / baudrate + 1;
573  while ( ( ctx->regs->FLR & TMS570_SCI_FLR_TX_EMPTY ) == 0 ) {
574     rtems_task_wake_after(tw);
575  }
576
577  /* uninstall ISR */
578  rtems_interrupt_handler_remove(ctx->irq, tms570_sci_interrupt_handler, tty);
579
580  tms570_sci_poll_last_close(tty, base, args);
581}
582
583/**
584 * @brief Struct containing definitions of polled driver functions.
585 *
586 * Encapsulates polled driver functions.
587 * Use of this table is determited by not defining TMS570_USE_INTERRUPTS
588 */
589const rtems_termios_device_handler tms570_sci_handler_polled = {
590  .first_open = tms570_sci_poll_first_open,
591  .last_close = tms570_sci_poll_last_close,
592  .poll_read = tms570_sci_poll_read,
593  .write = tms570_sci_poll_write,
594  .set_attributes = tms570_sci_set_attributes,
595  .mode = TERMIOS_POLLED
596};
597
598/**
599 * @brief Struct containing definitions of interrupt driven driver functions.
600 *
601 * Encapsulates interrupt driven driver functions.
602 * Use of this table is determited by defining TMS570_USE_INTERRUPTS
603 */
604const rtems_termios_device_handler tms570_sci_handler_interrupt  = {
605  .first_open = tms570_sci_interrupt_first_open,
606  .last_close = tms570_sci_interrupt_last_close,
607  .poll_read = NULL,
608  .write = tms570_sci_interrupt_write,
609  .set_attributes = tms570_sci_set_attributes,
610  .mode = TERMIOS_IRQ_DRIVEN
611};
Note: See TracBrowser for help on using the repository browser.