source: rtems/bsps/powerpc/tqm8xx/console/console.c @ 7b93d857

Last change on this file since 7b93d857 was 7b93d857, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 12, 2018 at 8:08:50 AM

bsp/tqm8xx: Use IRQ extensions API

Update #3513.

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