summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libcpu/powerpc/ppc403/console/console.c
blob: b1fc7bfe9c82dc72b1ad6d8f07051af845350813 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


                                                            











                                                                     
                                                













                                                                      












                                                                    

                                                                  
                                                     
                                                    
                                                 
  


                                                                          
  
                                                



                   
                  
                        

                                                                          


                                                                          
                                                                              
                       


                                                                              







                                     
                                                                              
                            


                                                                              


                                     
                                                                              
                             


                                                                              
 
                                                                              
                   




                                                                              






                                     
                                     

                                     
                                     
 
                                                                             
                            











                                                                             
                               
                                                                             
                       











                                                                             
                       

                                                                             


                    


                                              




                                                            
   















                                                         
 




                                             
 








                                                                       
 






                                                           
 



                                                     

 



                              
 









                                                        
                                            






                                             
   

































                                                               
 

                       


                       



                                                                       
                                                                        
                                       
     















                                                               
 









                                             

 
   
  
              
  






























                                                                    
  
            
  
   

                    
 

                                                     
 


                                
 































































                                                                          

 
                      
  
                                                   
  
                          

                            

                  

   



                                       

 
                           
 



                              
 



                                      
 






                                                             

 
 
  
                    
   




                                  

 
































                                                                











                                  
                                   











                                                       
                                  
 
 
  
                                                                  
   




                                  

 
                                   











                                    
                                   
 
 
/*
 *  This file contains the PowerPC 403GA console IO package.
 *
 *  Author:	Thomas Doerfler <td@imd.m.isar.de>
 *              IMD Ingenieurbuero fuer Microcomputertechnik
 *
 *  COPYRIGHT (c) 1998 by IMD
 * 
 *  Changes from IMD are covered by the original distributions terms.
 *  changes include interrupt support and termios support
 *  for backward compatibility, the original polled driver has been 
 *  renamed to console.c.polled
 * 
 *  This file has been initially created (polled version) by
 *
 *  Author:	Andrew Bray <andy@i-cubed.co.uk>
 *
 *  COPYRIGHT (c) 1995 by i-cubed ltd.
 *
 *  To anyone who acknowledges that this file is provided "AS IS"
 *  without any express or implied warranty:
 *      permission to use, copy, modify, and distribute this file
 *      for any purpose is hereby granted without fee, provided that
 *      the above copyright notice and this notice appears in all
 *      copies, and that the name of i-cubed limited not be used in
 *      advertising or publicity pertaining to distribution of the
 *      software without specific, written prior permission.
 *      i-cubed limited makes no representations about the suitability
 *      of this software for any purpose.
 *
 *  Modifications for spooling (interrupt driven) console driver
 *            by Thomas Doerfler <td@imd.m.isar.de>
 *  for these modifications:
 *  COPYRIGHT (c) 1997 by IMD, Puchheim, Germany.
 *
 *  To anyone who acknowledges that this file is provided "AS IS"
 *  without any express or implied warranty:
 *      permission to use, copy, modify, and distribute this file
 *      for any purpose is hereby granted without fee, provided that
 *      the above copyright notice and this notice appears in all
 *      copies. IMD makes no representations about the suitability
 *      of this software for any purpose.
 *
 *  Derived from c/src/lib/libbsp/no_cpu/no_bsp/console/console.c:
 *
 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
 *  On-Line Applications Research Corporation (OAR).
 *  All rights assigned to U.S. Government, 1994.
 *
 *  This material may be reproduced by or for the U.S. Government pursuant
 *  to the copyright license under the clause at DFARS 252.227-7013.  This
 *  notice must appear in all copies of this file and its derivatives.
 *
 *  console.c,v 1.4 1995/12/05 19:23:02 joel Exp
 */

#define NO_BSP_INIT

#include <rtems.h>
#include <rtems/libio.h>
#include "../ictrl/ictrl.h"
#include <stdlib.h>                                     /* for atexit() */
extern rtems_cpu_table           Cpu_table;             /* owned by BSP */

