⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial_au1000.c

📁 MIPS下的boottloader yamon 的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 *  Return values :
 *  ---------------
 *  'OK' = 0x00:      
 *  'ERROR_SERIAL_INVALID_BAUDRATE':  Invalid baudrate selected
 *
 ************************************************************************/
static INT32 
SERIAL_Au1000_checkbaudrate( 
    UINT8 baudrate )
{
#if 0
  if( baudrate < SERIAL_BAUDRATE_MAX )
  {
      if( (*serial_baudrate)[baudrate] != SERIAL_ILLEGAL )
      {
          return( OK );
      }
  }

  return( ERROR_SERIAL_INVALID_BAUDRATE );
#else
          return( OK );
#endif
}


/************************************************************************
 *
 *                          SERIAL_Au1000_checkdatabits
 *  Description :
 *  -------------
 *  This functions validates the specified databits for this type of device.
 *
 *  Parameters :
 *  ------------
 *
 *  'databits',   IN,    databits to be validated. 
 *
 *  Return values :
 *  ---------------
 *  'OK' = 0x00:      
 *  'ERROR_SERIAL_INVALID_DATABITS':  Invalid databits selected
 *
 ************************************************************************/
static INT32 
SERIAL_Au1000_checkdatabits( 
    UINT8 databits )
{
    if( databits < SERIAL_DATABITS_MAX )
    {
        if( serial_databits[databits] != SERIAL_ILLEGAL )
        {
            return( OK );
        }
    }
  
    return( ERROR_SERIAL_INVALID_DATABITS );
}


/************************************************************************
 *
 *                          SERIAL_Au1000_checkparity
 *  Description :
 *  -------------
 *  This functions validates the specified parity for this type of device.
 *
 *  Parameters :
 *  ------------
 *
 *  'parity',   IN,    parity to be validated. 
 *
 *  Return values :
 *  ---------------
 *  'OK' = 0x00:      
 *  'ERROR_SERIAL_INVALID_PARITY':  Invalid parity selected
 *
 ************************************************************************/
static INT32 
SERIAL_Au1000_checkparity( 
    UINT8 parity )
{
    if( parity < SERIAL_PARITY_MAX )
    {
        if( serial_parity[parity] != SERIAL_ILLEGAL )
        {
            return( OK );
        }
    }
  
    return( ERROR_SERIAL_INVALID_PARITY );
}


/************************************************************************
 *
 *                          SERIAL_Au1000_checkstopbits
 *  Description :
 *  -------------
 *  This functions validates the specified stopbits for this type of device.
 *
 *  Parameters :
 *  ------------
 *
 *  'stopbits',   IN,    stopbits to be validated. 
 *
 *  Return values :
 *  ---------------
 *  'OK' = 0x00:      
 *  'ERROR_SERIAL_INVALID_STOPBITS':  Invalid stopbits selected
 *
 ************************************************************************/
static INT32 
SERIAL_Au1000_checkstopbits( 
    UINT8 stopbits )
{
    if( stopbits < SERIAL_STOPBITS_MAX )
    {
        if( serial_stopbits[stopbits] != SERIAL_ILLEGAL )
        {
            return( OK );
        }
    }
  
    return( ERROR_SERIAL_INVALID_STOPBITS );
}


/************************************************************************
 *      Implementation : Device driver services
 ************************************************************************/


/************************************************************************
 *
 *                          SERIAL_Au1000_init
 *  Description :
 *  -------------
 *  This service initializes the serial driver and configures
 *  the applicable channels according to the configuration data, read
 *  from SYSCON
 *
 *  Parameters :
 *  ------------
 *
 *  'major',     IN,    major device number
 *  'minor',     IN,    minor device number for multi device drivers
 *  'port',      IN,	port mapping (PORT_TTY0/PORT_TTY1)
 *
 *  Return values :
 *  ---------------
 *
 *  'OK'(=0)
 *
 ************************************************************************/
