source: rtems/c/src/lib/libcpu/powerpc/ppc403/console/console405.c @ 73cdeb6

4.104.114.84.9
Last change on this file since 73cdeb6 was 73cdeb6, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on Jul 4, 2007 at 12:25:49 PM

merged individual exception handler code to a common one.

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 *  This file contains the PowerPC 405GP console IO package.
3 *
4 *  Author:     Thomas Doerfler <td@imd.m.isar.de>
5 *              IMD Ingenieurbuero fuer Microcomputertechnik
6 *
7 *  COPYRIGHT (c) 1998 by IMD
8 *
9 *  Changes from IMD are covered by the original distributions terms.
10 *  changes include interrupt support and termios support
11 *  for backward compatibility, the original polled driver has been
12 *  renamed to console.c.polled
13 *
14 *  This file has been initially created (polled version) by
15 *
16 *  Author:     Andrew Bray <andy@i-cubed.co.uk>
17 *
18 *  COPYRIGHT (c) 1995 by i-cubed ltd.
19 *
20 *  To anyone who acknowledges that this file is provided "AS IS"
21 *  without any express or implied warranty:
22 *      permission to use, copy, modify, and distribute this file
23 *      for any purpose is hereby granted without fee, provided that
24 *      the above copyright notice and this notice appears in all
25 *      copies, and that the name of i-cubed limited not be used in
26 *      advertising or publicity pertaining to distribution of the
27 *      software without specific, written prior permission.
28 *      i-cubed limited makes no representations about the suitability
29 *      of this software for any purpose.
30 *
31 *  Modifications for spooling (interrupt driven) console driver
32 *            by Thomas Doerfler <td@imd.m.isar.de>
33 *  for these modifications:
34 *  COPYRIGHT (c) 1997 by IMD, Puchheim, Germany.
35 *
36 *
37 *  To anyone who acknowledges that this file is provided "AS IS"
38 *  without any express or implied warranty:
39 *      permission to use, copy, modify, and distribute this file
40 *      for any purpose is hereby granted without fee, provided that
41 *      the above copyright notice and this notice appears in all
42 *      copies. IMD makes no representations about the suitability
43 *      of this software for any purpose.
44 *
45 *  Derived from c/src/lib/libbsp/no_cpu/no_bsp/console/console.c:
46 *
47 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
48 *  On-Line Applications Research Corporation (OAR).
49 *
50 *  Modifications for PPC405GP by Dennis Ehlin
51 *
52 * $Id$
53 */
54
55#define NO_BSP_INIT
56
57#include <rtems.h>
58#include <rtems/libio.h>
59#include "../ictrl/ictrl.h"
60#include <stdlib.h>                                     /* for atexit() */
61
62
63
64struct async {
65/*---------------------------------------------------------------------------+
66| Data Register.
67+---------------------------------------------------------------------------*/
68  unsigned char RBR;    /* 0x00 */
69  #define THR   RBR
70/*---------------------------------------------------------------------------+
71| Interrupt registers
72+---------------------------------------------------------------------------*/
73  unsigned char IER;    /* 0x01 */
74  #define IER_RCV                0x01
75  #define IER_XMT                0x02
76  #define IER_LS                 0x04
77  #define IER_MS                 0x08
78
79  unsigned char ISR;    /* 0x02 */
80  #define ISR_MS                 0x00
81  #define ISR_nIP                0x01
82  #define ISR_Tx                 0x02
83  #define ISR_Rx                 0x04
84  #define ISR_LS                 0x06
85  #define ISR_RxTO               0x0C
86  #define ISR_64BFIFO            0x20
87  #define ISR_FIFOworks          0x40
88  #define ISR_FIFOen             0x80
89
90/*---------------------------------------------------------------------------+
91| FIFO Control registers
92+---------------------------------------------------------------------------*/
93  #define FCR   ISR
94  #define FCR_FE                0x01    /* FIFO enable */
95  #define FCR_CRF               0x02    /* Clear receive FIFO */
96  #define FCR_CTF               0x04    /* Clear transmit FIFO */
97  #define FCR_DMA               0x08    /* DMA mode select */
98  #define FCR_F64               0x20    /* Enable 64 byte fifo (16750+) */
99  #define FCR_RT14              0xC0    /* Set Rx trigger at 14 */
100  #define FCR_RT8               0x80    /* Set Rx trigger at 8 */
101  #define FCR_RT4               0x40    /* Set Rx trigger at 4 */
102  #define FCR_RT1               0x00    /* Set Rx trigger at 1 */
103
104/*---------------------------------------------------------------------------+
105| Baud rate divisor registers
106+---------------------------------------------------------------------------*/
107  #define DLL   RBR
108  #define DLM   IER
109
110/*---------------------------------------------------------------------------+
111| Alternate function registers
112+---------------------------------------------------------------------------*/
113  #define AFR   ISR     
114
115/*---------------------------------------------------------------------------+
116| Line control Register.
117+---------------------------------------------------------------------------*/
118  unsigned char LCR;    /* 0x03 */
119  #define LCR_WL5                0x00   /* Word length 5 */
120  #define LCR_WL6                0x01   /* Word length 6 */
121  #define LCR_WL7                0x02   /* Word length 7 */
122  #define LCR_WL8                0x03   /* Word length 8 */
123
124  #define LCR_SB1                0x00   /* 1 stop bits */
125  #define LCR_SB1_5              0x04   /* 1.5 stop bits , only valid with 5 bit words*/
126  #define LCR_SB1_5              0x04   /* 2 stop bits */
127
128  #define LCR_PN                 0x00   /* Parity NONE */
129  #define LCR_PE                 0x0C   /* Parity EVEN */
130  #define LCR_PO                 0x08   /* Parity ODD */
131  #define LCR_PM                 0x28   /* Forced "mark" parity */
132  #define LCR_PS                 0x38   /* Forced "space" parity */
133
134  #define LCR_DL                 0x80   /* Enable baudrate latch */
135
136/*---------------------------------------------------------------------------+
137| Modem control Register.
138+---------------------------------------------------------------------------*/
139  unsigned char MCR;    /* 0x04 */
140  #define MCR_DTR                0x01
141  #define MCR_RTS                0x02
142  #define MCR_INT                0x08   /* Enable interrupts */
143  #define MCR_LOOP               0x10   /* Loopback mode */
144
145/*---------------------------------------------------------------------------+
146| Line status Register.
147+---------------------------------------------------------------------------*/
148  unsigned char LSR;    /* 0x05 */
149  #define LSR_RSR                0x01
150  #define LSR_OE                 0x02
151  #define LSR_PE                 0x04
152  #define LSR_FE                 0x08
153  #define LSR_BI                 0x10
154  #define LSR_THE                0x20
155  #define LSR_TEMT               0x40
156  #define LSR_FIE                0x80
157
158/*---------------------------------------------------------------------------+
159| Modem status Register.
160+---------------------------------------------------------------------------*/
161  unsigned char MSR;    /* 0x06 */
162  #define UART_MSR_DCTS          0x01
163  #define UART_MSR_DDSR          0x02
164  #define UART_MSR_TERI          0x04
165  #define UART_MSR_DDCD          0x08
166  #define UART_MSR_CTS           0x10
167  #define UART_MSR_DSR           0x20
168  #define UART_MSR_RI            0x40
169  #define UART_MSR_CD            0x80
170
171/*---------------------------------------------------------------------------+
172| Scratch pad Register.
173+---------------------------------------------------------------------------*/
174  unsigned char SCR;    /* 0x07 */
175};
176
177
178#define USE_UART 0 /* 0=UART0 1=UART1 */
179#define UART_INTERNAL_CLOCK_DIVISOR 16
180
181typedef volatile struct async *pasync;
182static const pasync port = (pasync)(0xEF600300   + (USE_UART*0x100));   /* 0xEF600300 - port A,  0xEF600400 - port B */
183
184static void *spittyp;         /* handle for termios */
185int ppc403_spi_interrupt = 0; /* do not use interrupts... */
186
187
188static int spiBaudRound(double x)
189{
190  return (int)((int)((x-(int)x)*1000)>500 ? x+1 : x);
191}
192
193void 
194spiBaudSet(uint32_t   baudrate)
195{
196  uint32_t   tmp;
197
198  tmp = spiBaudRound( (double)rtems_cpu_configuration_get_serial_per_sec() / (baudrate * 16) );
199
200  port->LCR = port->LCR | LCR_DL;
201
202  port->DLL = tmp & 0xff;
203  port->DLM = tmp >> 8;
204
205  port->LCR = port->LCR & ~LCR_DL;
206}
207/*
208 * Hardware-dependent portion of tcsetattr().
209 */
210static int
211spiSetAttributes (int minor, const struct termios *t)
212{
213  int baud;
214
215  /* FIXME: check c_cflag & CRTSCTS for hardware flowcontrol */
216  /* FIXME: check and IMPLEMENT XON/XOFF                     */
217  switch (t->c_cflag & CBAUD) {
218  default:      baud = -1;      break;
219  case B50:     baud = 50;      break;
220  case B75:     baud = 75;      break;
221  case B110:    baud = 110;     break;
222  case B134:    baud = 134;     break;
223  case B150:    baud = 150;     break;
224  case B200:    baud = 200;     break;
225  case B300:    baud = 300;     break;
226  case B600:    baud = 600;     break;
227  case B1200:   baud = 1200;    break;
228  case B1800:   baud = 1800;    break;
229  case B2400:   baud = 2400;    break;
230  case B4800:   baud = 4800;    break;
231  case B9600:   baud = 9600;    break;
232  case B19200:  baud = 19200;   break;
233  case B38400:  baud = 38400;   break;
234  case B57600:  baud = 57600;   break;
235  case B115200: baud = 115200;  break;
236  case B230400: baud = 230400;  break;
237  case B460800: baud = 460800;  break;
238  }
239  if (baud > 0) {
240    spiBaudSet(baud);
241  }
242  return 0;
243}
244
245static int
246spiPollRead (int minor)
247{
248
249  /* Wait for character */
250  while ((port->LSR & LSR_RSR)==0);;
251
252  return port->RBR; 
253}
254
255
256static int 
257spiPollWrite(int minor,const char *buf,int len)
258{ 
259
260  while (len-- > 0) {
261    while (!(port->LSR & LSR_THE));;
262    port->THR = *buf++;
263  }
264  return 0;
265}
266
267/*
268 * enable/disable RTS line to start/stop remote transmitter
269 */
270static int
271spiStartRemoteTx (int minor)
272{
273/* Not implemented !
274  rtems_interrupt_level level;
275
276  rtems_interrupt_disable (level);
277  port->SPCTL |= CRRts;            activate RTS 
278  rtems_interrupt_enable (level);
279*/
280  return 0;
281}
282
283static int
284spiStopRemoteTx (int minor)
285{
286/* Not implemented !
287  rtems_interrupt_level level;
288
289  rtems_interrupt_disable (level);
290  port->SPCTL &= ~CRRts;            deactivate RTS 
291  rtems_interrupt_enable (level);
292*/
293  return 0;
294}
295
296static int InterruptWrite (int minor, const char *buf, int len)
297{
298  port->IER |= IER_XMT;     /* always enable tx interrupt */
299  port->THR = *buf;         /* write char to send         */
300  return 0;
301}
302
303static rtems_isr serial_ISR(rtems_vector_number v)
304{
305  unsigned char _isr;
306  char ch;
307  int res;
308
309  _isr=port->ISR & 0x0E;
310   
311   if ((_isr == ISR_Rx) || (_isr==ISR_RxTO)) {
312        ch = port->RBR;
313        rtems_termios_enqueue_raw_characters (spittyp,&ch,1);
314   }
315   
316   if (_isr == ISR_Tx) {
317        res = rtems_termios_dequeue_characters (spittyp,1);
318        if (res==0) {
319                port->IER &= ~IER_XMT;
320                }
321
322   }
323}
324
325
326/*
327 *
328 * deinit SPI
329 *
330 */
331void
332spiDeInit(void) 
333{
334  /*
335   * disable interrupts for serial port
336   * set it to state to work with polling boot monitor, if any...
337   */
338
339
340  /* set up baud rate to original state */
341  spiBaudSet(rtems_cpu_configuration_get_serial_rate());
342
343  port->IER = 0;
344
345}
346
347/*
348 *
349 * init SPI
350 *
351 */
352rtems_status_code
353spiInitialize(void) 
354{
355  register unsigned tmp;
356  rtems_isr_entry previous_isr; /* this is a dummy */
357  unsigned char _ier;
358
359  /*
360   * Initialise the serial port
361   */
362
363  /*
364   * Select clock source and set uart internal clock divisor
365   */
366
367  asm volatile ("mfdcr %0, 0x0b1" : "=r" (tmp)); /* CPC_CR0 0x0b1 */
368
369  /* UART0 bit 24 0x80, UART1 bit 25 0x40 */
370  tmp |= (rtems_cpu_configuration_get_serial_external_clock() ?  (USE_UART ? 0x40 : 0x80) : 0);
371
372  tmp |= (rtems_cpu_configuration_get_serial_external_clock() ?  0: ((UART_INTERNAL_CLOCK_DIVISOR -1) << 1));
373
374  asm volatile ("mtdcr 0x0b1, %0" : "=r" (tmp) : "0" (tmp)); /* CPC_CR0 0x0b1*/
375
376  /* Disable port interrupts while changing hardware */
377  _ier = port->IER;
378  port->IER = 0;
379
380  /* set up port control: 8 bit,1 stop,no parity */
381  port->LCR = LCR_WL8 | LCR_SB1 | LCR_PN;
382
383  /* set up baud rate */
384  spiBaudSet(rtems_cpu_configuration_get_serial_rate());
385 
386  if (ppc403_spi_interrupt) {
387
388    /* add rx/tx isr to vector table */
389    if (USE_UART==0) 
390        ictrl_set_vector(serial_ISR,PPC_IRQ_EXT_UART0,&previous_isr);
391    else
392        ictrl_set_vector(serial_ISR,PPC_IRQ_EXT_UART1,&previous_isr);
393
394    /* Enable and clear FIFO */
395    port->FCR = FCR_FE | FCR_CRF | FCR_CTF | FCR_RT8;
396
397    /* Enable recive interrupts, don't enable TxInt yet */
398    port->IER=IER_RCV;
399  }
400  else {
401    port->IER=_ier;
402  }
403
404  atexit(spiDeInit);
405
406  return RTEMS_SUCCESSFUL;
407}
408
409/*
410 ***************
411 * BOILERPLATE *
412 ***************
413 */
414
415/*  console_initialize
416 *
417 *  This routine initializes the console IO driver.
418 *
419 *  Input parameters: NONE
420 *
421 *  Output parameters:  NONE
422 *
423 *  Return values:
424 */
425
426rtems_device_driver console_initialize(
427  rtems_device_major_number  major,
428  rtems_device_minor_number  minor,
429  void                      *arg
430)
431{
432  rtems_status_code status;
433
434  /*
435   * Set up TERMIOS
436   */
437  rtems_termios_initialize ();
438
439  /*
440   * Do device-specific initialization
441   */
442  spiInitialize ();
443
444  /*
445   * Register the device
446   */
447  status = rtems_io_register_name ("/dev/console", major, 0);
448  if (status != RTEMS_SUCCESSFUL)
449    rtems_fatal_error_occurred (status);
450  return RTEMS_SUCCESSFUL;
451}
452
453
454/*
455 *  Open entry point
456 */
457 
458rtems_device_driver console_open(
459  rtems_device_major_number major,
460  rtems_device_minor_number minor,
461  void                    * arg
462)
463{
464  rtems_status_code sc;
465  static const rtems_termios_callbacks intrCallbacks = {
466    NULL,               /* firstOpen */
467    NULL,               /* lastClose */
468    NULL,               /* pollRead */
469    InterruptWrite,     /* write */
470    spiSetAttributes,   /* setAttributes */
471    spiStopRemoteTx,    /* stopRemoteTx */
472    spiStartRemoteTx,   /* startRemoteTx */
473    1                   /* outputUsesInterrupts */
474  };
475
476  static const rtems_termios_callbacks pollCallbacks = {
477    NULL,               /* firstOpen */
478    NULL,               /* lastClose */
479    spiPollRead,        /* pollRead */
480    spiPollWrite,       /* write */
481    spiSetAttributes,   /* setAttributes */
482    spiStopRemoteTx,    /* stopRemoteTx */
483    spiStartRemoteTx,   /* startRemoteTx */
484    0                   /* outputUsesInterrupts */
485  };
486
487  if (ppc403_spi_interrupt) {
488    rtems_libio_open_close_args_t *args = arg;
489    sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
490    spittyp = args->iop->data1;
491  }
492  else {
493    sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
494  }
495  return sc;
496}
497 
498/*
499 *  Close entry point
500 */
501 
502rtems_device_driver console_close(
503  rtems_device_major_number major,
504  rtems_device_minor_number minor,
505  void                    * arg
506)
507{
508  return rtems_termios_close (arg);
509}
510 
511/*
512 * read bytes from the serial port. We only have stdin.
513 */
514 
515rtems_device_driver console_read(
516  rtems_device_major_number major,
517  rtems_device_minor_number minor,
518  void                    * arg
519)
520{
521  return rtems_termios_read (arg);
522}
523 
524/*
525 * write bytes to the serial port. Stdout and stderr are the same.
526 */
527 
528rtems_device_driver console_write(
529  rtems_device_major_number major,
530  rtems_device_minor_number minor,
531  void                    * arg
532)
533{
534  return rtems_termios_write (arg);
535}
536 
537/*
538 *  IO Control entry point
539 */
540 
541rtems_device_driver console_control(
542  rtems_device_major_number major,
543  rtems_device_minor_number minor,
544  void                    * arg
545)
546{
547  return rtems_termios_ioctl (arg);
548}
Note: See TracBrowser for help on using the repository browser.