struct async {
/*---------------------------------------------------------------------------+
| Line Status Register.
+---------------------------------------------------------------------------*/
  unsigned char SPLS;
  unsigned char SPLSset;
#define LSRDataReady             0x80
#define LSRFramingError          0x40
#define LSROverrunError          0x20
#define LSRParityError           0x10
#define LSRBreakInterrupt        0x08
#define LSRTxHoldEmpty           0x04
#define LSRTxShiftEmpty          0x02

/*---------------------------------------------------------------------------+
| Handshake Status Register.
+---------------------------------------------------------------------------*/
  unsigned char SPHS;
  unsigned char SPHSset;
#define HSRDsr                   0x80
#define HSRCts                   0x40

/*---------------------------------------------------------------------------+
| Baud rate divisor registers
+---------------------------------------------------------------------------*/
  unsigned char BRDH;
  unsigned char BRDL;

/*---------------------------------------------------------------------------+
| Control Register.
+---------------------------------------------------------------------------*/
  unsigned char SPCTL;
#define CRNormal		 0x00
#define CRLoopback		 0x40
#define CRAutoEcho		 0x80
#define CRDtr                    0x20
#define CRRts                    0x10
#define CRWordLength7            0x00
#define CRWordLength8            0x08
#define CRParityDisable          0x00
#define CRParityEnable           0x04
#define CREvenParity             0x00
#define CROddParity	         0x02
#define CRStopBitsOne            0x00
#define CRStopBitsTwo            0x01
#define CRDisableDtrRts	         0x00

/*--------------------------------------------------------------------------+
| Receiver Command Register.
+--------------------------------------------------------------------------*/
  unsigned char SPRC;
#define RCRDisable	         0x00
#define RCREnable		 0x80
#define RCRIntDisable	         0x00
#define RCRIntEnabled	         0x20
#define RCRDMACh2		 0x40
#define RCRDMACh3	         0x60
#define RCRErrorInt	         0x10
#define RCRPauseEnable	         0x08

/*--------------------------------------------------------------------------+
| Transmitter Command Register.
+--------------------------------------------------------------------------*/
    unsigned char SPTC;
#define TCRDisable	         0x00
#define TCREnable		 0x80
#define TCRIntDisable	         0x00
#define TCRIntEnabled 	         0x20
#define TCRDMACh2		 0x40
#define TCRDMACh3	         0x60
#define TCRTxEmpty		 0x10
#define TCRErrorInt	         0x08
#define TCRStopPause	         0x04
#define TCRBreakGen	         0x02

/*--------------------------------------------------------------------------+
| Miscellanies defines.
+--------------------------------------------------------------------------*/
  unsigned char SPTB;
#define SPRB	SPTB
};

typedef volatile struct async *pasync;
static const pasync port = (pasync)0x40000000;

static void *spittyp;         /* handle for termios */
int ppc403_spi_interrupt = 1; /* do not use interrupts... */

/*
 * Rx Interrupt handler
 */
static rtems_isr
spiRxInterruptHandler (rtems_vector_number v)
{
  char ch;

  /* clear any receive errors (errors are ignored now) */
  port->SPLS = (LSRFramingError | LSROverrunError |
                LSRParityError  | LSRBreakInterrupt);
  /*
   * Buffer received?
   */
  if (port->SPLS & LSRDataReady) {
    ch = port->SPRB; /* read receive buffer */
    rtems_termios_enqueue_raw_characters (spittyp,&ch,1);
  }
}

/*
 * Tx Interrupt handler
 */
static rtems_isr
spiTxInterruptHandler (rtems_vector_number v)
{
  /*
   * char transmitted?
   */
  if (0 != (port->SPLS & LSRTxHoldEmpty)) { /* must always be true!! */
    port->SPTC &= ~TCRIntEnabled;           /* stop irqs for now...  */
                                            /* and call termios...   */
    rtems_termios_dequeue_characters (spittyp,1);
  }
}

/*
 * enable/disable RTS line to start/stop remote transmitter
 */
static int
spiStartRemoteTx (int minor)
{
  rtems_interrupt_level level;

  rtems_interrupt_disable (level);
  port->SPCTL |= CRRts;           /* activate RTS  */
  rtems_interrupt_enable (level);
  return 0;
}

static int
spiStopRemoteTx (int minor)
{
  rtems_interrupt_level level;

  rtems_interrupt_disable (level);
  port->SPCTL &= ~CRRts;           /* deactivate RTS  */
  rtems_interrupt_enable (level);
  return 0;
}

