source: rtems/c/src/lib/libbsp/powerpc/tqm8xx/console/console.c @ 1c6926c1

Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on Mar 21, 2017 at 7:39:48 PM

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

  • Property mode set to 100644
File size: 28.1 KB
Line 
1/*===============================================================*\
2| Project: RTEMS TQM8xx BSP                                       |
3+-----------------------------------------------------------------+
4| This file has been adapted to MPC8xx by                         |
5|    Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>         |
6|                    Copyright (c) 2008                           |
7|                    Embedded Brains GmbH                         |
8|                    Obere Lagerstr. 30                           |
9|                    D-82178 Puchheim                             |
10|                    Germany                                      |
11|                    rtems@embedded-brains.de                     |
12|                                                                 |
13| See the other copyright notice below for the original parts.    |
14+-----------------------------------------------------------------+
15| The license and distribution terms for this file may be         |
16| found in the file LICENSE in this distribution or at            |
17|                                                                 |
18| http://www.rtems.org/license/LICENSE.                           |
19|                                                                 |
20+-----------------------------------------------------------------+
21| this file contains the console driver                           |
22\*===============================================================*/
23/* derived from: */
24/*
25 *  SMC1/2 SCC1..4 raw console serial I/O.
26 *  adapted to work with up to 4 SCC and 2 SMC
27 *
28 *  This driver is an example of `TASK DRIVEN' `POLLING' or `INTERRUPT' I/O.
29 *
30 *  To run with interrupt-driven I/O, ensure m8xx_smc1_interrupt
31 *  is set before calling the initialization routine.
32 *
33 *  Author:
34 *    W. Eric Norum
35 *    Saskatchewan Accelerator Laboratory
36 *    University of Saskatchewan
37 *    Saskatoon, Saskatchewan, CANADA
38 *    eric@skatter.usask.ca
39 *
40 *  COPYRIGHT (c) 1989-1998.
41 *  On-Line Applications Research Corporation (OAR).
42 *  Copyright assigned to U.S. Government, 1994.
43 *
44 *  The license and distribution terms for this file may be
45 *  found in the file LICENSE in this distribution or at
46 *  http://www.OARcorp.com/rtems/license.html.
47 */
48
49#include <stdio.h>
50#include <stdlib.h>
51#include <termios.h>
52#include <unistd.h>
53
54#include <rtems.h>
55#include <rtems/console.h>
56#include <rtems/libio.h>
57#include <rtems/termiostypes.h>
58#include <rtems/bspIo.h>
59#include <rtems/error.h>
60#include <rtems/irq.h>
61
62#include <bsp.h>
63#include <mpc8xx.h>
64#include <bsp/irq.h>
65
66/*
67 * Interrupt-driven input buffer
68 */
69#define RXBUFSIZE       16
70
71#define M8xx_SICR_BRG1 (0)
72#define M8xx_SICR_BRG2 (1)
73#define M8xx_SICR_BRG3 (2)
74#define M8xx_SICR_BRG4 (3)
75
76#define M8xx_SICR_SCCRX_MSK(scc) ((  7) << (((scc))*8+3))
77#define M8xx_SICR_SCCRX(scc,clk) ((clk) << (((scc))*8+3))
78
79#define M8xx_SICR_SCCTX_MSK(scc) ((  7) << (((scc))*8+0))
80#define M8xx_SICR_SCCTX(scc,clk) ((clk) << (((scc))*8+0))
81
82#define M8xx_SIMODE_SMCCS(smc,clk) ((clk) << ((smc)*16+12))
83#define M8xx_SIMODE_SMCCS_MSK(smc) M8xx_SIMODE_SMCCS(smc,7)
84
85#define CONS_CHN_CNT 6
86#define CONS_CHN_SCC1 0
87#define CONS_CHN_SCC2 1
88#define CONS_CHN_SCC3 2
89#define CONS_CHN_SCC4 3
90#define CONS_CHN_SMC1 4
91#define CONS_CHN_SMC2 5
92#define CONS_CHN_NONE -1
93
94/*
95 * possible identifiers for bspopts.h: CONS_SxCy_MODE
96 */
97#define CONS_MODE_UNUSED -1
98#define CONS_MODE_POLLED TERMIOS_POLLED
99#define CONS_MODE_IRQ    TERMIOS_IRQ_DRIVEN
100
101#define CHN_IS_SCC(chan) ((chan) < CONS_CHN_SMC1)
102
103#define BRG_CNT 4
104
105#define MAX_IDL_DEFAULT 10
106#define DEVICEPREFIX "tty"
107
108/*
109 * Interrupt-driven callback
110 */
111static int m8xx_scc_mode[CONS_CHN_CNT];
112static void *sccttyp[CONS_CHN_CNT];
113typedef struct m8xx_console_chan_desc_s {
114  bool is_scc;                  /* true for SCC */
115  struct {
116    volatile m8xxSCCparms_t *sccp;
117    volatile m8xxSMCparms_t *smcp;
118  } parms;
119  struct {
120    volatile m8xxSCCRegisters_t *sccr;
121    volatile m8xxSMCRegisters_t *smcr;
122  } regs;
123  int ivec_src;
124  int cr_chan_code;
125  int brg_used;
126} m8xx_console_chan_desc_t;
127
128m8xx_console_chan_desc_t m8xx_console_chan_desc[CONS_CHN_CNT] = {
129  /* SCC1 */
130  {TRUE,
131   {(m8xxSCCparms_t *)&(m8xx.scc1p),NULL},
132   {&(m8xx.scc1),NULL},
133   BSP_CPM_IRQ_SCC1,
134   M8xx_CR_CHAN_SCC1,
135   -1},
136  /* SCC2 */
137  {TRUE,
138   {&(m8xx.scc2p),NULL},
139   {&(m8xx.scc2),NULL},
140   BSP_CPM_IRQ_SCC2,
141   M8xx_CR_CHAN_SCC2,
142   -1},
143  /* SCC3 */
144  {TRUE,
145   {&(m8xx.scc3p),NULL},
146   {&(m8xx.scc3),NULL},
147   BSP_CPM_IRQ_SCC3,
148   M8xx_CR_CHAN_SCC3,
149   -1},
150  /* SCC4 */
151  {TRUE,
152   {&(m8xx.scc4p),NULL},
153   {&(m8xx.scc4),NULL},
154   BSP_CPM_IRQ_SCC4,
155   M8xx_CR_CHAN_SCC4,
156   -1},
157  /* SMC1 */
158  {FALSE,
159   {NULL,&(m8xx.smc1p)},
160   {NULL,&(m8xx.smc1)},
161   BSP_CPM_IRQ_SMC1,
162   M8xx_CR_CHAN_SMC1,
163   -1},
164  /* SMC2 */
165  {FALSE,
166   {NULL,&(m8xx.smc2p)},
167   {NULL,&(m8xx.smc2)},
168   BSP_CPM_IRQ_SMC2_OR_PIP,
169   M8xx_CR_CHAN_SMC2,
170   -1}};
171
172#define CHN_PARAM_GET(chan,param)                       \
173  (m8xx_console_chan_desc[chan].is_scc                  \
174   ? m8xx_console_chan_desc[chan].parms.sccp->param     \
175   : m8xx_console_chan_desc[chan].parms.smcp->param)
176
177#define CHN_PARAM_SET(chan,param,value)                         \
178  do {if (m8xx_console_chan_desc[chan].is_scc)                  \
179      m8xx_console_chan_desc[chan].parms.sccp->param = value;   \
180    else                                                        \
181      m8xx_console_chan_desc[chan].parms.smcp->param = value;   \
182  } while (0)
183
184#define CHN_EVENT_GET(chan)                             \
185  (m8xx_console_chan_desc[chan].is_scc                  \
186   ? m8xx_console_chan_desc[chan].regs.sccr->scce       \
187   : m8xx_console_chan_desc[chan].regs.smcr->smce)
188
189#define CHN_EVENT_CLR(chan,mask)                                \
190  do {                                                          \
191    if (m8xx_console_chan_desc[chan].is_scc)                    \
192      m8xx_console_chan_desc[chan].regs.sccr->scce = (mask);    \
193    else                                                        \
194      m8xx_console_chan_desc[chan].regs.smcr->smce = (mask);    \
195  }while (0)
196
197#define CHN_MASK_GET(chan)                              \
198  (m8xx_console_chan_desc[chan].is_scc                  \
199   ? m8xx_console_chan_desc[chan].regs.sccr->sccm       \
200   : m8xx_console_chan_desc[chan].regs.smcr->smcm)
201
202#define CHN_MASK_SET(chan,mask)                                 \
203  do {                                                          \
204    if (m8xx_console_chan_desc[chan].is_scc)                    \
205      m8xx_console_chan_desc[chan].regs.sccr->sccm = (mask);    \
206    else                                                        \
207      m8xx_console_chan_desc[chan].regs.smcr->smcm = (mask);    \
208  }while (0)
209
210
211/*
212 * I/O buffers and pointers to buffer descriptors
213 */
214#define SCC_RXBD_CNT 4
215#define SCC_TXBD_CNT 4
216typedef volatile char sccRxBuf_t[SCC_RXBD_CNT][RXBUFSIZE];
217static sccRxBuf_t *rxBuf[CONS_CHN_CNT];
218
219static volatile m8xxBufferDescriptor_t *sccFrstRxBd[CONS_CHN_CNT];
220static volatile m8xxBufferDescriptor_t *sccCurrRxBd[CONS_CHN_CNT];
221static volatile m8xxBufferDescriptor_t *sccFrstTxBd[CONS_CHN_CNT];
222static volatile m8xxBufferDescriptor_t *sccPrepTxBd[CONS_CHN_CNT];
223static volatile m8xxBufferDescriptor_t *sccDequTxBd[CONS_CHN_CNT];
224
225/*
226 * Compute baud-rate-generator configuration register value
227 */
228static uint32_t
229sccBRGval (int baud)
230{
231  int divisor;
232  int div16 = 0;
233
234  divisor = ((BSP_bus_frequency / 16) + (baud / 2)) / baud;
235  if (divisor > 4096) {
236    div16 = 1;
237    divisor = (divisor + 8) / 16;
238  }
239  return M8xx_BRG_EN | M8xx_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
240}
241
242typedef struct {
243  uint32_t reg_content;
244  int link_cnt;
245}brg_state_t;
246brg_state_t scc_brg_state[BRG_CNT];
247
248/*
249 * initialize brg_state
250 */
251static void sccBRGinit(void)
252{
253  int brg_idx;
254
255  for (brg_idx = 0;brg_idx < BRG_CNT;brg_idx++) {
256    scc_brg_state[brg_idx].reg_content = 0;
257    scc_brg_state[brg_idx].link_cnt    = 0;
258  }
259#ifndef MDE360
260  /*
261   * on ZEM40, init CLK4/5 inputs
262   */
263  m8xx.papar |=  ((1 << 11) | (1 << 12));
264  m8xx.padir &= ~((1 << 11) | (1 << 12));
265#endif
266}
267
268#if CONS_USE_EXT_CLK
269/*
270 * input clock frq for CPM clock inputs
271 */
272static uint32_t clkin_frq[2][4] = {
273#ifdef MDE360
274  {0,0,0,0},
275  {0,0,0,0}
276#else
277  {0,0,0,1843000},
278  {1843000,0,0,0}
279#endif
280};
281#endif
282
283/*
284 * allocate, set and connect baud rate generators
285 * FIXME: or clock input
286 * FIXME: set pin to be clock input
287 */
288
289static int sccBRGalloc(int chan,int baud)
290{
291  rtems_interrupt_level level;
292  m8xx_console_chan_desc_t *chan_desc = &(m8xx_console_chan_desc[chan]);
293  uint32_t reg_val;
294  int old_brg;
295  int new_brg = -1;
296  int brg_idx;
297#if CONS_USE_EXT_CLK
298  int clk_group;
299  int clk_sel;
300#endif
301
302  old_brg = chan_desc->brg_used;
303  /* compute brg register contents needed */
304  reg_val = sccBRGval(baud);
305
306#if CONS_EXT_CLK
307  /* search for clock input with this frq */
308  clk_group = ((chan == CONS_CHN_SCC3) ||
309               (chan == CONS_CHN_SCC4) ||
310               (chan == CONS_CHN_SMC2)) ? 1 : 0;
311
312  for (clk_sel = 0, new_brg = -1;
313       (clk_sel < 4) && (new_brg < 0);
314       clk_sel++) {
315    if (baud == (clkin_frq[clk_group][clk_sel] / 16)) {
316      new_brg = clk_sel + 4;
317    }
318  }
319#endif
320
321  rtems_interrupt_disable(level);
322
323  if (new_brg < 0) {
324    /* search for brg with this settings */
325    for (brg_idx = 0;
326         (new_brg < 0) && (brg_idx < BRG_CNT);
327         brg_idx++) {
328      if (scc_brg_state[brg_idx].reg_content == reg_val) {
329        new_brg = brg_idx;
330      }
331    }
332    /*
333     * if not found: check, whether brg currently in use
334     * is linked only from our channel
335     */
336    if ((new_brg < 0) &&
337        (old_brg >= 0) &&
338        (scc_brg_state[old_brg].link_cnt == 1)) {
339      new_brg = old_brg;
340    }
341    /* if not found: search for unused brg, set it  */
342    for (brg_idx = 0;
343         (new_brg < 0) && (brg_idx < BRG_CNT);
344         brg_idx++) {
345      if (scc_brg_state[brg_idx].link_cnt == 0) {
346        new_brg = brg_idx;
347      }
348    }
349  }
350
351  /* decrease old link count */
352  if ((old_brg >= 0) &&
353      (old_brg < 4)) {
354    scc_brg_state[old_brg].link_cnt--;
355  }
356  /* increase new brg link count, set brg */
357  if ((new_brg >= 0) &&
358      (new_brg < 4)) {
359    scc_brg_state[new_brg].link_cnt++;
360    scc_brg_state[new_brg].reg_content = reg_val;
361    (&m8xx.brgc1)[new_brg] = reg_val;
362  }
363  rtems_interrupt_enable(level);
364
365  /* connect to scc/smc */
366  if (new_brg >= 0) {
367    m8xx_console_chan_desc[chan].brg_used = new_brg;
368    /*
369     * Put SCC in NMSI mode, connect SCC to BRG or CLKx
370     */
371    if (m8xx_console_chan_desc[chan].is_scc) {
372      m8xx.sicr = ((m8xx.sicr & ~(M8xx_SICR_SCCRX_MSK(chan) |
373                                  M8xx_SICR_SCCTX_MSK(chan))) |
374                   M8xx_SICR_SCCRX(chan,new_brg)|
375                   M8xx_SICR_SCCTX(chan,new_brg));
376    }
377    else {
378      /* connect SMC to BRGx or CLKx... */
379      m8xx.simode = ((m8xx.simode & ~(M8xx_SIMODE_SMCCS_MSK(chan - CONS_CHN_SMC1)))|
380                     M8xx_SIMODE_SMCCS(chan - CONS_CHN_SMC1,new_brg));
381    }
382  }
383  return (new_brg < 0);
384}
385
386
387/*
388 * Hardware-dependent portion of tcsetattr().
389 */
390static int
391sccSetAttributes (int minor, const struct termios *t)
392{
393  int baud;
394
395  switch (t->c_ospeed) {
396  default:      baud = -1;      break;
397  case B50:     baud = 50;      break;
398  case B75:     baud = 75;      break;
399  case B110:    baud = 110;     break;
400  case B134:    baud = 134;     break;
401  case B150:    baud = 150;     break;
402  case B200:    baud = 200;     break;
403  case B300:    baud = 300;     break;
404  case B600:    baud = 600;     break;
405  case B1200:   baud = 1200;    break;
406  case B1800:   baud = 1800;    break;
407  case B2400:   baud = 2400;    break;
408  case B4800:   baud = 4800;    break;
409  case B9600:   baud = 9600;    break;
410  case B19200:  baud = 19200;   break;
411  case B38400:  baud = 38400;   break;
412  case B57600:  baud = 57600;   break;
413  case B115200: baud = 115200;  break;
414  case B230400: baud = 230400;  break;
415  case B460800: baud = 460800;  break;
416  }
417  return sccBRGalloc(minor,baud);
418  return 0;
419}
420
421/*
422 * Interrupt handler
423 */
424static rtems_isr
425sccInterruptHandler (void *arg)
426{
427  int chan = (int)arg;
428
429  /*
430   * Buffer received?
431   */
432  if (CHN_EVENT_GET(chan) & 0x1) {
433    /*
434     * clear SCC event flag
435     */
436    CHN_EVENT_CLR(chan,0x01);
437    /*
438     * process event
439     */
440    while ((sccCurrRxBd[chan]->status & M8xx_BD_EMPTY) == 0) {
441      if (sccttyp[chan] != NULL) {
442        rtems_cache_invalidate_multiple_data_lines((void *)sccCurrRxBd[chan]->buffer,
443                                                   sccCurrRxBd[chan]->length);
444        rtems_termios_enqueue_raw_characters (sccttyp[chan],
445                                              (char *)sccCurrRxBd[chan]->buffer,
446                                              sccCurrRxBd[chan]->length);
447      }
448      /*
449       * clear status
450       */
451      sccCurrRxBd[chan]->status =
452        (sccCurrRxBd[chan]->status
453         & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
454        | M8xx_BD_EMPTY;
455      /*
456       * advance to next BD
457       */
458      if ((sccCurrRxBd[chan]->status & M8xx_BD_WRAP) != 0) {
459        sccCurrRxBd[chan] = sccFrstRxBd[chan];
460      }
461      else {
462        sccCurrRxBd[chan]++;
463      }
464    }
465  }
466  /*
467   * Buffer transmitted?
468   */
469  if (CHN_EVENT_GET(chan) & 0x2) {
470    /*
471     * then clear interrupt event bit
472     */
473    CHN_EVENT_CLR(chan,0x2);
474    /*
475     * and signal successful transmit to termios
476     */
477    /*
478     * FIXME: multiple dequeue calls for multiple buffers
479     */
480    while((sccDequTxBd[chan] != sccPrepTxBd[chan]) &&
481          ((sccDequTxBd[chan]->status & M8xx_BD_READY) == 0)) {
482      if (sccttyp[chan] != NULL) {
483        rtems_termios_dequeue_characters (sccttyp[chan],
484                                          sccDequTxBd[chan]->length);
485      }
486      /*
487       * advance to next BD
488       */
489      if ((sccDequTxBd[chan]->status & M8xx_BD_WRAP) != 0) {
490        sccDequTxBd[chan] = sccFrstTxBd[chan];
491      }
492      else {
493        sccDequTxBd[chan]++;
494      }
495    }
496  }
497}
498
499static void
500mpc8xx_console_irq_on(const rtems_irq_connect_data *irq)
501{
502    CHN_MASK_SET(irq->name - BSP_CPM_IRQ_LOWEST_OFFSET,
503                 3);    /* Enable TX and RX interrupts */
504}
505
506static void
507mpc8xx_console_irq_off(const rtems_irq_connect_data *irq)
508{
509    CHN_MASK_SET(irq->name - BSP_CPM_IRQ_LOWEST_OFFSET,
510                 0);    /* Disable TX and RX interrupts */
511}
512
513static int
514mpc8xx_console_irq_isOn(const rtems_irq_connect_data *irq)
515{
516  return (0 != CHN_MASK_GET(irq->name - BSP_CPM_IRQ_LOWEST_OFFSET)); /* Check TX and RX interrupts */
517}
518
519static void
520sccInitialize (int chan)
521{
522  int i;
523  /*
524   * allocate buffers
525   * FIXME: use a cache-line size boundary alloc here
526   */
527  rxBuf[chan] = malloc(sizeof(*rxBuf[chan]) + 2*PPC_CACHE_ALIGNMENT);
528  if (rxBuf[chan] == NULL) {
529    BSP_panic("Cannot allocate console rx buffer\n");
530  }
531  else {
532    /*
533     * round up rxBuf[chan] to start at a cache line size
534     */
535    rxBuf[chan] = (sccRxBuf_t *)
536      (((uint32_t)rxBuf[chan]) +
537       (PPC_CACHE_ALIGNMENT
538        - ((uint32_t)rxBuf[chan]) % PPC_CACHE_ALIGNMENT));
539  }
540  /*
541   * Allocate buffer descriptors
542   */
543  sccCurrRxBd[chan] =
544    sccFrstRxBd[chan] = m8xx_bd_allocate(SCC_RXBD_CNT);
545  sccPrepTxBd[chan] =
546    sccDequTxBd[chan] =
547    sccFrstTxBd[chan] = m8xx_bd_allocate(SCC_TXBD_CNT);
548  switch(chan) {
549  case CONS_CHN_SCC1:
550    /*
551     * Configure port A pins to enable TXD1 and RXD1 pins
552     * FIXME: add setup for modem control lines....
553     */
554    m8xx.papar |=  0x03;
555    m8xx.padir &= ~0x03;
556
557    /*
558     * Configure port C pins to enable RTS1 pins (static active low)
559     */
560    m8xx.pcpar &= ~0x01;
561    m8xx.pcso  &= ~0x01;
562    m8xx.pcdir |=  0x01;
563    m8xx.pcdat &= ~0x01;
564    break;
565  case CONS_CHN_SCC2:
566    /*
567     * Configure port A pins to enable TXD2 and RXD2 pins
568     * FIXME: add setup for modem control lines....
569     */
570    m8xx.papar |=  0x0C;
571    m8xx.padir &= ~0x0C;
572
573    /*
574     * Configure port C pins to enable RTS2 pins (static active low)
575     */
576    m8xx.pcpar &= ~0x02;
577    m8xx.pcso  &= ~0x02;
578    m8xx.pcdir |=  0x02;
579    m8xx.pcdat &= ~0x02;
580    break;
581  case CONS_CHN_SCC3:
582    /*
583     * Configure port A pins to enable TXD3 and RXD3 pins
584     * FIXME: add setup for modem control lines....
585     */
586    m8xx.papar |=  0x30;
587    m8xx.padir &= ~0x30;
588
589    /*
590     * Configure port C pins to enable RTS3 (static active low)
591     */
592    m8xx.pcpar &= ~0x04;
593    m8xx.pcso  &= ~0x04;
594    m8xx.pcdir |=  0x04;
595    m8xx.pcdat &= ~0x04;
596    break;
597  case CONS_CHN_SCC4:
598    /*
599     * Configure port A pins to enable TXD4 and RXD4 pins
600     * FIXME: add setup for modem control lines....
601     */
602    m8xx.papar |=  0xC0;
603    m8xx.padir &= ~0xC0;
604
605    /*
606     * Configure port C pins to enable RTS4 pins (static active low)
607     */
608    m8xx.pcpar &= ~0x08;
609    m8xx.pcso  &= ~0x08;
610    m8xx.pcdir |=  0x08;
611    m8xx.pcdat &= ~0x08;
612    break;
613  case CONS_CHN_SMC1:
614    /*
615     * Configure port B pins to enable SMTXD1 and SMRXD1 pins
616     */
617    m8xx.pbpar |=  0xC0;
618    m8xx.pbdir &= ~0xC0;
619    break;
620  case CONS_CHN_SMC2:
621    /*
622     * Configure port B pins to enable SMTXD2 and SMRXD2 pins
623     */
624    m8xx.pbpar |=  0xC00;
625    m8xx.pbdir &= ~0xC00;
626    break;
627  }
628  /*
629   * allocate and connect BRG
630   */
631  sccBRGalloc(chan,9600);
632
633
634  /*
635   * Set up SCCx parameter RAM common to all protocols
636   */
637  CHN_PARAM_SET(chan,rbase,(char *)sccFrstRxBd[chan] - (char *)&m8xx);
638  CHN_PARAM_SET(chan,tbase,(char *)sccFrstTxBd[chan] - (char *)&m8xx);
639  CHN_PARAM_SET(chan,rfcr ,M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0));
640  CHN_PARAM_SET(chan,tfcr ,M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0));
641  if (m8xx_scc_mode[chan] != TERMIOS_POLLED)
642    CHN_PARAM_SET(chan,mrblr,RXBUFSIZE);
643  else
644    CHN_PARAM_SET(chan,mrblr,1);
645
646  /*
647   * Set up SCCx parameter RAM UART-specific parameters
648   */
649  CHN_PARAM_SET(chan,un.uart.max_idl ,MAX_IDL_DEFAULT);
650  CHN_PARAM_SET(chan,un.uart.brkln   ,0);
651  CHN_PARAM_SET(chan,un.uart.brkec   ,0);
652  CHN_PARAM_SET(chan,un.uart.brkcr   ,0);
653  if (m8xx_console_chan_desc[chan].is_scc) {
654    m8xx_console_chan_desc[chan].parms.sccp->un.uart.character[0]=0x8000; /* no char filter */
655    m8xx_console_chan_desc[chan].parms.sccp->un.uart.rccm=0x80FF; /* control character mask */
656  }
657
658  /*
659   * Set up the Receive Buffer Descriptors
660   */
661  for (i = 0;i < SCC_RXBD_CNT;i++) {
662    sccFrstRxBd[chan][i].status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT;
663    if (i == SCC_RXBD_CNT-1) {
664      sccFrstRxBd[chan][i].status |= M8xx_BD_WRAP;
665    }
666    sccFrstRxBd[chan][i].length = 0;
667    sccFrstRxBd[chan][i].buffer = (*rxBuf[chan])[i];
668  }
669  /*
670   * Setup the Transmit Buffer Descriptor
671   */
672  for (i = 0;i < SCC_TXBD_CNT;i++) {
673    sccFrstTxBd[chan][i].status = M8xx_BD_INTERRUPT;
674    if (i == SCC_TXBD_CNT-1) {
675      sccFrstTxBd[chan][i].status |= M8xx_BD_WRAP;
676    }
677    sccFrstTxBd[chan][i].length = 0;
678    sccFrstTxBd[chan][i].buffer = NULL;
679  }
680
681  /*
682   * Set up SCC general and protocol-specific mode registers
683   */
684  CHN_EVENT_CLR(chan,~0);       /* Clear any pending events */
685  CHN_MASK_SET(chan,0);         /* Mask all interrupt/event sources */
686
687  if (m8xx_console_chan_desc[chan].is_scc) {
688    m8xx_console_chan_desc[chan].regs.sccr->psmr = 0xb000; /* 8N1, CTS flow control */
689    m8xx_console_chan_desc[chan].regs.sccr->gsmr_h = 0x00000000;
690    m8xx_console_chan_desc[chan].regs.sccr->gsmr_l = 0x00028004; /* UART mode */
691  }
692  else {
693    m8xx_console_chan_desc[chan].regs.smcr->smcmr = 0x4820;
694  }
695  /*
696   * Send "Init parameters" command
697   */
698  m8xx_cp_execute_cmd(M8xx_CR_OP_INIT_RX_TX
699                      | m8xx_console_chan_desc[chan].cr_chan_code);
700
701  /*
702   * Enable receiver and transmitter
703   */
704  if (m8xx_console_chan_desc[chan].is_scc) {
705    m8xx_console_chan_desc[chan].regs.sccr->gsmr_l |= 0x00000030;
706  }
707  else {
708    m8xx_console_chan_desc[chan].regs.smcr->smcmr |= 0x0003;
709  }
710
711  if (m8xx_scc_mode[chan] != TERMIOS_POLLED) {
712
713    rtems_irq_connect_data irq_conn_data = {
714      m8xx_console_chan_desc[chan].ivec_src,
715      sccInterruptHandler,         /* rtems_irq_hdl           */
716      (rtems_irq_hdl_param)chan,   /* (rtems_irq_hdl_param)   */
717      mpc8xx_console_irq_on,       /* (rtems_irq_enable)      */
718      mpc8xx_console_irq_off,      /* (rtems_irq_disable)     */
719      mpc8xx_console_irq_isOn      /* (rtems_irq_is_enabled)  */
720    };
721    if (!BSP_install_rtems_irq_handler (&irq_conn_data)) {
722      rtems_panic("console: cannot install IRQ handler");
723    }
724  }
725}
726
727/*
728 * polled scc read function
729 */
730static int
731sccPollRead (int minor)
732{
733  int c = -1;
734  int chan = minor;
735
736  while(1) {
737    if ((sccCurrRxBd[chan]->status & M8xx_BD_EMPTY) != 0) {
738      return -1;
739    }
740
741    if (0 == (sccCurrRxBd[chan]->status & (M8xx_BD_OVERRUN
742                                           | M8xx_BD_PARITY_ERROR
743                                           | M8xx_BD_FRAMING_ERROR
744                                           | M8xx_BD_BREAK
745                                           | M8xx_BD_IDLE))) {
746      /* character received and no error detected */
747      rtems_cache_invalidate_multiple_data_lines((void *)sccCurrRxBd[chan]->buffer,
748                                                 sccCurrRxBd[chan]->length);
749      c = (unsigned)*((char *)sccCurrRxBd[chan]->buffer);
750      /*
751       * clear status
752       */
753    }
754    sccCurrRxBd[chan]->status =
755      (sccCurrRxBd[chan]->status
756       & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
757      | M8xx_BD_EMPTY;
758    /*
759     * advance to next BD
760     */
761    if ((sccCurrRxBd[chan]->status & M8xx_BD_WRAP) != 0) {
762      sccCurrRxBd[chan] = sccFrstRxBd[chan];
763    }
764    else {
765      sccCurrRxBd[chan]++;
766    }
767    if (c >= 0) {
768      return c;
769    }
770  }
771}
772
773
774/*
775 * Device-dependent write routine
776 * Interrupt-driven devices:
777 *      Begin transmission of as many characters as possible (minimum is 1).
778 * Polling devices:
779 *      Transmit all characters.
780 */
781static ssize_t
782sccInterruptWrite (int minor, const char *buf, size_t len)
783{
784  if (len > 0) {
785    int chan = minor;
786
787    if ((sccPrepTxBd[chan]->status & M8xx_BD_READY) == 0) {
788      sccPrepTxBd[chan]->buffer = (char *)buf;
789      sccPrepTxBd[chan]->length = len;
790      rtems_cache_flush_multiple_data_lines((const void *)buf,len);
791      /*
792       * clear status, set ready bit
793       */
794      sccPrepTxBd[chan]->status =
795        (sccPrepTxBd[chan]->status
796         & M8xx_BD_WRAP)
797        | M8xx_BD_READY | M8xx_BD_INTERRUPT;
798      if ((sccPrepTxBd[chan]->status & M8xx_BD_WRAP) != 0) {
799        sccPrepTxBd[chan] = sccFrstTxBd[chan];
800      }
801      else {
802        sccPrepTxBd[chan]++;
803      }
804    }
805  }
806
807  return 0;
808}
809
810static ssize_t
811sccPollWrite (int minor, const char *buf, size_t len)
812{
813  static char txBuf[CONS_CHN_CNT][SCC_TXBD_CNT];
814  int chan = minor;
815  int bd_used;
816  size_t retval = len;
817
818  while (len--) {
819    while (sccPrepTxBd[chan]->status & M8xx_BD_READY)
820      continue;
821    bd_used = sccPrepTxBd[chan]-sccFrstTxBd[chan];
822    txBuf[chan][bd_used] = *buf++;
823      rtems_cache_flush_multiple_data_lines((const void *)&txBuf[chan][bd_used],
824                                            sizeof(txBuf[chan][bd_used]));
825    sccPrepTxBd[chan]->buffer = &(txBuf[chan][bd_used]);
826    sccPrepTxBd[chan]->length = 1;
827    sccPrepTxBd[chan]->status =
828      (sccPrepTxBd[chan]->status
829       & M8xx_BD_WRAP)
830      | M8xx_BD_READY;
831    if ((sccPrepTxBd[chan]->status & M8xx_BD_WRAP) != 0) {
832      sccPrepTxBd[chan] = sccFrstTxBd[chan];
833    }
834    else {
835      sccPrepTxBd[chan]++;
836    }
837  }
838  return retval;
839}
840
841/*
842 * printk basic support
843 */
844int BSP_output_chan = CONS_CHN_NONE; /* channel used for printk operation */
845
846static void console_debug_putc_onlcr(const char c)
847{
848  rtems_interrupt_level irq_level;
849  static char cr_chr = '\r';
850
851  if (BSP_output_chan != CONS_CHN_NONE) {
852    rtems_interrupt_disable(irq_level);
853
854    if (c == '\n') {
855      sccPollWrite (BSP_output_chan,&cr_chr,1);
856    }
857    sccPollWrite (BSP_output_chan,&c,1);
858    rtems_interrupt_enable(irq_level);
859  }
860}
861
862BSP_output_char_function_type     BSP_output_char = console_debug_putc_onlcr;
863BSP_polling_getchar_function_type BSP_poll_char = NULL;
864
865
866/*
867***************
868* BOILERPLATE *
869***************
870*/
871
872struct {
873  rtems_device_minor_number minor;
874  int driver_mode;
875} channel_list[] = {
876  {CONS_CHN_SMC1,CONS_SMC1_MODE},
877  {CONS_CHN_SMC2,CONS_SMC2_MODE},
878  {CONS_CHN_SCC1,CONS_SCC1_MODE},
879  {CONS_CHN_SCC2,CONS_SCC2_MODE},
880  {CONS_CHN_SCC3,CONS_SCC3_MODE},
881  {CONS_CHN_SCC4,CONS_SCC4_MODE}
882};
883
884
885/*
886 * Initialize and register the device
887 */
888rtems_device_driver console_initialize(rtems_device_major_number  major,
889                                       rtems_device_minor_number  minor,/* ignored */
890                                       void                      *arg
891                                       )
892{
893  rtems_status_code status = RTEMS_SUCCESSFUL;
894  int chan,entry,ttynum;
895  char tty_name[] = "/dev/tty00";
896
897  /*
898   * Set up TERMIOS
899   */
900  rtems_termios_initialize ();
901  /*
902   * init BRG allocataion
903   */
904  sccBRGinit();
905  ttynum = 0;
906  for (entry = 0;
907       (entry < sizeof(channel_list)/sizeof(channel_list[0]))
908         && (status == RTEMS_SUCCESSFUL);
909       entry++) {
910    if (channel_list[entry].driver_mode != CONS_MODE_UNUSED) {
911      /*
912       * Do device-specific initialization
913       */
914      chan = channel_list[entry].minor;
915      m8xx_scc_mode[chan] = channel_list[entry].driver_mode;
916      sccInitialize (chan);
917
918      /*
919       * build device name
920       */
921      tty_name[sizeof(tty_name)-2] = '0'+ttynum;
922      ttynum++;
923      /*
924       * Register the device
925       */
926      status = rtems_io_register_name (tty_name,
927                                       major,
928                                       channel_list[entry].minor);
929      if (status != RTEMS_SUCCESSFUL) {
930        rtems_fatal_error_occurred (status);
931      }
932    }
933  }
934  /*
935   * register /dev/console
936   */
937  status = rtems_io_register_name ("/dev/console",
938                                   major,
939                                   CONSOLE_CHN);
940  if (status != RTEMS_SUCCESSFUL) {
941    rtems_fatal_error_occurred (status);
942  }
943  /*
944   * enable printk support
945   */
946  BSP_output_chan = PRINTK_CHN;
947
948  return RTEMS_SUCCESSFUL;
949}
950
951/*
952 * Open the device
953 */
954rtems_device_driver console_open(
955                                 rtems_device_major_number major,
956                                 rtems_device_minor_number minor,
957                                 void                    * arg
958                                 )
959{
960  rtems_status_code status;
961  int chan = minor;
962  rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg;
963  static const rtems_termios_callbacks interruptCallbacks = {
964    NULL,               /* firstOpen */
965    NULL,               /* lastClose */
966    NULL,               /* pollRead */
967    sccInterruptWrite,  /* write */
968    sccSetAttributes,   /* setAttributes */
969    NULL,               /* stopRemoteTx */
970    NULL,               /* startRemoteTx */
971    TERMIOS_IRQ_DRIVEN  /* outputUsesInterrupts */
972  };
973  static const rtems_termios_callbacks pollCallbacks = {
974    NULL,               /* firstOpen */
975    NULL,               /* lastClose */
976    sccPollRead,        /* pollRead */
977    sccPollWrite,       /* write */
978    sccSetAttributes,   /* setAttributes */
979    NULL,               /* stopRemoteTx */
980    NULL,               /* startRemoteTx */
981    0                   /* outputUsesInterrupts */
982  };
983
984  if (m8xx_scc_mode[chan] == TERMIOS_IRQ_DRIVEN) {
985    status = rtems_termios_open (major, minor, arg, &interruptCallbacks);
986    sccttyp[chan] = args->iop->data1;
987  }
988  else {
989    status = rtems_termios_open (major, minor, arg, &pollCallbacks);
990    sccttyp[chan] = args->iop->data1;
991  }
992  return status;
993}
994
995/*
996 * Close the device
997 */
998rtems_device_driver console_close(
999                                  rtems_device_major_number major,
1000                                  rtems_device_minor_number minor,
1001                                  void                    * arg
1002                                  )
1003{
1004  rtems_status_code rc;
1005
1006  rc = rtems_termios_close (arg);
1007  sccttyp[minor] = NULL;
1008
1009  return rc;
1010
1011}
1012
1013/*
1014 * Read from the device
1015 */
1016rtems_device_driver console_read(
1017                                 rtems_device_major_number major,
1018                                 rtems_device_minor_number minor,
1019                                 void                    * arg
1020                                 )
1021{
1022  return rtems_termios_read (arg);
1023}
1024
1025/*
1026 * Write to the device
1027 */
1028rtems_device_driver console_write(
1029                                  rtems_device_major_number major,
1030                                  rtems_device_minor_number minor,
1031                                  void                    * arg
1032                                  )
1033{
1034  return rtems_termios_write (arg);
1035}
1036
1037#if 0
1038static int scc_io_set_trm_char(rtems_device_minor_number minor,
1039                               rtems_libio_ioctl_args_t *ioa)
1040{
1041  rtems_status_code rc                = RTEMS_SUCCESSFUL;
1042  con360_io_trm_char_t *trm_char_info = ioa->buffer;
1043
1044  /*
1045   * check, that parameter is non-NULL
1046   */
1047  if ((rc == RTEMS_SUCCESSFUL) &&
1048      (trm_char_info == NULL)) {
1049    rc = RTEMS_INVALID_ADDRESS;
1050  }
1051  /*
1052   * transfer max_idl
1053   */
1054  if (rc == RTEMS_SUCCESSFUL) {
1055    if (trm_char_info->max_idl >= 0x10000) {
1056      rc = RTEMS_INVALID_NUMBER;
1057    }
1058    else if (trm_char_info->max_idl > 0) {
1059      CHN_PARAM_SET(minor,un.uart.max_idl ,trm_char_info->max_idl);
1060    }
1061    else if (trm_char_info->max_idl == 0) {
1062      CHN_PARAM_SET(minor,un.uart.max_idl ,MAX_IDL_DEFAULT);
1063    }
1064  }
1065  /*
1066   * transfer characters
1067   */
1068  if (rc == RTEMS_SUCCESSFUL) {
1069    if (trm_char_info->char_cnt > CON8XX_TRM_CHAR_CNT) {
1070      rc = RTEMS_TOO_MANY;
1071    }
1072    else if (trm_char_info->char_cnt >= 0) {
1073      /*
1074       * check, whether device is a SCC
1075       */
1076      if ((rc == RTEMS_SUCCESSFUL) &&
1077          !m8xx_console_chan_desc[minor].is_scc) {
1078        rc = RTEMS_UNSATISFIED;
1079      }
1080      else {
1081        int idx = 0;
1082        for(idx = 0;idx < trm_char_info->char_cnt;idx++) {
1083          m8xx_console_chan_desc[minor].parms.sccp->un.uart.character[idx] =
1084            trm_char_info->character[idx] & 0x00ff;
1085        }
1086        if (trm_char_info->char_cnt < CON8XX_TRM_CHAR_CNT) {
1087          m8xx_console_chan_desc[minor].parms.sccp
1088            ->un.uart.character[trm_char_info->char_cnt] = 0x8000;
1089        }
1090      }
1091    }
1092  }
1093
1094  return rc;
1095}
1096#endif
1097
1098/*
1099 * Handle ioctl request.
1100 */
1101rtems_device_driver console_control(
1102                                    rtems_device_major_number major,
1103                                    rtems_device_minor_number minor,
1104                                    void                    * arg
1105                                    )
1106{
1107  rtems_libio_ioctl_args_t *ioa=arg;
1108
1109  switch (ioa->command) {
1110#if 0
1111  case CON8XX_IO_SET_TRM_CHAR:
1112    return scc_io_set_trm_char(minor, ioa);
1113#endif
1114  default:
1115    return rtems_termios_ioctl (arg);
1116    break;
1117  }
1118}
1119
Note: See TracBrowser for help on using the repository browser.