source: rtems/bsps/powerpc/tqm8xx/console/console.c @ 94ea8a8

Last change on this file since 94ea8a8 was d7d66d7, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 19, 2018 at 4:28:01 AM

bsps: Move console drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 28.0 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    rtems_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
850  if (BSP_output_chan != CONS_CHN_NONE) {
851    rtems_interrupt_disable(irq_level);
852
853    sccPollWrite (BSP_output_chan,&c,1);
854    rtems_interrupt_enable(irq_level);
855  }
856}
857
858BSP_output_char_function_type     BSP_output_char = console_debug_putc_onlcr;
859BSP_polling_getchar_function_type BSP_poll_char = NULL;
860
861
862/*
863***************
864* BOILERPLATE *
865***************
866*/
867
868struct {
869  rtems_device_minor_number minor;
870  int driver_mode;
871} channel_list[] = {
872  {CONS_CHN_SMC1,CONS_SMC1_MODE},
873  {CONS_CHN_SMC2,CONS_SMC2_MODE},
874  {CONS_CHN_SCC1,CONS_SCC1_MODE},
875  {CONS_CHN_SCC2,CONS_SCC2_MODE},
876  {CONS_CHN_SCC3,CONS_SCC3_MODE},
877  {CONS_CHN_SCC4,CONS_SCC4_MODE}
878};
879
880
881/*
882 * Initialize and register the device
883 */
884rtems_device_driver console_initialize(rtems_device_major_number  major,
885                                       rtems_device_minor_number  minor,/* ignored */
886                                       void                      *arg
887                                       )
888{
889  rtems_status_code status = RTEMS_SUCCESSFUL;
890  int chan,entry,ttynum;
891  char tty_name[] = "/dev/tty00";
892
893  /*
894   * Set up TERMIOS
895   */
896  rtems_termios_initialize ();
897  /*
898   * init BRG allocataion
899   */
900  sccBRGinit();
901  ttynum = 0;
902  for (entry = 0;
903       (entry < sizeof(channel_list)/sizeof(channel_list[0]))
904         && (status == RTEMS_SUCCESSFUL);
905       entry++) {
906    if (channel_list[entry].driver_mode != CONS_MODE_UNUSED) {
907      /*
908       * Do device-specific initialization
909       */
910      chan = channel_list[entry].minor;
911      m8xx_scc_mode[chan] = channel_list[entry].driver_mode;
912      sccInitialize (chan);
913
914      /*
915       * build device name
916       */
917      tty_name[sizeof(tty_name)-2] = '0'+ttynum;
918      ttynum++;
919      /*
920       * Register the device
921       */
922      status = rtems_io_register_name (tty_name,
923                                       major,
924                                       channel_list[entry].minor);
925      if (status != RTEMS_SUCCESSFUL) {
926        rtems_fatal_error_occurred (status);
927      }
928    }
929  }
930  /*
931   * register /dev/console
932   */
933  status = rtems_io_register_name ("/dev/console",
934                                   major,
935                                   CONSOLE_CHN);
936  if (status != RTEMS_SUCCESSFUL) {
937    rtems_fatal_error_occurred (status);
938  }
939  /*
940   * enable printk support
941   */
942  BSP_output_chan = PRINTK_CHN;
943
944  return RTEMS_SUCCESSFUL;
945}
946
947/*
948 * Open the device
949 */
950rtems_device_driver console_open(
951                                 rtems_device_major_number major,
952                                 rtems_device_minor_number minor,
953                                 void                    * arg
954                                 )
955{
956  rtems_status_code status;
957  int chan = minor;
958  rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg;
959  static const rtems_termios_callbacks interruptCallbacks = {
960    NULL,               /* firstOpen */
961    NULL,               /* lastClose */
962    NULL,               /* pollRead */
963    sccInterruptWrite,  /* write */
964    sccSetAttributes,   /* setAttributes */
965    NULL,               /* stopRemoteTx */
966    NULL,               /* startRemoteTx */
967    TERMIOS_IRQ_DRIVEN  /* outputUsesInterrupts */
968  };
969  static const rtems_termios_callbacks pollCallbacks = {
970    NULL,               /* firstOpen */
971    NULL,               /* lastClose */
972    sccPollRead,        /* pollRead */
973    sccPollWrite,       /* write */
974    sccSetAttributes,   /* setAttributes */
975    NULL,               /* stopRemoteTx */
976    NULL,               /* startRemoteTx */
977    0                   /* outputUsesInterrupts */
978  };
979
980  if (m8xx_scc_mode[chan] == TERMIOS_IRQ_DRIVEN) {
981    status = rtems_termios_open (major, minor, arg, &interruptCallbacks);
982    sccttyp[chan] = args->iop->data1;
983  }
984  else {
985    status = rtems_termios_open (major, minor, arg, &pollCallbacks);
986    sccttyp[chan] = args->iop->data1;
987  }
988  return status;
989}
990
991/*
992 * Close the device
993 */
994rtems_device_driver console_close(
995                                  rtems_device_major_number major,
996                                  rtems_device_minor_number minor,
997                                  void                    * arg
998                                  )
999{
1000  rtems_status_code rc;
1001
1002  rc = rtems_termios_close (arg);
1003  sccttyp[minor] = NULL;
1004
1005  return rc;
1006
1007}
1008
1009/*
1010 * Read from the device
1011 */
1012rtems_device_driver console_read(
1013                                 rtems_device_major_number major,
1014                                 rtems_device_minor_number minor,
1015                                 void                    * arg
1016                                 )
1017{
1018  return rtems_termios_read (arg);
1019}
1020
1021/*
1022 * Write to the device
1023 */
1024rtems_device_driver console_write(
1025                                  rtems_device_major_number major,
1026                                  rtems_device_minor_number minor,
1027                                  void                    * arg
1028                                  )
1029{
1030  return rtems_termios_write (arg);
1031}
1032
1033#if 0
1034static int scc_io_set_trm_char(rtems_device_minor_number minor,
1035                               rtems_libio_ioctl_args_t *ioa)
1036{
1037  rtems_status_code rc                = RTEMS_SUCCESSFUL;
1038  con360_io_trm_char_t *trm_char_info = ioa->buffer;
1039
1040  /*
1041   * check, that parameter is non-NULL
1042   */
1043  if ((rc == RTEMS_SUCCESSFUL) &&
1044      (trm_char_info == NULL)) {
1045    rc = RTEMS_INVALID_ADDRESS;
1046  }
1047  /*
1048   * transfer max_idl
1049   */
1050  if (rc == RTEMS_SUCCESSFUL) {
1051    if (trm_char_info->max_idl >= 0x10000) {
1052      rc = RTEMS_INVALID_NUMBER;
1053    }
1054    else if (trm_char_info->max_idl > 0) {
1055      CHN_PARAM_SET(minor,un.uart.max_idl ,trm_char_info->max_idl);
1056    }
1057    else if (trm_char_info->max_idl == 0) {
1058      CHN_PARAM_SET(minor,un.uart.max_idl ,MAX_IDL_DEFAULT);
1059    }
1060  }
1061  /*
1062   * transfer characters
1063   */
1064  if (rc == RTEMS_SUCCESSFUL) {
1065    if (trm_char_info->char_cnt > CON8XX_TRM_CHAR_CNT) {
1066      rc = RTEMS_TOO_MANY;
1067    }
1068    else if (trm_char_info->char_cnt >= 0) {
1069      /*
1070       * check, whether device is a SCC
1071       */
1072      if ((rc == RTEMS_SUCCESSFUL) &&
1073          !m8xx_console_chan_desc[minor].is_scc) {
1074        rc = RTEMS_UNSATISFIED;
1075      }
1076      else {
1077        int idx = 0;
1078        for(idx = 0;idx < trm_char_info->char_cnt;idx++) {
1079          m8xx_console_chan_desc[minor].parms.sccp->un.uart.character[idx] =
1080            trm_char_info->character[idx] & 0x00ff;
1081        }
1082        if (trm_char_info->char_cnt < CON8XX_TRM_CHAR_CNT) {
1083          m8xx_console_chan_desc[minor].parms.sccp
1084            ->un.uart.character[trm_char_info->char_cnt] = 0x8000;
1085        }
1086      }
1087    }
1088  }
1089
1090  return rc;
1091}
1092#endif
1093
1094/*
1095 * Handle ioctl request.
1096 */
1097rtems_device_driver console_control(
1098                                    rtems_device_major_number major,
1099                                    rtems_device_minor_number minor,
1100                                    void                    * arg
1101                                    )
1102{
1103  rtems_libio_ioctl_args_t *ioa=arg;
1104
1105  switch (ioa->command) {
1106#if 0
1107  case CON8XX_IO_SET_TRM_CHAR:
1108    return scc_io_set_trm_char(minor, ioa);
1109#endif
1110  default:
1111    return rtems_termios_ioctl (arg);
1112    break;
1113  }
1114}
1115
Note: See TracBrowser for help on using the repository browser.