//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  File:  debug.c            
//
//  This module is provides the interface to the serial port.
//
#include <bsp.h>
#include <nkintr.h>
#include "bsp_gpio.h"
#include <dbgserial.h>
 
//------------------------------------------------------------------------------
// Externs
 
//------------------------------------------------------------------------------
// Global Variables

//------------------------------------------------------------------------------
// Local Variables 
static volatile UART_REG *g_pUARTReg=NULL;
static volatile GPIO_REG *g_pGPIOReg = NULL;
static volatile DWORD g_UARTStat = UART_NOT_READY;

//#define DEBUG_PORT  DEBUG_UART0;	//added by terry for test 20110926
//------------------------------------------------------------------------------
//
//  Function: OEMInitDebugSerial
//
//  Initializes the debug serial port
//
VOID OEMInitDebugSerial() 
{
    volatile CMU_CLK_REG *pCMUCLKReg=(CMU_CLK_REG *)OALPAtoVA(BASE_REG_PA_CMU_CLK, FALSE);
    float Div;
    UINT32 DivSlot;
    const UINT32 aSlotTable[16] = 
    {
        0x0000, 0x0080, 0x0808, 0x0888, 
        0x2222, 0x4924, 0x4a52, 0x54aa, 
        0x5555, 0xd555, 0xd5d5, 0xddd5, 
        0xdddd, 0xdfdd, 0xdfdf, 0xffdf
    };
    UINT32 nSlot=0;

    // Hoon: At this moment we must suppress logging.
    g_UARTStat |= UART_NOT_READY;

    


    if (g_pUARTReg == NULL)
    {
		
#if    (DEBUG_PORT == DEBUG_UART0)
        // UART0
        g_pUARTReg = (UART_REG *)OALPAtoVA(BASE_REG_PA_UART0, FALSE);
#elif (DEBUG_PORT == DEBUG_UART1)
        // UART1
        g_pUARTReg = (UART_REG *)OALPAtoVA(BASE_REG_PA_UART1, FALSE);
#elif (DEBUG_PORT == DEBUG_UART2)
        // UART2
        g_pUARTReg = (UART_REG *)OALPAtoVA(BASE_REG_PA_UART2, FALSE);
#elif (DEBUG_PORT == DEBUG_UART3)
        // UART3
        g_pUARTReg = (UART_REG *)OALPAtoVA(BASE_REG_PA_UART3, FALSE);
#else
        INVALID_DEBUG_PORT        // Error
#endif

    }

    if (g_pGPIOReg == NULL)
    {
        g_pGPIOReg = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
    }

    // UART I/O port initialize
#if   (DEBUG_PORT == DEBUG_UART0)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART0));
    Set_PinFunction(g_pGPIOReg, UART0_RXD);
    Set_PinFunction(g_pGPIOReg, UART0_TXD);
    Set_PinPullUD(g_pGPIOReg, UART0_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(g_pGPIOReg, UART0_TXD, sgip_PULL_DISABLE);

#elif (DEBUG_PORT == DEBUG_UART1)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART1));
    Set_PinFunction(g_pGPIOReg, UART1_RXD);
    Set_PinFunction(g_pGPIOReg, UART1_TXD);
    Set_PinPullUD(g_pGPIOReg, UART1_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(g_pGPIOReg, UART1_TXD, sgip_PULL_DISABLE);

#elif (DEBUG_PORT == DEBUG_UART2)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART2));
    Set_PinFunction(g_pGPIOReg, UART2_RXD);
    Set_PinFunction(g_pGPIOReg, UART2_TXD);
    Set_PinPullUD(g_pGPIOReg, UART2_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(g_pGPIOReg, UART2_TXD, sgip_PULL_DISABLE);

#elif (DEBUG_PORT == DEBUG_UART3)
    SETREG32(&pCMUCLKReg->CLK_GATE.CLK_GATE_IP3, (CLK_ON<<BP_CLK_IP_UART3));
    Set_PinFunction(g_pGPIOReg, UART3_RXD);
    Set_PinFunction(g_pGPIOReg, UART3_TXD);
    Set_PinPullUD(g_pGPIOReg, UART3_RXD, sgip_PULL_DOWN);
    Set_PinPullUD(g_pGPIOReg, UART3_TXD, sgip_PULL_DISABLE);
#endif

    // UART Configuration
    Div = (float)((float)PCLKPSYS/(16.0*(float)DEFAULT_DEBUG_BAUDRATE)) - 1;
    OUTREG32(&g_pUARTReg->UFCON,  DEBUG_UART_UFCON);
    OUTREG32(&g_pUARTReg->ULCON,  DEBUG_UART_ULCON);
    OUTREG32(&g_pUARTReg->UCON,   DEBUG_UART_UCON);
    OUTREG32(&g_pUARTReg->UBRDIV, (UINT32)Div);

    DivSlot = (UINT32)(((Div-(int)Div)*16)+0.5);
    OUTREG32(&g_pUARTReg->UDIVSLOT, aSlotTable[DivSlot]);

    // Now, let the log go through the serial 
    g_UARTStat &= ~UART_NOT_READY;
}

//------------------------------------------------------------------------------
//
//  Function: OEMWriteDebugByte
//
//  Transmits a character out the debug serial port.
//
VOID OEMWriteDebugByte(UINT8 ch) 
{

	// Data never be able to go through the serial, when either of the 
	// UART_NOT_READY or MSG_SUPPRESSED flag is set.
    if (g_UARTStat)
        return;

    // Wait for transmit buffer to be empty
    while((INREG32(&g_pUARTReg->UTRSTAT) & 0x02) == 0);

	OUTREG32(&g_pUARTReg->UTXH, ch);
}

//------------------------------------------------------------------------------
//
//  Function: OEMReadDebugByte
//
//  Reads a byte from the debug serial port. Does not wait for a character. 
//  If a character is not available function returns "OEM_DEBUG_READ_NODATA".
//

int OEMReadDebugByte() 
{
    UINT32 status, ch;

	if (g_UARTStat & UART_NOT_READY)
        return OEM_DEBUG_READ_NODATA;
    
    status = INREG32(&g_pUARTReg->UTRSTAT);
    if ((status & 0x01) != 0) {
       ch = INREG32(&g_pUARTReg->URXH);
    } else {
       ch = OEM_DEBUG_READ_NODATA;
    }

    return (int)ch;
}

//------------------------------------------------------------------------------
//
//  Function:  OEMWriteDebugString
//
//  Output unicode string to debug serial port
//
VOID OEMWriteDebugString(UINT16 *string)
{

    while (*string != L'\0') OEMWriteDebugByte((UINT8)*string++);
}


/*
    @func   void | OEMWriteDebugLED | Writes specified pattern to debug LEDs 1-4.
    @rdesc  None.
    @comm    
    @xref   
*/
void OEMWriteDebugLED(UINT16 Index, DWORD Pattern)
{
    if (g_pGPIOReg == NULL)
    {
        g_pGPIOReg = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
    }
    
    switch(Pattern)
    {
        case 0x0:
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;
        case 0x1:
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;
        case 0x2:    
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;             
        case 0x3:
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;
        case 0x4:
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;
        case 0x5:    
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;
        case 0x6:
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;
        case 0x7:
                Set_PinData(g_pGPIOReg, LED6, 0);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;
        case 0x8:    
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;
        case 0x9:
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;
        case 0xa:
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;
        case 0xb:    
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 0);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;
        case 0xc:
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;
        case 0xd:
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 0);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;
        case 0xe:    
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 0);
                break;      
        case 0xf:    
                Set_PinData(g_pGPIOReg, LED6, 1);
                Set_PinData(g_pGPIOReg, LED7, 1);
                Set_PinData(g_pGPIOReg, LED8, 1);
                Set_PinData(g_pGPIOReg, LED9, 1);
                break;   
        default:
                break;
     }     
}


//------------------------------------------------------------------------------
//
//  Function: OEMSupressDebug
//
//  Disables this library to send data through the serial port
//
void OEMSupressDebug(BOOL supress)
{
	if (supress)
		g_UARTStat |= UART_SUPPRESSED;
	else
		g_UARTStat &= ~UART_SUPPRESSED;
}
