source: rtems/c/src/lib/libbsp/powerpc/mpc55xxevb/console/console-esci.c @ 6273201

4.115
Last change on this file since 6273201 was a762dc2, checked in by Sebastian Huber <sebastian.huber@…>, on 01/23/12 at 10:19:22

Support for MPC5643L.

Rework of the start sequence to reduce the amount assembler code and to
support configuration tables which may be provided by the application.

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