source: rtems/bsps/powerpc/tqm8xx/console/console.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: 21.8 KB
RevLine 
[63de714c]1/*
[eeea4fee]2 * RTEMS TQM8xx BSP
3 *
4 * This file contains the console driver.
5 *
[63de714c]6 *  SMC1/2 SCC1..4 raw console serial I/O.
7 *  adapted to work with up to 4 SCC and 2 SMC
8 *
9 *  This driver is an example of `TASK DRIVEN' `POLLING' or `INTERRUPT' I/O.
10 *
11 *  To run with interrupt-driven I/O, ensure m8xx_smc1_interrupt
12 *  is set before calling the initialization routine.
[eeea4fee]13 */
14
15/*
[753873e5]16 * Copyright (c) 2005 Eric Norum <eric@norum.ca>
[63de714c]17 *
[753873e5]18 * COPYRIGHT (c) 1989-1998.
19 * On-Line Applications Research Corporation (OAR).
20 * Copyright assigned to U.S. Government, 1994.
[63de714c]21 *
[bcef89f2]22 * Copyright (c) 2008 Thomas Doerfler, embedded brains GmbH & Co. KG
[753873e5]23 * All rights reserved.
[eeea4fee]24 *
[753873e5]25 * The license and distribution terms for this file may be
26 * found in the file LICENSE in this distribution or at
27 * http://www.OARcorp.com/rtems/license.html.
[63de714c]28 */
29
30#include <unistd.h>
[2a8afe1]31
32#include <rtems.h>
33#include <rtems/console.h>
[63de714c]34#include <rtems/termiostypes.h>
35#include <rtems/bspIo.h>
[d7637d8d]36#include <rtems/error.h>
[2a8afe1]37
38#include <bsp.h>
39#include <mpc8xx.h>
40#include <bsp/irq.h>
[63de714c]41
42/*
43 * Interrupt-driven input buffer
44 */
[e08dbc5]45#define RXBUFSIZE       16
[63de714c]46
47#define M8xx_SICR_BRG1 (0)
48#define M8xx_SICR_BRG2 (1)
49#define M8xx_SICR_BRG3 (2)
50#define M8xx_SICR_BRG4 (3)
51
52#define M8xx_SICR_SCCRX_MSK(scc) ((  7) << (((scc))*8+3))
53#define M8xx_SICR_SCCRX(scc,clk) ((clk) << (((scc))*8+3))
54
55#define M8xx_SICR_SCCTX_MSK(scc) ((  7) << (((scc))*8+0))
56#define M8xx_SICR_SCCTX(scc,clk) ((clk) << (((scc))*8+0))
57
58#define M8xx_SIMODE_SMCCS(smc,clk) ((clk) << ((smc)*16+12))
59#define M8xx_SIMODE_SMCCS_MSK(smc) M8xx_SIMODE_SMCCS(smc,7)
60
61#define CONS_CHN_CNT 6
62#define CONS_CHN_SCC1 0
63#define CONS_CHN_SCC2 1
64#define CONS_CHN_SCC3 2
65#define CONS_CHN_SCC4 3
66#define CONS_CHN_SMC1 4
67#define CONS_CHN_SMC2 5
[85e87f1]68#define CONS_CHN_NONE -1
[63de714c]69
70/*
71 * possible identifiers for bspopts.h: CONS_SxCy_MODE
72 */
73#define CONS_MODE_UNUSED -1
74#define CONS_MODE_POLLED TERMIOS_POLLED
75#define CONS_MODE_IRQ    TERMIOS_IRQ_DRIVEN
76
77#define CHN_IS_SCC(chan) ((chan) < CONS_CHN_SMC1)
78
79#define BRG_CNT 4
80
81#define MAX_IDL_DEFAULT 10
82#define DEVICEPREFIX "tty"
83
[53fb03fe]84/*
85 * I/O buffers and pointers to buffer descriptors
86 */
87#define SCC_RXBD_CNT 4
88#define SCC_TXBD_CNT 4
[688e101a]89typedef char sccRxBuf_t[SCC_RXBD_CNT][RXBUFSIZE];
[53fb03fe]90
[63de714c]91/*
92 * Interrupt-driven callback
93 */
94typedef struct m8xx_console_chan_desc_s {
[d22147e]95  rtems_termios_device_context base;
[68920e7f]96  volatile m8xxBufferDescriptor_t *sccFrstRxBd;
97  volatile m8xxBufferDescriptor_t *sccCurrRxBd;
98  volatile m8xxBufferDescriptor_t *sccFrstTxBd;
99  volatile m8xxBufferDescriptor_t *sccPrepTxBd;
100  volatile m8xxBufferDescriptor_t *sccDequTxBd;
[63de714c]101  bool is_scc;                  /* true for SCC */
102  struct {
103    volatile m8xxSCCparms_t *sccp;
104    volatile m8xxSMCparms_t *smcp;
105  } parms;
106  struct {
107    volatile m8xxSCCRegisters_t *sccr;
108    volatile m8xxSMCRegisters_t *smcr;
109  } regs;
[68920e7f]110  int chan;
111  rtems_termios_device_mode mode;
[7b93d857]112  rtems_vector_number ivec_src;
[60e5832]113  int cr_chan_code;
114  int brg_used;
[53fb03fe]115  sccRxBuf_t *rxBuf;
[63de714c]116} m8xx_console_chan_desc_t;
117
118m8xx_console_chan_desc_t m8xx_console_chan_desc[CONS_CHN_CNT] = {
119  /* SCC1 */
[53fb03fe]120  { .is_scc = true,
121   .parms = {(m8xxSCCparms_t *)&(m8xx.scc1p),NULL},
122   .regs = {&(m8xx.scc1),NULL},
[68920e7f]123   .chan = CONS_CHN_SCC1,
[53fb03fe]124   .ivec_src = BSP_CPM_IRQ_SCC1,
125   .cr_chan_code = M8xx_CR_CHAN_SCC1,
126   .brg_used = -1},
[63de714c]127  /* SCC2 */
[53fb03fe]128  { .is_scc = true,
129   .parms = {&(m8xx.scc2p),NULL},
130   .regs = {&(m8xx.scc2),NULL},
[68920e7f]131   .chan = CONS_CHN_SCC2,
[53fb03fe]132   .ivec_src = BSP_CPM_IRQ_SCC2,
133   .cr_chan_code = M8xx_CR_CHAN_SCC2,
134   .brg_used = -1},
[63de714c]135  /* SCC3 */
[53fb03fe]136  { .is_scc = true,
137   .parms = {&(m8xx.scc3p),NULL},
138   .regs = {&(m8xx.scc3),NULL},
[68920e7f]139   .chan = CONS_CHN_SCC3,
[53fb03fe]140   .ivec_src = BSP_CPM_IRQ_SCC3,
141   .cr_chan_code = M8xx_CR_CHAN_SCC3,
142   .brg_used = -1},
[63de714c]143  /* SCC4 */
[53fb03fe]144  { .is_scc = true,
145   .parms = {&(m8xx.scc4p),NULL},
146   .regs = {&(m8xx.scc4),NULL},
[68920e7f]147   .chan = CONS_CHN_SCC4,
[53fb03fe]148   .ivec_src = BSP_CPM_IRQ_SCC4,
149   .cr_chan_code = M8xx_CR_CHAN_SCC4,
150   .brg_used = -1},
[63de714c]151  /* SMC1 */
[53fb03fe]152  { .is_scc = false,
153   .parms = {NULL,&(m8xx.smc1p)},
154   .regs = {NULL,&(m8xx.smc1)},
[68920e7f]155   .chan = CONS_CHN_SMC1,
[53fb03fe]156   .ivec_src = BSP_CPM_IRQ_SMC1,
157   .cr_chan_code = M8xx_CR_CHAN_SMC1,
158   .brg_used = -1},
[63de714c]159  /* SMC2 */
[53fb03fe]160  { .is_scc = false,
161   .parms = {NULL,&(m8xx.smc2p)},
162   .regs = {NULL,&(m8xx.smc2)},
[68920e7f]163   .chan = CONS_CHN_SMC2,
[53fb03fe]164   .ivec_src = BSP_CPM_IRQ_SMC2_OR_PIP,
165   .cr_chan_code = M8xx_CR_CHAN_SMC2,
166   .brg_used = -1}};
[63de714c]167
[68920e7f]168#define CHN_PARAM_GET(cd,param) \
169  (cd->is_scc                   \
170   ? cd->parms.sccp->param      \
171   : cd->parms.smcp->param)
[63de714c]172
[68920e7f]173#define CHN_PARAM_SET(cd,param,value)   \
174  do {if (cd->is_scc)                   \
175      cd->parms.sccp->param = value;    \
176    else                                \
177      cd->parms.smcp->param = value;    \
[63de714c]178  } while (0)
179
[68920e7f]180#define CHN_EVENT_GET(cd)       \
181  (cd->is_scc                   \
182   ? cd->regs.sccr->scce        \
183   : cd->regs.smcr->smce)
184
185#define CHN_EVENT_CLR(cd,mask)          \
186  do {                                  \
187    if (cd->is_scc)                     \
188      cd->regs.sccr->scce = (mask);     \
189    else                                \
190      cd->regs.smcr->smce = (mask);     \
[63de714c]191  }while (0)
192
[68920e7f]193#define CHN_MASK_GET(cd)        \
194  (cd->is_scc                   \
195   ? cd->regs.sccr->sccm        \
196   : cd->regs.smcr->smcm)
197
198#define CHN_MASK_SET(cd,mask)           \
199  do {                                  \
200    if (cd->is_scc)                     \
201      cd->regs.sccr->sccm = (mask);     \
202    else                                \
203      cd->regs.smcr->smcm = (mask);     \
[63de714c]204  }while (0)
205
206/*
207 * Compute baud-rate-generator configuration register value
208 */
209static uint32_t
210sccBRGval (int baud)
211{
212  int divisor;
213  int div16 = 0;
214
[60e5832]215  divisor = ((BSP_bus_frequency / 16) + (baud / 2)) / baud;
[63de714c]216  if (divisor > 4096) {
217    div16 = 1;
218    divisor = (divisor + 8) / 16;
219  }
220  return M8xx_BRG_EN | M8xx_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
221}
222
223typedef struct {
224  uint32_t reg_content;
225  int link_cnt;
[ac7af4a]226}brg_state_t;
[63de714c]227brg_state_t scc_brg_state[BRG_CNT];
228
229/*
[ac7af4a]230 * initialize brg_state
[63de714c]231 */
232static void sccBRGinit(void)
233{
234  int brg_idx;
235
236  for (brg_idx = 0;brg_idx < BRG_CNT;brg_idx++) {
237    scc_brg_state[brg_idx].reg_content = 0;
238    scc_brg_state[brg_idx].link_cnt    = 0;
239  }
240#ifndef MDE360
241  /*
242   * on ZEM40, init CLK4/5 inputs
243   */
244  m8xx.papar |=  ((1 << 11) | (1 << 12));
245  m8xx.padir &= ~((1 << 11) | (1 << 12));
246#endif
247}
248
[60e5832]249#if CONS_USE_EXT_CLK
[63de714c]250/*
251 * input clock frq for CPM clock inputs
252 */
253static uint32_t clkin_frq[2][4] = {
254#ifdef MDE360
255  {0,0,0,0},
256  {0,0,0,0}
257#else
258  {0,0,0,1843000},
259  {1843000,0,0,0}
260#endif
261};
[60e5832]262#endif
[63de714c]263
264/*
265 * allocate, set and connect baud rate generators
266 * FIXME: or clock input
267 * FIXME: set pin to be clock input
268 */
269
[d22147e]270static bool sccBRGalloc(m8xx_console_chan_desc_t *cd,int baud)
[63de714c]271{
272  rtems_interrupt_level level;
273  uint32_t reg_val;
274  int old_brg;
275  int new_brg = -1;
276  int brg_idx;
[60e5832]277#if CONS_USE_EXT_CLK
[63de714c]278  int clk_group;
279  int clk_sel;
280#endif
281
[68920e7f]282  old_brg = cd->brg_used;
[63de714c]283  /* compute brg register contents needed */
284  reg_val = sccBRGval(baud);
285
[60e5832]286#if CONS_EXT_CLK
[63de714c]287  /* search for clock input with this frq */
288  clk_group = ((chan == CONS_CHN_SCC3) ||
289               (chan == CONS_CHN_SCC4) ||
290               (chan == CONS_CHN_SMC2)) ? 1 : 0;
291
292  for (clk_sel = 0, new_brg = -1;
293       (clk_sel < 4) && (new_brg < 0);
294       clk_sel++) {
295    if (baud == (clkin_frq[clk_group][clk_sel] / 16)) {
296      new_brg = clk_sel + 4;
297    }
298  }
299#endif
300
[ac7af4a]301  rtems_interrupt_disable(level);
[63de714c]302
303  if (new_brg < 0) {
304    /* search for brg with this settings */
305    for (brg_idx = 0;
306         (new_brg < 0) && (brg_idx < BRG_CNT);
307         brg_idx++) {
308      if (scc_brg_state[brg_idx].reg_content == reg_val) {
309        new_brg = brg_idx;
310      }
311    }
[ac7af4a]312    /*
313     * if not found: check, whether brg currently in use
314     * is linked only from our channel
[63de714c]315     */
316    if ((new_brg < 0) &&
317        (old_brg >= 0) &&
318        (scc_brg_state[old_brg].link_cnt == 1)) {
319      new_brg = old_brg;
320    }
321    /* if not found: search for unused brg, set it  */
322    for (brg_idx = 0;
323         (new_brg < 0) && (brg_idx < BRG_CNT);
324         brg_idx++) {
325      if (scc_brg_state[brg_idx].link_cnt == 0) {
326        new_brg = brg_idx;
327      }
328    }
329  }
330
331  /* decrease old link count */
[ac7af4a]332  if ((old_brg >= 0) &&
[63de714c]333      (old_brg < 4)) {
334    scc_brg_state[old_brg].link_cnt--;
335  }
336  /* increase new brg link count, set brg */
[ac7af4a]337  if ((new_brg >= 0) &&
[63de714c]338      (new_brg < 4)) {
339    scc_brg_state[new_brg].link_cnt++;
340    scc_brg_state[new_brg].reg_content = reg_val;
341    (&m8xx.brgc1)[new_brg] = reg_val;
[ac7af4a]342  }
[63de714c]343  rtems_interrupt_enable(level);
344
345  /* connect to scc/smc */
346  if (new_brg >= 0) {
[68920e7f]347    cd->brg_used = new_brg;
[63de714c]348    /*
349     * Put SCC in NMSI mode, connect SCC to BRG or CLKx
350     */
[68920e7f]351    if (cd->is_scc) {
352      m8xx.sicr = ((m8xx.sicr & ~(M8xx_SICR_SCCRX_MSK(cd->chan) |
353                                  M8xx_SICR_SCCTX_MSK(cd->chan))) |
354                   M8xx_SICR_SCCRX(cd->chan,new_brg)|
355                   M8xx_SICR_SCCTX(cd->chan,new_brg));
[63de714c]356    }
357    else {
358      /* connect SMC to BRGx or CLKx... */
[68920e7f]359      m8xx.simode = ((m8xx.simode & ~(M8xx_SIMODE_SMCCS_MSK(cd->chan - CONS_CHN_SMC1)))|
360                     M8xx_SIMODE_SMCCS(cd->chan - CONS_CHN_SMC1,new_brg));
[63de714c]361    }
[d22147e]362
363    return true;
364  } else {
365    return false;
[63de714c]366  }
367}
368
369
370/*
371 * Hardware-dependent portion of tcsetattr().
372 */
[d22147e]373static bool
374sccSetAttributes (rtems_termios_device_context *base, const struct termios *t)
[63de714c]375{
[d22147e]376  m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
377  speed_t speed;
378  rtems_termios_baud_t baud;
379
380  speed = cfgetispeed(t);
381  if (speed == B0) {
382        speed = cfgetospeed(t);
383  }
384
385  baud = rtems_termios_baud_to_number(speed);
386  if (baud == 0) {
387    return false;
[63de714c]388  }
[d22147e]389
[68920e7f]390  return sccBRGalloc(cd,baud);
[63de714c]391}
392
393/*
[ac7af4a]394 * Interrupt handler
[63de714c]395 */
396static rtems_isr
[60e5832]397sccInterruptHandler (void *arg)
[63de714c]398{
[d22147e]399  rtems_termios_tty *tty = arg;
400  m8xx_console_chan_desc_t *cd = rtems_termios_get_device_context(tty);
[688e101a]401  uint16_t status;
402  uint16_t length;
403  void *buffer;
[63de714c]404
405  /*
406   * Buffer received?
407   */
[68920e7f]408  if (CHN_EVENT_GET(cd) & 0x1) {
[63de714c]409    /*
[ac7af4a]410     * clear SCC event flag
[63de714c]411     */
[68920e7f]412    CHN_EVENT_CLR(cd,0x01);
[63de714c]413    /*
414     * process event
415     */
[688e101a]416    while (true) {
417      status = cd->sccCurrRxBd->status;
418
419      if ((cd->sccCurrRxBd->status & M8xx_BD_EMPTY) != 0) {
420        break;
421      }
422
423      buffer = cd->sccCurrRxBd->buffer;
424      length = cd->sccCurrRxBd->length;
425      rtems_cache_invalidate_multiple_data_lines(buffer, length);
426      rtems_termios_enqueue_raw_characters (tty, buffer, length);
427
[63de714c]428      /*
429       * clear status
430       */
[688e101a]431      cd->sccCurrRxBd->status = (status & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
432        | M8xx_BD_EMPTY;
[63de714c]433      /*
434       * advance to next BD
435       */
[688e101a]436      if ((status & M8xx_BD_WRAP) != 0) {
437        cd->sccCurrRxBd = cd->sccFrstRxBd;
438      } else {
439        cd->sccCurrRxBd++;
[63de714c]440      }
441    }
442  }
443  /*
444   * Buffer transmitted?
445   */
[68920e7f]446  if (CHN_EVENT_GET(cd) & 0x2) {
[63de714c]447    /*
448     * then clear interrupt event bit
449     */
[68920e7f]450    CHN_EVENT_CLR(cd,0x2);
[63de714c]451    /*
452     * and signal successful transmit to termios
453     */
454    /*
455     * FIXME: multiple dequeue calls for multiple buffers
456     */
[688e101a]457    while (cd->sccDequTxBd != cd->sccPrepTxBd) {
458      status = cd->sccDequTxBd->status;
459
460      if ((status & M8xx_BD_READY) != 0) {
461        break;
462      }
463
464      if ((status & M8xx_BD_INTERRUPT) != 0) {
465        rtems_termios_dequeue_characters (tty, cd->sccDequTxBd->length);
466      }
467
[63de714c]468      /*
469       * advance to next BD
470       */
[688e101a]471      if ((status & M8xx_BD_WRAP) != 0) {
472        cd->sccDequTxBd = cd->sccFrstTxBd;
473      } else {
474        cd->sccDequTxBd++;
[63de714c]475      }
476    }
477  }
[60e5832]478}
[63de714c]479
[60e5832]480static void
[68920e7f]481mpc8xx_console_irq_on(m8xx_console_chan_desc_t *cd)
[60e5832]482{
[68920e7f]483    CHN_MASK_SET(cd, 3);        /* Enable TX and RX interrupts */
[63de714c]484}
485
486static void
[68920e7f]487sccInitialize (m8xx_console_chan_desc_t *cd)
[63de714c]488{
489  int i;
490  /*
491   * allocate buffers
492   * FIXME: use a cache-line size boundary alloc here
493   */
[53fb03fe]494  cd->rxBuf = rtems_cache_aligned_malloc(sizeof(*cd->rxBuf));
495  if (cd->rxBuf == NULL) {
[1c193a2]496    rtems_panic("Cannot allocate console rx buffer\n");
[63de714c]497  }
[53fb03fe]498
[63de714c]499  /*
[ac7af4a]500   * Allocate buffer descriptors
[63de714c]501   */
[68920e7f]502  cd->sccCurrRxBd =
503    cd->sccFrstRxBd = m8xx_bd_allocate(SCC_RXBD_CNT);
504  cd->sccPrepTxBd =
505    cd->sccDequTxBd =
506    cd->sccFrstTxBd = m8xx_bd_allocate(SCC_TXBD_CNT);
507  switch(cd->chan) {
[63de714c]508  case CONS_CHN_SCC1:
509    /*
510     * Configure port A pins to enable TXD1 and RXD1 pins
511     * FIXME: add setup for modem control lines....
512     */
513    m8xx.papar |=  0x03;
514    m8xx.padir &= ~0x03;
515
516    /*
517     * Configure port C pins to enable RTS1 pins (static active low)
518     */
519    m8xx.pcpar &= ~0x01;
520    m8xx.pcso  &= ~0x01;
521    m8xx.pcdir |=  0x01;
522    m8xx.pcdat &= ~0x01;
523    break;
524  case CONS_CHN_SCC2:
525    /*
526     * Configure port A pins to enable TXD2 and RXD2 pins
527     * FIXME: add setup for modem control lines....
528     */
529    m8xx.papar |=  0x0C;
530    m8xx.padir &= ~0x0C;
531
532    /*
533     * Configure port C pins to enable RTS2 pins (static active low)
534     */
535    m8xx.pcpar &= ~0x02;
536    m8xx.pcso  &= ~0x02;
537    m8xx.pcdir |=  0x02;
538    m8xx.pcdat &= ~0x02;
539    break;
540  case CONS_CHN_SCC3:
541    /*
542     * Configure port A pins to enable TXD3 and RXD3 pins
543     * FIXME: add setup for modem control lines....
544     */
545    m8xx.papar |=  0x30;
546    m8xx.padir &= ~0x30;
547
548    /*
549     * Configure port C pins to enable RTS3 (static active low)
550     */
551    m8xx.pcpar &= ~0x04;
552    m8xx.pcso  &= ~0x04;
553    m8xx.pcdir |=  0x04;
554    m8xx.pcdat &= ~0x04;
555    break;
556  case CONS_CHN_SCC4:
557    /*
558     * Configure port A pins to enable TXD4 and RXD4 pins
559     * FIXME: add setup for modem control lines....
560     */
561    m8xx.papar |=  0xC0;
562    m8xx.padir &= ~0xC0;
563
564    /*
565     * Configure port C pins to enable RTS4 pins (static active low)
566     */
567    m8xx.pcpar &= ~0x08;
568    m8xx.pcso  &= ~0x08;
569    m8xx.pcdir |=  0x08;
570    m8xx.pcdat &= ~0x08;
571    break;
572  case CONS_CHN_SMC1:
573    /*
574     * Configure port B pins to enable SMTXD1 and SMRXD1 pins
575     */
[ac7af4a]576    m8xx.pbpar |=  0xC0;
[63de714c]577    m8xx.pbdir &= ~0xC0;
578    break;
579  case CONS_CHN_SMC2:
580    /*
581     * Configure port B pins to enable SMTXD2 and SMRXD2 pins
582     */
583    m8xx.pbpar |=  0xC00;
584    m8xx.pbdir &= ~0xC00;
585    break;
586  }
587  /*
[ac7af4a]588   * allocate and connect BRG
[63de714c]589   */
[68920e7f]590  sccBRGalloc(cd,9600);
[ac7af4a]591
592
[63de714c]593  /*
594   * Set up SCCx parameter RAM common to all protocols
595   */
[68920e7f]596  CHN_PARAM_SET(cd,rbase,(char *)cd->sccFrstRxBd - (char *)&m8xx);
597  CHN_PARAM_SET(cd,tbase,(char *)cd->sccFrstTxBd - (char *)&m8xx);
598  CHN_PARAM_SET(cd,rfcr ,M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0));
599  CHN_PARAM_SET(cd,tfcr ,M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0));
600  if (cd->mode != TERMIOS_POLLED)
601    CHN_PARAM_SET(cd,mrblr,RXBUFSIZE);
[63de714c]602  else
[68920e7f]603    CHN_PARAM_SET(cd,mrblr,1);
[ac7af4a]604
[63de714c]605  /*
606   * Set up SCCx parameter RAM UART-specific parameters
607   */
[68920e7f]608  CHN_PARAM_SET(cd,un.uart.max_idl ,MAX_IDL_DEFAULT);
609  CHN_PARAM_SET(cd,un.uart.brkln   ,0);
610  CHN_PARAM_SET(cd,un.uart.brkec   ,0);
611  CHN_PARAM_SET(cd,un.uart.brkcr   ,0);
612  if (cd->is_scc) {
613    cd->parms.sccp->un.uart.character[0]=0x8000; /* no char filter */
614    cd->parms.sccp->un.uart.rccm=0x80FF; /* control character mask */
[63de714c]615  }
[ac7af4a]616
[63de714c]617  /*
618   * Set up the Receive Buffer Descriptors
619   */
620  for (i = 0;i < SCC_RXBD_CNT;i++) {
[68920e7f]621    cd->sccFrstRxBd[i].status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT;
[63de714c]622    if (i == SCC_RXBD_CNT-1) {
[68920e7f]623      cd->sccFrstRxBd[i].status |= M8xx_BD_WRAP;
[63de714c]624    }
[68920e7f]625    cd->sccFrstRxBd[i].length = 0;
626    cd->sccFrstRxBd[i].buffer = (*cd->rxBuf)[i];
[63de714c]627  }
628  /*
629   * Setup the Transmit Buffer Descriptor
630   */
631  for (i = 0;i < SCC_TXBD_CNT;i++) {
[68920e7f]632    cd->sccFrstTxBd[i].status = M8xx_BD_INTERRUPT;
[63de714c]633    if (i == SCC_TXBD_CNT-1) {
[68920e7f]634      cd->sccFrstTxBd[i].status |= M8xx_BD_WRAP;
[63de714c]635    }
[68920e7f]636    cd->sccFrstTxBd[i].length = 0;
637    cd->sccFrstTxBd[i].buffer = NULL;
[63de714c]638  }
[ac7af4a]639
[63de714c]640  /*
641   * Set up SCC general and protocol-specific mode registers
642   */
[68920e7f]643  CHN_EVENT_CLR(cd,~0); /* Clear any pending events */
644  CHN_MASK_SET(cd,0);           /* Mask all interrupt/event sources */
[ac7af4a]645
[68920e7f]646  if (cd->is_scc) {
647    cd->regs.sccr->psmr = 0xb000; /* 8N1, CTS flow control */
648    cd->regs.sccr->gsmr_h = 0x00000000;
649    cd->regs.sccr->gsmr_l = 0x00028004; /* UART mode */
[63de714c]650  }
651  else {
[68920e7f]652    cd->regs.smcr->smcmr = 0x4820;
[63de714c]653  }
654  /*
655   * Send "Init parameters" command
656   */
[68920e7f]657  m8xx_cp_execute_cmd(M8xx_CR_OP_INIT_RX_TX | cd->cr_chan_code);
[ac7af4a]658
[63de714c]659  /*
660   * Enable receiver and transmitter
661   */
[68920e7f]662  if (cd->is_scc) {
663    cd->regs.sccr->gsmr_l |= 0x00000030;
[63de714c]664  }
665  else {
[68920e7f]666    cd->regs.smcr->smcmr |= 0x0003;
[63de714c]667  }
668}
669
670/*
671 * polled scc read function
672 */
673static int
[d22147e]674sccPollRead (rtems_termios_device_context *base)
[63de714c]675{
[d22147e]676  m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
[e08dbc5]677  int c = -1;
[63de714c]678
[e08dbc5]679  while(1) {
[68920e7f]680    if ((cd->sccCurrRxBd->status & M8xx_BD_EMPTY) != 0) {
[e08dbc5]681      return -1;
682    }
[ac7af4a]683
[68920e7f]684    if (0 == (cd->sccCurrRxBd->status & (M8xx_BD_OVERRUN
[ac7af4a]685                                           | M8xx_BD_PARITY_ERROR
[e08dbc5]686                                           | M8xx_BD_FRAMING_ERROR
687                                           | M8xx_BD_BREAK
688                                           | M8xx_BD_IDLE))) {
689      /* character received and no error detected */
[68920e7f]690      rtems_cache_invalidate_multiple_data_lines((void *)cd->sccCurrRxBd->buffer,
691                                                 cd->sccCurrRxBd->length);
692      c = (unsigned)*((char *)cd->sccCurrRxBd->buffer);
[e08dbc5]693      /*
694       * clear status
695       */
696    }
[68920e7f]697    cd->sccCurrRxBd->status =
698      (cd->sccCurrRxBd->status
[e08dbc5]699       & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
700      | M8xx_BD_EMPTY;
701    /*
702     * advance to next BD
703     */
[68920e7f]704    if ((cd->sccCurrRxBd->status & M8xx_BD_WRAP) != 0) {
705      cd->sccCurrRxBd = cd->sccFrstRxBd;
[e08dbc5]706    }
707    else {
[68920e7f]708      cd->sccCurrRxBd++;
[e08dbc5]709    }
710    if (c >= 0) {
711      return c;
712    }
[63de714c]713  }
714}
715
716
717/*
718 * Device-dependent write routine
719 * Interrupt-driven devices:
720 *      Begin transmission of as many characters as possible (minimum is 1).
721 * Polling devices:
722 *      Transmit all characters.
723 */
[d22147e]724static void
725sccInterruptWrite (rtems_termios_device_context *base, const char *buf, size_t len)
[63de714c]726{
[688e101a]727  m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
728
[e18db9f]729  if (len > 0) {
[688e101a]730    uint16_t status = cd->sccPrepTxBd->status;
731
732    if ((status & M8xx_BD_READY) == 0) {
733      cd->sccPrepTxBd->buffer = RTEMS_DECONST(char*, buf);
[68920e7f]734      cd->sccPrepTxBd->length = len;
[688e101a]735      rtems_cache_flush_multiple_data_lines(buf, len);
736
[e18db9f]737      /*
738       * clear status, set ready bit
739       */
[688e101a]740      cd->sccPrepTxBd->status = (status & M8xx_BD_WRAP)
[e18db9f]741        | M8xx_BD_READY | M8xx_BD_INTERRUPT;
[688e101a]742
743      if ((status & M8xx_BD_WRAP) != 0) {
[68920e7f]744        cd->sccPrepTxBd = cd->sccFrstTxBd;
[688e101a]745      } else {
[68920e7f]746        cd->sccPrepTxBd++;
[e18db9f]747      }
[63de714c]748    }
749  }
750}
751
[d22147e]752static void
753sccPollWrite (rtems_termios_device_context *base, const char *buf, size_t len)
[63de714c]754{
[d22147e]755  m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
[688e101a]756  volatile m8xxBufferDescriptor_t *bd = NULL;
757
758  rtems_cache_flush_multiple_data_lines (buf, len);
759
760  while (bd == NULL) {
761    rtems_interrupt_level level;
762    uint16_t status;
763
764    rtems_interrupt_disable(level);
765
766    bd = cd->sccPrepTxBd;
767    status = bd->status;
768
769    if ((status & M8xx_BD_READY) == 0) {
770      bd->buffer = RTEMS_DECONST (char *, buf);
771      bd->length = len;
772      bd->status = (status & M8xx_BD_WRAP) | M8xx_BD_READY;
773
774      if ((status & M8xx_BD_WRAP) != 0) {
775        cd->sccPrepTxBd = cd->sccFrstTxBd;
776      } else {
777        cd->sccPrepTxBd++;
778      }
779    } else {
780      bd = NULL;
[63de714c]781    }
[688e101a]782
783    rtems_interrupt_enable(level);
784  }
785
786  while ((bd->status & M8xx_BD_READY) != 0) {
787    /* Wait */
[63de714c]788  }
789}
790
[85e87f1]791/*
792 * printk basic support
793 */
794int BSP_output_chan = CONS_CHN_NONE; /* channel used for printk operation */
795
796static void console_debug_putc_onlcr(const char c)
797{
798  rtems_interrupt_level irq_level;
799
800  if (BSP_output_chan != CONS_CHN_NONE) {
801    rtems_interrupt_disable(irq_level);
[ac7af4a]802
[d22147e]803    sccPollWrite (&m8xx_console_chan_desc[BSP_output_chan].base,&c,1);
[85e87f1]804    rtems_interrupt_enable(irq_level);
805  }
806}
807
[989938f1]808BSP_output_char_function_type     BSP_output_char = console_debug_putc_onlcr;
809BSP_polling_getchar_function_type BSP_poll_char = NULL;
[85e87f1]810
811
[63de714c]812/*
813***************
814* BOILERPLATE *
815***************
816*/
817
818struct {
819  rtems_device_minor_number minor;
820  int driver_mode;
821} channel_list[] = {
822  {CONS_CHN_SMC1,CONS_SMC1_MODE},
823  {CONS_CHN_SMC2,CONS_SMC2_MODE},
824  {CONS_CHN_SCC1,CONS_SCC1_MODE},
825  {CONS_CHN_SCC2,CONS_SCC2_MODE},
826  {CONS_CHN_SCC3,CONS_SCC3_MODE},
827  {CONS_CHN_SCC4,CONS_SCC4_MODE}
828};
829
[d22147e]830static bool m8xx_console_first_open(
831  rtems_termios_tty *tty,
832  rtems_termios_device_context *base,
833  struct termios *term,
834  rtems_libio_open_close_args_t *args
835)
836{
837  m8xx_console_chan_desc_t *cd = (m8xx_console_chan_desc_t *)base;
838
839  if (cd->mode == TERMIOS_IRQ_DRIVEN) {
840    rtems_status_code sc;
841
842    sc = rtems_interrupt_handler_install(
843      cd->ivec_src,
844      "SCC",
845      RTEMS_INTERRUPT_UNIQUE,
846      sccInterruptHandler,
847      tty
848    );
849    if (sc != RTEMS_SUCCESSFUL) {
850      return false;
851    }
852
853    mpc8xx_console_irq_on(cd);
854  }
855
856  return true;
857}
858
859static const rtems_termios_device_handler m8xx_console_handler_polled = {
860  .first_open = m8xx_console_first_open,
861  .set_attributes = sccSetAttributes,
862  .write = sccPollWrite,
863  .poll_read = sccPollRead,
864  .mode = TERMIOS_POLLED
865};
866
867static const rtems_termios_device_handler m8xx_console_handler_irq_driven = {
868  .first_open = m8xx_console_first_open,
869  .set_attributes = sccSetAttributes,
870  .write = sccInterruptWrite,
871  .mode = TERMIOS_IRQ_DRIVEN
872};
[63de714c]873
874/*
875 * Initialize and register the device
876 */
877rtems_device_driver console_initialize(rtems_device_major_number  major,
878                                       rtems_device_minor_number  minor,/* ignored */
879                                       void                      *arg
880                                       )
881{
882  rtems_status_code status = RTEMS_SUCCESSFUL;
[68920e7f]883  int entry,ttynum;
[63de714c]884  char tty_name[] = "/dev/tty00";
885
886  /*
887   * Set up TERMIOS
888   */
889  rtems_termios_initialize ();
890  /*
891   * init BRG allocataion
892   */
893  sccBRGinit();
894  ttynum = 0;
895  for (entry = 0;
896       (entry < sizeof(channel_list)/sizeof(channel_list[0]))
897         && (status == RTEMS_SUCCESSFUL);
898       entry++) {
899    if (channel_list[entry].driver_mode != CONS_MODE_UNUSED) {
[68920e7f]900      m8xx_console_chan_desc_t *cd =
[d22147e]901        &m8xx_console_chan_desc[channel_list[entry].minor];
[63de714c]902      /*
903       * Do device-specific initialization
904       */
[68920e7f]905      cd->mode = channel_list[entry].driver_mode;
906      sccInitialize (cd);
[63de714c]907
908      /*
909       * build device name
910       */
911      tty_name[sizeof(tty_name)-2] = '0'+ttynum;
912      ttynum++;
913      /*
914       * Register the device
915       */
[d22147e]916      status = rtems_termios_device_install(
917        tty_name,
918        cd->mode == TERMIOS_IRQ_DRIVEN ?
919          &m8xx_console_handler_irq_driven : &m8xx_console_handler_polled,
920        NULL,
921        &cd->base
922      );
[63de714c]923      if (status != RTEMS_SUCCESSFUL) {
924        rtems_fatal_error_occurred (status);
925      }
926
[d22147e]927      if (cd->chan == CONSOLE_CHN) {
928        int rv;
[63de714c]929
[d22147e]930        rv = link(tty_name, CONSOLE_DEVICE_NAME);
931        if (rv != 0) {
932          rtems_fatal_error_occurred (RTEMS_IO_ERROR);
[63de714c]933        }
934      }
935    }
936  }
937
[d22147e]938  /*
939   * enable printk support
940   */
941  BSP_output_chan = PRINTK_CHN;
[63de714c]942
[d22147e]943  return RTEMS_SUCCESSFUL;
[63de714c]944}
Note: See TracBrowser for help on using the repository browser.