source: rtems/bsps/powerpc/mpc55xxevb/console/console-esci.c @ 762fa62

5
Last change on this file since 762fa62 was d7d66d7, checked in by Sebastian Huber <sebastian.huber@…>, on 04/19/18 at 04:28:01

bsps: Move console drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief Console ESCI implementation.
5 */
6
7/*
8 * Copyright (c) 2008-2012 embedded brains GmbH.  All rights reserved.
9 *
10 *  embedded brains GmbH
11 *  Obere Lagerstr. 30
12 *  82178 Puchheim
13 *  Germany
14 *  <rtems@embedded-brains.de>
15 *
16 * The license and distribution terms for this file may be
17 * found in the file LICENSE in this distribution or at
18 * http://www.rtems.org/license/LICENSE.
19 */
20
21#include <bsp/console-esci.h>
22
23#include <bsp.h>
24#include <bsp/fatal.h>
25#include <bsp/irq.h>
26
27#ifdef MPC55XX_HAS_ESCI
28
29mpc55xx_esci_context mpc55xx_esci_devices [] = {
30  {
31    .regs = &ESCI_A,
32    .irq = MPC55XX_IRQ_ESCI(0)
33  }
34  #ifdef ESCI_B
35    , {
36      .regs = &ESCI_B,
37      .irq = MPC55XX_IRQ_ESCI(1)
38    }
39  #endif
40  #ifdef ESCI_C
41    , {
42      .regs = &ESCI_C,
43      .irq = MPC55XX_IRQ_ESCI(2)
44    }
45  #endif
46  #ifdef ESCI_D
47    , {
48      .regs = &ESCI_D,
49      .irq = MPC55XX_IRQ_ESCI(3)
50    }
51  #endif
52};
53
54static void mpc55xx_esci_poll_write(int minor, char c)
55{
56  mpc55xx_esci_context *self = console_generic_get_context(minor);
57  const union ESCI_SR_tag clear_tdre = { .B = { .TDRE = 1 } };
58  volatile struct ESCI_tag *regs = self->regs;
59  rtems_interrupt_level level;
60  bool done = false;
61  bool wait_for_transmit_done = false;
62
63  rtems_interrupt_disable(level);
64  if (self->transmit_nest_level == 0) {
65    union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
66
67    if (cr1.B.TIE != 0) {
68      cr1.B.TIE = 0;
69      regs->CR1.R = cr1.R;
70      wait_for_transmit_done = !self->transmit_in_progress;
71      self->transmit_nest_level = 1;
72    }
73  } else {
74    ++self->transmit_nest_level;
75  }
76  rtems_interrupt_enable(level);
77
78  while (!done) {
79    rtems_interrupt_disable(level);
80    bool tx = self->transmit_in_progress;
81    if (!tx || (tx && regs->SR.B.TDRE)) {
82      regs->SR.R = clear_tdre.R;
83      regs->DR.B.D = c;
84      self->transmit_in_progress = true;
85      done = true;
86    }
87    rtems_interrupt_enable(level);
88  }
89
90  done = false;
91  while (!done) {
92    rtems_interrupt_disable(level);
93    if (wait_for_transmit_done) {
94      if (regs->SR.B.TDRE) {
95        regs->SR.R = clear_tdre.R;
96        self->transmit_in_progress = false;
97        done = true;
98      }
99    } else {
100      done = true;
101    }
102
103    if (done && self->transmit_nest_level > 0) {
104      --self->transmit_nest_level;
105
106      if (self->transmit_nest_level == 0) {
107        union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
108
109        cr1.B.TIE = 1;
110        regs->CR1.R = cr1.R;
111      }
112    }
113    rtems_interrupt_enable(level);
114  }
115}
116
117static inline void mpc55xx_esci_interrupts_clear_and_enable(
118  mpc55xx_esci_context *self
119)
120{
121  volatile struct ESCI_tag *regs = self->regs;
122  union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
123  rtems_interrupt_level level;
124
125  rtems_interrupt_disable(level);
126  cr1.R = regs->CR1.R;
127  cr1.B.RIE = 1;
128  cr1.B.TIE = 1;
129  regs->CR1.R = cr1.R;
130  regs->SR.R = regs->SR.R;
131  rtems_interrupt_enable(level);
132}
133
134static inline void mpc55xx_esci_interrupts_disable(mpc55xx_esci_context *self)
135{
136  volatile struct ESCI_tag *regs = self->regs;
137  union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
138  rtems_interrupt_level level;
139
140  rtems_interrupt_disable(level);
141  cr1.R = regs->CR1.R;
142  cr1.B.RIE = 0;
143  cr1.B.TIE = 0;
144  regs->CR1.R = cr1.R;
145  rtems_interrupt_enable(level);
146}
147
148static void mpc55xx_esci_interrupt_handler(void *arg)
149{
150  mpc55xx_esci_context *self = arg;
151  volatile struct ESCI_tag *regs = self->regs;
152  union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
153  union ESCI_SR_tag active = MPC55XX_ZERO_FLAGS;
154  rtems_interrupt_level level;
155
156  /* Status */
157  sr.R = regs->SR.R;
158
159  /* Receive data register full? */
160  if (sr.B.RDRF != 0) {
161    active.B.RDRF = 1;
162  }
163
164  /* Transmit data register empty? */
165  if (sr.B.TDRE != 0) {
166    active.B.TDRE = 1;
167  }
168
169  /* Clear flags */
170  rtems_interrupt_disable(level);
171  regs->SR.R = active.R;
172  self->transmit_in_progress = false;
173  rtems_interrupt_enable(level);
174
175  /* Enqueue */
176  if (active.B.RDRF != 0) {
177    char c = regs->DR.B.D;
178    rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
179  }
180
181  /* Dequeue */
182  if (active.B.TDRE != 0) {
183    rtems_termios_dequeue_characters(self->tty, 1);
184  }
185}
186
187static int mpc55xx_esci_set_attributes(int minor, const struct termios *t)
188{
189  mpc55xx_esci_context *self = console_generic_get_context(minor);
190  volatile struct ESCI_tag *regs = self->regs;
191  union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
192  union ESCI_CR2_tag cr2 = MPC55XX_ZERO_FLAGS;
193  rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
194
195  /* Enable module */
196  cr2.B.MDIS = 0;
197
198  /* Interrupts */
199  cr1.B.TCIE = 0;
200  cr1.B.ILIE = 0;
201  cr2.B.IEBERR = 0;
202  cr2.B.ORIE = 0;
203  cr2.B.NFIE = 0;
204  cr2.B.FEIE = 0;
205  cr2.B.PFIE = 0;
206
207  /* Disable receiver wake-up standby */
208  cr1.B.RWU = 0;
209
210  /* Disable DMA channels */
211  cr2.B.RXDMA = 0;
212  cr2.B.TXDMA = 0;
213
214  /* Idle line type */
215  cr1.B.ILT = 0;
216
217  /* Disable loops */
218  cr1.B.LOOPS = 0;
219
220  /* Enable or disable receiver */
221  cr1.B.RE = (t->c_cflag & CREAD) ? 1 : 0;
222
223  /* Enable transmitter */
224  cr1.B.TE = 1;
225
226  /* Baud rate */
227  if (br > 0) {
228    br = bsp_clock_speed / (16 * br);
229    br = (br > 8191) ? 8191 : br;
230  } else {
231    br = 0;
232  }
233  cr1.B.SBR = br;
234
235  /* Number of data bits */
236  if ((t->c_cflag & CSIZE) != CS8) {
237    return -1;
238  }
239  cr1.B.M = 0;
240
241  /* Parity */
242  cr1.B.PE = (t->c_cflag & PARENB) ? 1 : 0;
243  cr1.B.PT = (t->c_cflag & PARODD) ? 1 : 0;
244
245  /* Stop bits */
246  if (t->c_cflag & CSTOPB ) {
247    /* Two stop bits */
248    return -1;
249  }
250
251  /* Disable LIN */
252  regs->LCR.R = 0;
253
254  /* Set control registers */
255  regs->CR2.R = cr2.R;
256  regs->CR1.R = cr1.R;
257
258  return 0;
259}
260
261static int mpc55xx_esci_first_open(int major, int minor, void *arg)
262{
263  rtems_status_code sc = RTEMS_SUCCESSFUL;
264  int rv = 0;
265  mpc55xx_esci_context *self = console_generic_get_context(minor);
266  struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
267
268  self->tty = tty;
269
270  rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
271  if (rv != 0) {
272    bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_BAUD);
273  }
274
275  rv = mpc55xx_esci_set_attributes(minor, &tty->termios);
276  if (rv != 0) {
277    bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_ATTRIBUTES);
278  }
279
280  sc = mpc55xx_interrupt_handler_install(
281    self->irq,
282    "eSCI",
283    RTEMS_INTERRUPT_UNIQUE,
284    MPC55XX_INTC_DEFAULT_PRIORITY,
285    mpc55xx_esci_interrupt_handler,
286    self
287  );
288  if (sc != RTEMS_SUCCESSFUL) {
289    bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_IRQ_INSTALL);
290  }
291
292  mpc55xx_esci_interrupts_clear_and_enable(self);
293  self->transmit_in_progress = false;
294
295  return 0;
296}
297
298static int mpc55xx_esci_last_close(int major, int minor, void* arg)
299{
300  mpc55xx_esci_context *self = console_generic_get_context(minor);
301
302  mpc55xx_esci_interrupts_disable(self);
303  self->tty = NULL;
304
305  return 0;
306}
307
308static int mpc55xx_esci_poll_read(int minor)
309{
310  mpc55xx_esci_context *self = console_generic_get_context(minor);
311  volatile struct ESCI_tag *regs = self->regs;
312  union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
313  rtems_interrupt_level level;
314  int c = -1;
315
316  rtems_interrupt_disable(level);
317  if (regs->SR.B.RDRF != 0) {
318    /* Clear flag */
319    sr.B.RDRF = 1;
320    regs->SR.R = sr.R;
321
322    /* Read */
323    c = regs->DR.B.D;
324  }
325  rtems_interrupt_enable(level);
326
327  return c;
328}
329
330static int mpc55xx_esci_write(int minor, const char *out, size_t n)
331{
332  if (n > 0) {
333    mpc55xx_esci_context *self = console_generic_get_context(minor);
334
335    self->regs->DR.B.D = out [0];
336    self->transmit_in_progress = true;
337  }
338
339  return 0;
340}
341
342const console_generic_callbacks mpc55xx_esci_callbacks = {
343  .termios_callbacks = {
344    .firstOpen = mpc55xx_esci_first_open,
345    .lastClose = mpc55xx_esci_last_close,
346    .write = mpc55xx_esci_write,
347    .setAttributes = mpc55xx_esci_set_attributes,
348    .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
349  },
350  .poll_read = mpc55xx_esci_poll_read,
351  .poll_write = mpc55xx_esci_poll_write
352};
353
354#endif /* MPC55XX_HAS_ESCI */
Note: See TracBrowser for help on using the repository browser.