source: rtems/c/src/lib/libbsp/powerpc/tqm8xx/console/console.c @ 85e87f1

4.104.114.95
Last change on this file since 85e87f1 was 85e87f1, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 09/09/08 at 13:20:04

added printk support
added port init, added phy support
init mmu

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