static
INT32 SERIAL_Au1000_init(
    UINT32 major,          /* IN: major device number			*/
    UINT32 minor,          /* IN: minor device number			*/
    UINT32 *port )         /* IN: port mapping				*/
{
	INT32  rcode;
	UINT32 brkresval;
	UINT8  baudrate, databits, parity, stopbits;
	UINT32 bps_raw, bps_actual;
	UINT32 clkdiv;
	INT32  bps_error;  /* baudrate error in 0.1% increments (perc * 10) */
	t_SERIAL_ctrl_descriptor  ctrl;
	void   *minor_data;
	UINT32 int_line;
	UINT32 cpu_speed;  /* cpu core freq in Hz */
	UINT32 sysbusdiv;  /* System Bus Divider ratio (2, 3, or 4) */
	UINT32 den_temp;
	AU1X00_UART *uart = minor2base(minor);


	/* Get settings */
	SYSCON_read( (*port == PORT_TTY0) ? 
		     SYSCON_COM_TTY0_BAUDRATE_ID :
		     SYSCON_COM_TTY1_BAUDRATE_ID,
		     (void *)&baudrate,
		     sizeof(UINT8) );

	SYSCON_read( (*port == PORT_TTY0) ? 
		     SYSCON_COM_TTY0_DATABITS_ID :
		     SYSCON_COM_TTY1_DATABITS_ID,
		     (void *)&databits,
		     sizeof(UINT8) );

	SYSCON_read( (*port == PORT_TTY0) ? 
		     SYSCON_COM_TTY0_PARITY_ID :
		     SYSCON_COM_TTY1_PARITY_ID,
		     (void *)&parity,
		     sizeof(UINT8) );

	SYSCON_read( (*port == PORT_TTY0) ? 
		     SYSCON_COM_TTY0_STOPBITS_ID :
		     SYSCON_COM_TTY1_STOPBITS_ID,
		     (void *)&stopbits,
		     sizeof(UINT8) );

	/* FIX!!! not accurate for all processors */
	if (*port == PORT_TTY0)
		int_line = PB1000_INTLINE_TTY0;
	else
		int_line = PB1000_INTLINE_TTY1;

	/* Verify settings */
	rcode = SERIAL_Au1000_checkbaudrate( baudrate );

	if (rcode == OK)
		rcode = SERIAL_Au1000_checkdatabits( databits );

	if (rcode == OK)
		rcode = SERIAL_Au1000_checkparity( parity );

	if (rcode == OK)
		rcode = SERIAL_Au1000_checkstopbits( stopbits );

	if (rcode != OK)
		return rcode;

	/* table lookup to convert to uart bit fields */
	/*clkdiv   = (*serial_baudrate)[baudrate];*/
	databits = serial_databits[databits];
	parity   = serial_parity[parity];
	stopbits = serial_stopbits[stopbits];

	/* Recompute UART clkdiv on-the-fly based on current CPU core freq 
	   and requested baud rate.  Then this can be called after changing
	   CPU PLL multiplier or system bus divider ratio.
	   (This code could be put in its own function at some point
           if the stty baudrate validation function wanted to do this calc.)*/
	/* first do a table lookup to find the integer bps requested. */
	bps_raw = SERIAL_baudrate_rates[baudrate];
	/* get current CPU core freq and System Bus Divider ratio */
	SYSCON_read(SYSCON_BOARD_CPU_CLOCK_FREQ_ID, 
		    &cpu_speed, sizeof(cpu_speed));
	SYSCON_read(SYSCON_BOARD_BUS_CLOCK_FREQ_ID, 
		    &sysbusdiv, sizeof(sysbusdiv));
	/* here it is, with extras to get rounding right with ints */
	den_temp = 2*16*sysbusdiv*bps_raw;
	clkdiv = ((cpu_speed % den_temp) > (den_temp/2))
		 ? (cpu_speed / den_temp + 1)
		 : (cpu_speed / den_temp);
		
	/* recalc actually achieved bps to get error */
	bps_actual = cpu_speed/(2*16*sysbusdiv*clkdiv);
	bps_error = (1000*((INT32)bps_actual - (INT32)bps_raw))/bps_raw;
	/* having found the error we proceed to do nothing with it for now :) */

#if 0
	/* dan temp debug */
	printf("\nDEBUG, SERIAL_Au1000_init(), port = %d\n"
	       "\tcpu_speed = %u, sysbusdiv = %u, bps_raw = %d\n"
	       "\tclkdiv = %d, bps_actual = %d\n", 
	       *port, cpu_speed, sysbusdiv, bps_raw, clkdiv, bps_actual);
	sys_wait_ms(500); /* kludge for TX bytes to go out */
#endif

	recv_getptr[minor] = recv_putptr[minor] = &recv_buffer[minor][0];

	/* NOTE: If debug messages via sys_disp_string are enabled in
	   file arch/init/platform/init_platform_s.S, then UART0 has
	   already been initialized for sys_disp_string to work. But
	   enabling UART here permits stty changes to be effective. */

	/* Enable Clocks */
	uart->enable = UART_ENABLE_CE;
	asm(" sync");

	/* bring out of reset with clocks enabled */
	uart->enable = UART_ENABLE_CE | UART_ENABLE_E;
	asm(" sync");
    
	/* init IER: clear all interrupts */
	shadow_ier[minor] = 0;
	uart->inten = 0;

	/* initalize poll buffer pointers */
	/* (code from MIPS' Yamon is missing here.  Why?) */

	/* clear statistical info */
	uart_statistics[minor].ua_tx_bytes   = 0;
	uart_statistics[minor].ua_rx_bytes   = 0;
	uart_statistics[minor].ua_rx_overrun = 0;
	uart_statistics[minor].ua_rx_parity  = 0;
	uart_statistics[minor].ua_rx_framing = 0;
	uart_statistics[minor].ua_rx_break   = 0;
	uart_statistics[minor].ua_rx_irqs    = 0;
	uart_statistics[minor].ua_no_of_init++;

	/* Set uart_clkdiv per requested line rate.  Equation:
	   CLKDIV[15:0] = CPU_freq/(SD * BPS * 2 * 16)
	   where 
	     CPU_freq: Au1x00 CPU core freq in Hz, 
	     SD:       System Bus Divider (2, 3, or 4)
	     BPS:      bits/second
	 */
	uart->clkdiv = clkdiv;

	/*  Init LCR (data bits, stop bits, parity setting) */
	uart->linectrl = databits | stopbits | parity;

	/*  Init FCR: 
	 *          1) enable FIFO
	 *	    2) reset receiver FIFO
	 *	    3) reset transmitter FIFO
	 *	    4) set receive FIFO threshold to 14 bytes
	 */
	uart->fifoctrl = ( 0
		| UART_FIFOCTRL_FE
		| UART_FIFOCTRL_RR
		| UART_FIFOCTRL_TR
		| UART_FIFOCTRL_RFT_14
		) ;


	/*  Init MCR: 
	 *          1) set DTR
	 *	    2) set RTS  
	 *  (uart0/uart1 have no modem control lines, but uart3 does. */
	uart->mdmctrl = 
	shadow_mcr[minor] = UART_MDMCTRL_DT | UART_MDMCTRL_RT;

	/* newer MIPS' Yamon source has some BRKRES code here that may be
	   of interest. */

#if 0
	/* If this is the first call of init, we need to install interrupt 
	   handler */
	if( !registered[minor] )
	{    
		/* Determine parameter for interrupt service routine */
		minor_data = (void *)&minor_numbers[minor];

		/* Register interrupt handler */
		EXCEP_register_ic_isr(  int_line,
					serial_int_handler,
					minor_data,
					NULL );
        
		registered[minor] = TRUE;
	}

	/* Configure driver to be interrupt driven */
	ctrl.sc_command = SERIAL_CTRL_RCV_IRQ_ON;
	SERIAL_Au1000_ctrl( major, minor, &ctrl );
#endif


	return( OK );
}


/************************************************************************
 *		serial_int_handler
 ************************************************************************/
static void
serial_int_handler(
    void *data )	/* Holds the minor device number		*/
{
    t_SERIAL_ctrl_descriptor  ctrl;

    ctrl.sc_command = SERIAL_CTRL_RCV_IRQ;

    SERIAL_Au1000_ctrl( 0, *(UINT32 *)data, &ctrl );
}


/************************************************************************
 *
 *                          SERIAL_Au1000_read
 *  Description :
 *  -------------
 *  This service polls the specified channel for any present character.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -