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

4.115
Last change on this file since 52c8df84 was 52c8df84, checked in by Peter Dufault <dufault@…>, on 10/01/12 at 13:43:22

bsp/mpc55xx: PR2077: Add BSP_DEFAULT_BAUD_RATE

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