/**     ll_serial_io_npa_56x4.c
 **
 ** Author: Ted Schmitz
 ** Date of original creation February 17, 2009
 **
 **     This file contains all the routines to handle low-level serial I/O
 ** for the NPA-56x4 AMC card.  
 **
 **/
#include <config.h>
#include <common.h>
#include "octeon_boot.h"
//#include "octeon_serial.h"

#include "ll_serial_io.h"

/* local prototypes */
static int check_for_char(int uart_index);
static unsigned char get_one_char(int uart_index);
static void bist_putch(int uart_index, unsigned char);

/*****************************************************************************
 **               Get One Character From UART Receive Buffer
 **
 **   This function reads a single character from the selected UART's receive
 ** register and returns that value to the calling code.  This function DOES
 ** NOT WAIT FOR A CHARACTER TO BECOME AVAILABLE!  Presumably that 
 ** determination has been made prior to calling this function.
 **
 **   If a new character is not available at the time this function is called,
 ** then the last character in the receive buffer will be returned to the
 ** calling code.  IN THIS CASE THERE IS NO GUARANTEE THE VALUE RETURNED
 ** REPRESENTS THE LAST CHARACTER RECEIVED BY THE UART!
 **
 ** INPUT - "uart_index" = which UART is to be read. (0 = UART0, 1 = UART1)
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - The value read from the selected UART's receive register is
 **          returned to the calling code. 
 **
 ****************************************************************************/
static unsigned char get_one_char(int uart_index)
{
  uint8_t ret_val;                /* value retured to calling cod */

  /* read on char from selected UART's reqad register (RBR) */
  ret_val = cvmx_read_csr(OCTEON_MIO_UARTX_RBR(uart_index));

  return (unsigned char) ret_val; /* ret char to calling code */
}

/*****************************************************************************
 **               Write One Character To UART Transmit Buffer
 **
 **   This function writes a single character to the selected UART's transmit
 ** register.  This function DOES NOT WAIT FOR A CHARACTER TO BECOME AVAILABLE!
 ** Presumably that determination has been made prior to calling this function.
 **
 ** INPUT - "uart_index" = which UART is to be written. (0 = UART0, 1 = UART1)
 **       - "char" = 8-bit byte to be written to UART.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - The value read from the selected UART's receive register is
 **          returned to the calling code. 
 **
 ****************************************************************************/
static void bist_putch(int uart_index, unsigned char ch)
{
  //printf("\nIn 'bist_putch()', ch = %02X...\n",ch);
  /* Write a single byte to the selected UART */
  cvmx_write_csr(OCTEON_MIO_UARTX_THR(uart_index), ch);
  //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), ch);
  //cvmx_write_csr(OCTEON_MIO_UARTX_THR(0), 'A');

}

/*****************************************************************************
 **                    Check For Character Available
 **
 **   This function checks the status on the particular UART channel to see
 ** if a character is available (key pressed on keyboard).  If a character is
 ** available, the appropriate status is returned to the calling code.
 **
 ** INPUT - "uart_index" = which UART is to be checked. (0 = UART0, 1 = UART1)
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - A one will be returned to the calling code if a key
 **          was pressed.  Zero will be returned otherwise.
 **
 ****************************************************************************/
static int check_for_char(int uart_index)
{
  int ret_val;                /* value retured to calling cod */
  cvmx_uart_lsr_t lsrval;

  /* Read the appropriate UART's status (LSR) register */
  lsrval.u64 = cvmx_read_csr(OCTEON_MIO_UARTX_LSR(uart_index));

  /* return the "data read" bit status to the calling code */
  ret_val = lsrval.s.dr;

  return ret_val;
}

/*****************************************************************************
 **                      Check For Key Pressed
 **
 **   This function checks the UART status register to see if a key was 
 ** pressed on the keyboard.  if so, a "TRUE" is returned to the calling code.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Returns a "TRUE" condition if a key has been pressed, "FALSE"
 **          otherwise.
 **
 ****************************************************************************/
int check_for_key(void)
{
  if (check_for_char(CONSOLE_UART_SEL) == 1)
    return TRUE;
  else 
    return FALSE;
}

/*****************************************************************************
 **                       Wait For Key Pressed
 **
 **   This function waits for a key to be pressed then returns to the
 ** calling code.  The key is not read or returned.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void wait_for_key(void)
{
  while (check_for_key() == FALSE);
}

/*****************************************************************************
 **               Low Level Read One Character From Keyboard
 **
 **   This function reads the next character from the receive buffer.  It is
 ** assumed a character is ready to be read before this function is called.
 ** The character is not echoed to the screen.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Returns a the value read from the RHR register (receive buffer).
 **
 ****************************************************************************/
char llgetchar(void)
{
  return (char) get_one_char(CONSOLE_UART_SEL);
  //return (UART_RBR_REG & 0xFF);
}

/*****************************************************************************
 **                    Check For Transmitter Ready
 **
 **   This function checks the UART status register to see if another 
 ** character can be transmitted.  If so, a "TRUE" is returned to the calling 
 ** code.  No characters are transmitted.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Returns a "TRUE" condition if the transmitter is ready to accept
 **          the next character, "FALSE" otherwise.
 **
 ****************************************************************************/