void 
spiBaudSet(unsigned32 baudrate)
{
  unsigned32 tmp;
  tmp = Cpu_table.serial_per_sec / baudrate;
  tmp = ((tmp) >> 4) - 1;
  port->BRDL = tmp & 0xff;
  port->BRDH = tmp >> 8;

}
/*
 * Hardware-dependent portion of tcsetattr().
 */
static int
spiSetAttributes (int minor, const struct termios *t)
{
  int baud;

  /* FIXME: check c_cflag & CRTSCTS for hardware flowcontrol */
  /* FIXME: check and IMPLEMENT XON/XOFF                     */
  switch (t->c_cflag & CBAUD) {
  default:	baud = -1;	break;
  case B50:	baud = 50;	break;
  case B75:	baud = 75;	break;
  case B110:	baud = 110;	break;
  case B134:	baud = 134;	break;
  case B150:	baud = 150;	break;
  case B200:	baud = 200;	break;
  case B300:	baud = 300;	break;
  case B600:	baud = 600;	break;
  case B1200:	baud = 1200;	break;
  case B1800:	baud = 1800;	break;
  case B2400:	baud = 2400;	break;
  case B4800:	baud = 4800;	break;
  case B9600:	baud = 9600;	break;
  case B19200:	baud = 19200;	break;
  case B38400:	baud = 38400;	break;
  case B57600:	baud = 57600;	break;
  case B115200:	baud = 115200;	break;
  case B230400:	baud = 230400;	break;
  case B460800:	baud = 460800;	break;
  }
  if (baud > 0) {
    spiBaudSet(baud);
  }
  return 0;
}

static int
spiPollRead (int minor)
{
  unsigned char status;

  while (0 == ((status = port->SPLS) & LSRDataReady)) {
    /* Clean any dodgy status */
    if ((status & (LSRFramingError | LSROverrunError | LSRParityError |
		   LSRBreakInterrupt)) != 0) {
      port->SPLS = (LSRFramingError | LSROverrunError | LSRParityError |
		    LSRBreakInterrupt);
    }
  } 
  return port->SPRB;  
}

static int
spiInterruptWrite (int minor, const char *buf, int len)
{
  port->SPTB = *buf;           /* write char to send         */
  port->SPTC |= TCRIntEnabled; /* always enable tx interrupt */
  return 0;
}

static int 
spiPollWrite(int minor,const char *buf,int len)
{  
  unsigned char status;

  while (len-- > 0) {
    do {
      if (port->SPHS) {
	port->SPHS = (HSRDsr | HSRCts);
      }
      status = port->SPLS;
    } while (0 == (status & LSRTxHoldEmpty));
    port->SPTB = *buf++;
  }
  return 0;
}

/* 
 *
 * deinit SPI 
 *
 */
void
spiDeInit(void) 
{
  /*
   * disable interrupts for serial port 
   * set it to state to work with polling boot monitor, if any... 
   */

  /* set up baud rate to original state */
  spiBaudSet(Cpu_table.serial_rate);

  /* clear any receive (error) status */
  port->SPLS = (LSRDataReady   | LSRFramingError | LSROverrunError |
		LSRParityError | LSRBreakInterrupt);

  /* set up port control: DTR/RTS active,8 bit,1 stop,no parity */
  port->SPCTL = (CRNormal | 
		 CRDtr | CRRts | 
		 CRWordLength8 | CRParityDisable | CRStopBitsOne);

  /* clear handshake status bits */
  port->SPHS = (HSRDsr | HSRCts);

  /* enable receiver/transmitter, no interrupts */
  port->SPRC = (RCREnable | RCRIntDisable);
  port->SPTC = (TCREnable | TCRIntDisable);

}

/* 
 *
 * init SPI 
 *
 */
