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

Last change on this file was bcef89f2, checked in by Sebastian Huber <sebastian.huber@…>, on 05/19/23 at 06:18:25

Update company name

The embedded brains GmbH & Co. KG is the legal successor of embedded
brains GmbH.

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