source: rtems/c/src/lib/libbsp/powerpc/mpc55xxevb/console/console-linflex.c @ 1301468

5
Last change on this file since 1301468 was 1301468, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 3, 2017 at 10:51:51 AM

bsps: Fix baud settings

Update #2897.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/**
2 * @file
3 *
4 * @brief Console LINFlexD implementation.
5 */
6
7/*
8 * Copyright (c) 2011-2014 embedded brains GmbH.  All rights reserved.
9 *
10 *  embedded brains GmbH
11 *  Dornierstr. 4
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-linflex.h>
22
23#include <bsp.h>
24#include <bsp/fatal.h>
25#include <bsp/irq.h>
26
27#ifdef MPC55XX_HAS_LINFLEX
28
29mpc55xx_linflex_context mpc55xx_linflex_devices [] = {
30  {
31    .regs = &LINFLEX0,
32    .irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(0),
33    .irq_txi = MPC55XX_IRQ_LINFLEX_TXI(0),
34    .irq_err = MPC55XX_IRQ_LINFLEX_ERR(0),
35    .tx_pcr_register = &((SIU_tag *) &SIUL)->PCR18,
36    .tx_pa_value = 1,
37    .rx_pcr_register = &((SIU_tag *) &SIUL)->PCR19,
38    .rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI31,
39    .rx_padsel_value = 0
40  }, {
41    .regs = &LINFLEX1,
42    .irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(1),
43    .irq_txi = MPC55XX_IRQ_LINFLEX_TXI(1),
44    .irq_err = MPC55XX_IRQ_LINFLEX_ERR(1),
45    .tx_pcr_register = &((SIU_tag *) &SIUL)->PCR94,
46    .tx_pa_value = 1,
47    .rx_pcr_register = &((SIU_tag *) &SIUL)->PCR95,
48    .rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI32,
49    .rx_padsel_value = 2
50  }
51};
52
53static void enter_init_mode(volatile LINFLEX_tag *regs)
54{
55  LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
56  cr1.B.SLEEP = 0;
57  cr1.B.INIT = 1;
58  regs->LINCR1.R = cr1.R;
59}
60
61static void enter_active_mode(volatile LINFLEX_tag *regs)
62{
63  LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
64  cr1.B.SLEEP = 0;
65  cr1.B.INIT = 0;
66  regs->LINCR1.R = cr1.R;
67}
68
69static void enter_sleep_mode(volatile LINFLEX_tag *regs)
70{
71  LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
72  cr1.B.SLEEP = 1;
73  cr1.B.INIT = 0;
74  regs->LINCR1.R = cr1.R;
75}
76
77static void mpc55xx_linflex_poll_write(int minor, char c)
78{
79  mpc55xx_linflex_context *self = console_generic_get_context(minor);
80  volatile LINFLEX_tag *regs = self->regs;
81  const LINFLEX_UARTSR_32B_tag clear_dtf = { .B = { .DTF_TFF = 1 } };
82  rtems_interrupt_level level;
83  bool done = false;
84  bool wait_for_transmit_done = false;
85
86  rtems_interrupt_disable(level);
87  if (self->transmit_nest_level == 0) {
88        LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
89
90        if (ier.B.DTIE != 0) {
91          ier.B.DTIE = 0;
92          regs->LINIER.R = ier.R;
93          wait_for_transmit_done = !self->transmit_in_progress;
94          self->transmit_nest_level = 1;
95        }
96  } else {
97        ++self->transmit_nest_level;
98  }
99  rtems_interrupt_enable(level);
100
101  while (!done) {
102        rtems_interrupt_disable(level);
103        bool tx = self->transmit_in_progress;
104        if (!tx || (tx && regs->UARTSR.B.DTF_TFF)) {
105          regs->UARTSR.R = clear_dtf.R;
106          regs->BDRL.B.DATA0 = c;
107          self->transmit_in_progress = true;
108          done = true;
109        }
110        rtems_interrupt_enable(level);
111  }
112
113  done = false;
114  while (!done) {
115        rtems_interrupt_disable(level);
116        if (wait_for_transmit_done) {
117          if (regs->UARTSR.B.DTF_TFF) {
118                regs->UARTSR.R = clear_dtf.R;
119                self->transmit_in_progress = false;
120                done = true;
121          }
122        } else {
123          done = true;
124        }
125
126        if (done && self->transmit_nest_level > 0) {
127          --self->transmit_nest_level;
128
129          if (self->transmit_nest_level == 0) {
130        LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
131
132        ier.B.DTIE = 1;
133                regs->LINIER.R = ier.R;
134          }
135        }
136        rtems_interrupt_enable(level);
137  }
138}
139
140static void mpc55xx_linflex_rx_interrupt_handler(void *arg)
141{
142  mpc55xx_linflex_context *self = arg;
143  volatile LINFLEX_tag *regs = self->regs;
144  char c = regs->BDRM.B.DATA4;
145  const LINFLEX_UARTSR_32B_tag clear_flags = { .B = { .RMB = 1, .DRF_RFE = 1 } };
146
147  regs->UARTSR.R = clear_flags.R;
148
149  rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
150}
151
152static void mpc55xx_linflex_tx_interrupt_handler(void *arg)
153{
154  mpc55xx_linflex_context *self = arg;
155  volatile LINFLEX_tag *regs = self->regs;
156
157  regs->UARTSR.B.DTF_TFF = 1;   /* clear flag */
158  self->transmit_in_progress = false;
159
160  rtems_termios_dequeue_characters(self->tty, 1);
161}
162
163/*
164static void mpc55xx_linflex_err_interrupt_handler(void *arg)
165{
166  mpc55xx_linflex_context *self = arg;
167}
168*/
169
170static int mpc55xx_linflex_set_attributes(int minor, const struct termios *t)
171{
172  mpc55xx_linflex_context *self = console_generic_get_context(minor);
173  volatile LINFLEX_tag *regs = self->regs;
174  LINFLEX_UARTCR_32B_tag uartcr = { .R = 0 };
175  LINFLEX_GCR_32B_tag gcr = { .R = 0 };
176  LINFLEX_LINIER_32B_tag ier = { .R = 0 };
177  rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
178  LINFLEX_LINFBRR_32B_tag fbrr = { .R = 0 };
179  LINFLEX_LINIBRR_32B_tag ibrr = { .R = 0 };
180
181  enter_init_mode(regs);
182
183  /* Set to UART-mode */
184  uartcr.B.UART = 1;
185  regs->UARTCR.R = uartcr.R;
186
187  /* Set to buffer mode with size 1 */
188  uartcr.B.TDFL_TFC = 0;
189  uartcr.B.RDFL_RFC0 = 0;
190  uartcr.B.RFBM = 0;
191  uartcr.B.TFBM = 0;
192
193  /* Enable receiver and transmitter */
194  uartcr.B.RXEN = 1;
195  uartcr.B.TXEN = 1;
196
197  /* Number of data bits */
198  uartcr.B.WL1 = 0;
199  if ((t->c_cflag & CSIZE) == CS8) {
200        uartcr.B.WL0 = 1;
201  } else if ((t->c_cflag & CSIZE) == CS7) {
202        uartcr.B.WL0 = 0;
203  } else {
204    return -1;
205  }
206
207  /* Parity */
208  uartcr.B.PCE = (t->c_cflag & PARENB) ? 1 : 0;
209  uartcr.B.PC1 = 0;
210  uartcr.B.PC0 = (t->c_cflag & PARODD) ? 1 : 0;
211
212  /* Stop bits */
213  gcr.B.STOP = (t->c_cflag & CSTOPB) ? 1 : 0;
214
215  /* Set control registers */
216  regs->UARTCR.R = uartcr.R;
217  regs->GCR.R = gcr.R;
218
219  /* Interrupts */
220  ier.B.DTIE = 1;
221  ier.B.DRIE = 1;
222  regs->LINIER.R = ier.R;
223
224  /* Baud rate */
225  if (br > 0) {
226        uint32_t lfdiv_mult_32 = bsp_clock_speed * 2 / br;
227        if((lfdiv_mult_32 & 0x1) != 0) {
228                ++lfdiv_mult_32;
229        }
230        fbrr.B.FBR = (lfdiv_mult_32 >> 1) & 0xF;
231        ibrr.B.IBR = lfdiv_mult_32 >> 5;
232  } else {
233    return -1;
234  }
235  regs->LINFBRR.R = fbrr.R;
236  regs->LINIBRR.R = ibrr.R;
237
238  enter_active_mode(regs);
239
240  return 0;
241}
242
243static int mpc55xx_linflex_first_open(int major, int minor, void *arg)
244{
245  rtems_status_code sc = RTEMS_SUCCESSFUL;
246  int rv = 0;
247  mpc55xx_linflex_context *self = console_generic_get_context(minor);
248  struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
249  SIU_PCR_tag pcr = { .R = 0 };
250  SIUL_PSMI_8B_tag psmi = { .R = 0 };
251
252  self->tty = tty;
253
254  pcr.B.IBE = 1;
255  self->rx_pcr_register->R = pcr.R;
256  psmi.B.PADSEL = self->rx_padsel_value;
257  self->rx_psmi_register->R = psmi.R;
258  pcr.R = 0;
259  pcr.B.OBE = 1;
260  pcr.B.PA = self->tx_pa_value;
261  self->tx_pcr_register->R = pcr.R;
262
263  rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
264  if (rv != 0) {
265    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_BAUD);
266  }
267
268  rv = mpc55xx_linflex_set_attributes(minor, &tty->termios);
269  if (rv != 0) {
270    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ATTRIBUTES);
271  }
272
273  sc = mpc55xx_interrupt_handler_install(
274    self->irq_rxi,
275    "LINFlexD RXI",
276    RTEMS_INTERRUPT_UNIQUE,
277    MPC55XX_INTC_DEFAULT_PRIORITY,
278    mpc55xx_linflex_rx_interrupt_handler,
279    self
280  );
281  if (sc != RTEMS_SUCCESSFUL) {
282    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_INSTALL);
283  }
284
285  sc = mpc55xx_interrupt_handler_install(
286    self->irq_txi,
287    "LINFlexD TXI",
288    RTEMS_INTERRUPT_UNIQUE,
289    MPC55XX_INTC_DEFAULT_PRIORITY,
290    mpc55xx_linflex_tx_interrupt_handler,
291    self
292  );
293  if (sc != RTEMS_SUCCESSFUL) {
294    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_INSTALL);
295  }
296
297  /*
298  sc = mpc55xx_interrupt_handler_install(
299    self->irq_err,
300    "LINFlexD ERR",
301    RTEMS_INTERRUPT_UNIQUE,
302    MPC55XX_INTC_DEFAULT_PRIORITY,
303    mpc55xx_linflex_err_interrupt_handler,
304    self
305  );
306  if (sc != RTEMS_SUCCESSFUL) {
307    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ERR_IRQ_INSTALL);
308  }
309  */
310
311  return 0;
312}
313
314static int mpc55xx_linflex_last_close(int major, int minor, void* arg)
315{
316  rtems_status_code sc = RTEMS_SUCCESSFUL;
317  mpc55xx_linflex_context *self = console_generic_get_context(minor);
318  volatile LINFLEX_tag *regs = self->regs;
319  SIU_PCR_tag pcr = { .R = 0 };
320  SIUL_PSMI_8B_tag psmi = { .R = 0 };
321
322  /* enter initialization mode */
323  enter_init_mode(regs);
324
325  /* disable interrupts */
326  regs->LINIER.R = 0;
327
328  /* set module to sleep mode */
329  enter_sleep_mode(regs);
330
331  sc = rtems_interrupt_handler_remove(
332    self->irq_rxi,
333    mpc55xx_linflex_rx_interrupt_handler,
334    self
335  );
336  if (sc != RTEMS_SUCCESSFUL) {
337    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_REMOVE);
338  }
339
340  sc = rtems_interrupt_handler_remove(
341    self->irq_txi,
342    mpc55xx_linflex_tx_interrupt_handler,
343    self
344  );
345  if (sc != RTEMS_SUCCESSFUL) {
346    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_REMOVE);
347  }
348
349  /*
350  sc = rtems_interrupt_handler_remove(
351    self->irq_err,
352    mpc55xx_linflex_err_interrupt_handler,
353    self
354  );
355  if (sc != RTEMS_SUCCESSFUL) {
356    bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ERR_IRQ_REMOVE);
357  }
358  */
359
360  pcr.B.IBE = 1;
361  self->rx_pcr_register->R = pcr.R;
362  self->tx_pcr_register->R = pcr.R;
363  psmi.R = 0;
364  self->rx_psmi_register->R = psmi.R;
365
366  self->tty = NULL;
367
368  return 0;
369}
370
371static int mpc55xx_linflex_poll_read(int minor)
372{
373  mpc55xx_linflex_context *self = console_generic_get_context(minor);
374  volatile LINFLEX_tag *regs = self->regs;
375  rtems_interrupt_level level;
376  int c = -1;
377
378  rtems_interrupt_disable(level);
379  if (regs->UARTSR.B.DRF_RFE != 0) {
380    /* Clear flag */
381    regs->UARTSR.B.DRF_RFE = 1;
382
383    /* Read */
384    c = regs->BDRM.B.DATA4;
385  }
386  rtems_interrupt_enable(level);
387
388  return c;
389}
390
391static int mpc55xx_linflex_write(int minor, const char *out, size_t n)
392{
393  if (n > 0) {
394    mpc55xx_linflex_context *self = console_generic_get_context(minor);
395    volatile LINFLEX_tag *regs = self->regs;
396
397    regs->BDRL.B.DATA0 = out [0];
398    self->transmit_in_progress = true;
399    /* TODO: send more then one byte */
400  }
401
402  return 0;
403}
404
405const console_generic_callbacks mpc55xx_linflex_callbacks = {
406  .termios_callbacks = {
407    .firstOpen = mpc55xx_linflex_first_open,
408    .lastClose = mpc55xx_linflex_last_close,
409    .write = mpc55xx_linflex_write,
410    .setAttributes = mpc55xx_linflex_set_attributes,
411    .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
412  },
413  .poll_read = mpc55xx_linflex_poll_read,
414  .poll_write = mpc55xx_linflex_poll_write
415};
416
417#endif /* MPC55XX_HAS_LINFLEX */
Note: See TracBrowser for help on using the repository browser.