rtems_status_code 
spiInitialize(void) 
{
  register unsigned tmp;
  rtems_isr_entry previous_isr; /* this is a dummy */

  /*
   * Initialise the serial port 
   */

  /* 
   * select RTS/CTS hardware handshake lines, 
   * select clock source 
   */
  asm volatile ("mfdcr %0, 0xa0" : "=r" (tmp)); /* IOCR */

  tmp &= ~3;
  tmp |= (Cpu_table.serial_external_clock ? 2 : 0) | 1;

  asm volatile ("mtdcr 0xa0, %0" : "=r" (tmp) : "0" (tmp)); /* IOCR */

  /* clear any receive (error) status */
  port->SPLS = (LSRDataReady   | LSRFramingError | LSROverrunError |
		LSRParityError | LSRBreakInterrupt);

  /* set up baud rate */
  spiBaudSet(Cpu_table.serial_rate);

  /* set up port control: DTR/RTS active,8 bit,1 stop,no parity */
  port->SPCTL = (CRNormal | 
		 CRDtr | CRRts | 
		 CRWordLength8 | CRParityDisable | CRStopBitsOne);

  /* clear handshake status bits */
  port->SPHS = (HSRDsr | HSRCts);

  if (ppc403_spi_interrupt) {
    /* add rx/tx isr to vector table */
    ictrl_set_vector(spiRxInterruptHandler,
		     PPC_IRQ_EXT_SPIR,
		     &previous_isr);

    ictrl_set_vector(spiTxInterruptHandler,
		     PPC_IRQ_EXT_SPIT,
		     &previous_isr);

    port->SPRC = (RCREnable | RCRIntEnabled | RCRErrorInt);
    port->SPTC = (TCREnable | TCRIntDisable); /* don't enable TxInt yet */
  }
  else {
    /* enable receiver/transmitter, no interrupts */
    port->SPRC = (RCREnable | RCRIntDisable);
    port->SPTC = (TCREnable | TCRIntDisable);
  }

  atexit(spiDeInit);

  return RTEMS_SUCCESSFUL;
}

/*
 ***************
 * BOILERPLATE *
 ***************
 */

/*
 * Reserve resources consumed by this driver
 */
void console_reserve_resources(
  rtems_configuration_table *configuration
)
{
	rtems_termios_reserve_resources (configuration, 1);
}

/*  console_initialize
 *
 *  This routine initializes the console IO driver.
 *
 *  Input parameters: NONE
 *
 *  Output parameters:  NONE
 *
 *  Return values:
 */

rtems_device_driver console_initialize(
  rtems_device_major_number  major,
  rtems_device_minor_number  minor,
  void                      *arg
)
{
  rtems_status_code status;

  /*
   * Set up TERMIOS
   */
  rtems_termios_initialize ();

  /*
   * Do device-specific initialization
   */
  spiInitialize ();

  /*
   * Register the device
   */
  status = rtems_io_register_name ("/dev/console", major, 0);
  if (status != RTEMS_SUCCESSFUL)
    rtems_fatal_error_occurred (status);
  return RTEMS_SUCCESSFUL;
}


/*
 *  Open entry point
 */
 
rtems_device_driver console_open(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void                    * arg
)
{
  rtems_status_code sc;
  static const rtems_termios_callbacks intrCallbacks = {
    NULL,		/* firstOpen */
    NULL,		/* lastClose */
    NULL,	        /* pollRead */
    spiInterruptWrite,	/* write */
    spiSetAttributes,   /* setAttributes */
    spiStopRemoteTx,	/* stopRemoteTx */
    spiStartRemoteTx,	/* startRemoteTx */
    1			/* outputUsesInterrupts */
  };

  static const rtems_termios_callbacks pollCallbacks = {
    NULL,		/* firstOpen */
    NULL,		/* lastClose */
    spiPollRead,	/* pollRead */
    spiPollWrite,	/* write */
    spiSetAttributes,	/* setAttributes */
    spiStopRemoteTx,	/* stopRemoteTx */
    spiStartRemoteTx,	/* startRemoteTx */
    0			/* outputUsesInterrupts */
  };

  if (ppc403_spi_interrupt) {
    rtems_libio_open_close_args_t *args = arg;
    
    sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
    spittyp = args->iop->data1;
  }
  else {
    sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
  }
  return sc;
}
 
/*
 *  Close entry point
 */
 
rtems_device_driver console_close(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void                    * arg
)
{
  return rtems_termios_close (arg);
}
 
/*
 * read bytes from the serial port. We only have stdin.
 */
 
rtems_device_driver console_read(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void                    * arg
)
{
  return rtems_termios_read (arg);
}
 
/*
 * write bytes to the serial port. Stdout and stderr are the same.
 */
 
rtems_device_driver console_write(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void                    * arg
)
{
  return rtems_termios_write (arg);
}
 
/*
 *  IO Control entry point
 */
 
rtems_device_driver console_control(
  rtems_device_major_number major,
  rtems_device_minor_number minor,
  void                    * arg
)
{
  return rtems_termios_ioctl (arg);
}