int check_for_xmit_ready(void)
{
#if 1 /* Cavium */
  cvmx_uart_lsr_t lsrval;

  /* Read the appropriate UART's status (LSR) register */
  lsrval.u64 = cvmx_read_csr(OCTEON_MIO_UARTX_LSR(CONSOLE_UART_SEL));

  /* check the "Transmitter Holding Register Empty" bit & ret status */
  if (lsrval.s.thre == 1)
    return TRUE;
  else 
    return FALSE;

#else /* old */
  if ((UART_LSR_REG & UART_LSR_THRE_BIT) == UART_LSR_THRE_BIT)
    return TRUE;
  else 
    return FALSE;
#endif
}

/*****************************************************************************
 **                 Low Level Transmit Character
 **
 **   This function transmits one character on the RS232 port.  It is assumed
 ** the transmitter is ready to receive the character before this function
 ** is called.
 **
 ** INPUT - "ch" charcter to be transmitted.
 **
 ** OUTPUT - The character is tranmsitted on the RS232 port.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void llputchar(char ch)
{
  bist_putch(CONSOLE_UART_SEL, (unsigned char) ch);

  //OLD UART_THR_REG = ch;
}

/*****************************************************************************
 **                 Low Level Transmit Character When Ready
 **
 **   This function waits for the transmitter to become ready to accept at
 ** least one more character then transmits the next chartacter on the Console 
 ** port.
 **
 ** INPUT - "ch" charcter to be transmitted.
 **
 ** OUTPUT - The character is tranmsitted on the console port.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void llputchar_when_ready(char ch)
{
  while (check_for_xmit_ready() == FALSE); /* wait for xmitter to go ready */

  llputchar(ch);                           /* write the char to console */

}

/*****************************************************************************
 **               Low Level Read One Line From keyboard
 **
 **   This function gets one line of keyboard input until it receives an
 ** end of line character (enter is pressed).  The line can be editied as it
 ** is typed and is echoed to the screen. The "new line" character is 
 ** overwritten with a null.
 **
 ** INPUT - "buffer" = pointer to where characters are to be stored.
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - Returns the number of characters read, not including the end of
 **          line or the null terminating character.
 **
 ****************************************************************************/
int get_line(char * buffer)
{
  char ch;                              /* character read from keyboard */
  int index;                            /* index to characters in buffer */

  index = 0;                            /* init num of chars read so far */

  while (TRUE)
    {
    wait_for_key(); 
    ch = llgetchar();                     /* get the key */

    if (ch == '\r')
      {
      buffer[index] = 00;                 /* overwrite new line char w/null */
      return index;                       /* return num of chars entered */
      }
    else if ((ch == BACKSPACE) || (ch == DELETE))
      {
      if (index > 0) /* only back space up to prompt then stop */
        {
        /* back up over last character and erase it */
        llputchar_when_ready(BACKSPACE);
        llputchar_when_ready(SPACE);
        llputchar_when_ready(BACKSPACE);
        index -= 1;                         /* decrement char counter */
        }    
      }
    else if ((ch > 0x1f) && (ch < DELETE))
      { /* reg char so save it in buffer and echo it to screen. Toss all
           non-printing characters */
      buffer[index] = ch;
      llputchar_when_ready(ch);
      index++;                            /* increment character counter */
      }
    } /* end while */
}

#if 0 /* Not finished yet */
/*****************************************************************************
 **               Low Write String To Console
 **
 **   This function writes a null-terminated string to the Rs232 port.
 **
 ** INPUT - "buffer" = pointer to where string is located.
 **
 ** OUTPUT - String is output directly to the console port.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
int ll_puts(char * buffer)
{
  char ch;                              /* character read from keyboard */
  int index;                            /* index to characters in buffer */

  index = 0;                            /* init num of chars read so far */

  while (TRUE)
    {
    wait_for_key(); 
    ch = llgetchar();                     /* get the key */

    if (ch == '\r')
      {
      buffer[index] = 00;                 /* overwrite new line char w/null */
      return index;                       /* return num of chars entered */
      }
    else if (((ch == BACKSPACE) || (ch == DELETE)) && (index > 0))
      {
      /* back up over last character and erase it */
      llputchar_when_ready(BACKSPACE);
      llputchar_when_ready(SPACE);
      llputchar_when_ready(BACKSPACE);
      index -= 1;                         /* decrement char counter */    
      }
    else 
      { /* reg char so save it in buffer and echo it to screen */
      buffer[index] = ch;
      llputchar_when_ready(ch);
      index++;                            /* increment character counter */
      }
    } /* end while */
}
#endif

#if 0 /* this should work but we don't need it when compiling for Uboot */
/*****************************************************************************
 **                            Check For Keystroke
 **
 **   This function checks to see if a key was pressed and returns the
 ** appropriate status to the calling code.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - A one will be returned to the calling code if a key
 **          was pressed.  Zero will be returned otherwise.
 **
 ****************************************************************************/
int kbhit(void)
{
  return check_for_char(CONSOLE_UART_SEL);
}

/*****************************************************************************
 **                  Read A Single Character From Keyboard
 **
 **   This function reads a single character from the keyboard input buffer.
 ** Some other function has determined that a key has been pressed before this
 ** function is called.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Nothing
 **
 ** RETURN - The character read from the keyboard input buffer will be
 **          returned to the calling code.
 **
 **          NOTE: This function will wait for a key to be pressed if one is
 **                not available when this function is called.
 **
 ****************************************************************************/
char readch(void)
{
  //char ch;

  return get_one_char(CONSOLE_UART_SEL);
}

#endif

