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

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