//==========================================================================
//
//      board_misc.c
//
//      HAL misc board support code for the board
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//========================================================================*/

#include <pkgconf/hal.h>
#include <pkgconf/system.h>
#include <redboot.h>
#include CYGBLD_HAL_PLATFORM_H

#include <cyg/infra/cyg_type.h>         // base types
#include <cyg/infra/cyg_trac.h>         // tracing macros
#include <cyg/infra/cyg_ass.h>          // assertion macros

#include <cyg/hal/hal_io.h>             // IO macros
#include <cyg/hal/hal_arch.h>           // Register state info
#include <cyg/hal/hal_diag.h>
#include <cyg/hal/hal_intr.h>           // Interrupt names
#include <cyg/hal/hal_cache.h>
#include <cyg/hal/hal_soc.h>         // Hardware definitions
#include <cyg/hal/kinpo_g23.h>             // Platform specifics

#include <cyg/infra/diag.h>             // diag_printf

// All the MM table layout is here:
#include <cyg/hal/hal_mm.h>

#include <cyg/io/mx31_pins.h>

#define USB_MASK		0x3F0000
#define USB_NONE		0x080000
#define USB_PC			0x0f0000
#define USB_CLA			0x270000
#define USB_POWERSUPPLY	0x2e0000
#define USB_ADAPTER		0x2f0000
#define USB_SONY		0x100000
#define USB_SONY_PLUS	USB_SONY
	
#define RESTART			0x1

static cyg_int8 pcb_ver = -1;
static cyg_int8 bd_phase = -1;

/* internal function declare */
static void mxc_kpp_init(void);
static void mxc_kpp_set_clock(int on);
cyg_uint8 mxc_kpp_scan(void);
static void board_redboot_init(void);
static void cpld_init(void);
#ifdef CYG_HAL_ARM_G23_TARGET_TYPE_EVT
static void usb2uart(void);
void led_shine(bool enable);
#endif
void get_cpld_board_phase(cyg_int8 *VR_phase);
void get_cpld_pcb_version(cyg_int8 *VR_pcb);

static void gps_init(void);
static void check_power_on(void);
static void lcd_init(void);
static void check_batt_low(void);

unsigned int _iomux_pad_data[110] = {
    0x0A000000, 0x1A0281A0, 0x081285A0, 0x1A0681A0,
    0x0A0281A0, 0x0A128481, 0x0A1284A1, 0x0A328CA3,
    0x0A348CA3, 0x0A328CA3, 0x0A328CA3, 0x0A328CA3,
    0x1A328CA3, 0x12348D23, 0x12348D23, 0x12348D23,
    0x12348D23, 0x12348D23, 0x12348D23, 0x1A0681A0,
    0x1A0681A0, 0x1A0681A0, 0x0A0681A0, 0x1A0680A0,
    0x1B0681A0, 0x1A0681A0, 0x1A0681A0, 0x1B06C0A3,
    0x1A020D90, 0x1A0681A0, 0x1A0681A0, 0x1A0681A0,
    0x1A0681A0, 0x1A0681A0, 0x1A0683A8, 0x1A0681A0,
    0x1A02E1A8, 0x1A0681B0, 0x1A0681A0, 0x1A0681A0,
    0x1B0681A0, 0x1B0681A0, 0x0A0681B0, 0x0A0681A0,
    0x1A0280A0, 0x1A0681A0, 0x1A0681A0, 0x1A0681A0,
    0x1A0681A0, 0x1A0681A0, 0x1312A0B8, 0x12148521,
    0x12148521, 0x12148521, 0x12148521, 0x1A168521,
    0x0A2281A0, 0x1A2689A2, 0x1A2689A2, 0x1A2609A2,
    0x1A2689A2, 0x12348D23, 0x12348D23, 0x12348D23,
    0x12348D23, 0x12348D23, 0x1A128523, 0x1A1685A0,
    0x181605A1, 0x18160581, 0x121A8DA0, 0x12348521,
    0x2A328D23, 0x0A368CA3, 0x12348CA3, 0x0A328CA3,
    0x12328CA3, 0x12348D23, 0x12348D23, 0x12348D23,
    0x12348D23, 0x12348D23, 0x12348D23, 0x12348D23,
    0x12348D23, 0x12348D23, 0x12348D23, 0x12348D23,
    0x0A148D23, 0x0A328CA1, 0x0A328CA3, 0x0A328CA3,
    0x0A328CA3, 0x0A328CA3, 0x0A328CA3, 0x0A328CA3,
    0x0A328CA3, 0x0A328CA3, 0x0A0280A3, 0x0A0280A0,
    0x0A02C180, 0x0A0280A0, 0x1B029CA0, 0x1A02C1B0,
    0x1A0681A0, 0x1B0681A0, 0x1B06C1B0, 0x1B06C1B0,
    0x0A06C1B0, 0x1A0681A0
} ;

/* external function declare */
externC void* memset(void *, int, size_t);
externC void mxc_pmic_init(void);
externC unsigned int pmic_reg(unsigned int reg, unsigned int val,
                              unsigned int write);
externC unsigned int pmic_reg_set(unsigned int reg, unsigned int val,
                                  unsigned int mask);
externC void mxc_framebuffer_init(void);
externC void paint_logo(void);

/* extern variable declare */
extern struct cmd __NAND_cmds_TAB__[], __NAND_cmds_TAB_END__;


void hal_mmu_init(void)
{
    unsigned long ttb_base = RAM_BANK0_BASE + 0x4000;
    unsigned long i;

    /*
     * Set the TTB register
     */
    asm volatile ("mcr  p15,0,%0,c2,c0,0" : : "r"(ttb_base) /*:*/);

    /*
     * Set the Domain Access Control Register
     */
    i = ARM_ACCESS_DACR_DEFAULT;
    asm volatile ("mcr  p15,0,%0,c3,c0,0" : : "r"(i) /*:*/);

    /*
     * First clear all TT entries - ie Set them to Faulting
     */
    memset((void *)ttb_base, 0, ARM_FIRST_LEVEL_PAGE_TABLE_SIZE);

    /*              Actual   Virtual  Size   Attributes                                                    Function  */
    /*              Base     Base     MB     cached?           buffered?        access permissions                 */
    /*              xxx00000 xxx00000                                                                                */
    X_ARM_MMU_SECTION(0x000, 0xF00,   0x1,   ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* ROM */
    X_ARM_MMU_SECTION(0x300, 0x300,   0x1,   ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* L2CC */
    X_ARM_MMU_SECTION(0x43F, 0x43F,   0x3C1, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* Internal Regsisters upto SDRAM*/
    X_ARM_MMU_SECTION(0x800, 0x000,   0x80,  ARM_CACHEABLE,   ARM_BUFFERABLE,   ARM_ACCESS_PERM_RW_RW); /* SDRAM */
    X_ARM_MMU_SECTION(0x800, 0x800,   0x80,  ARM_CACHEABLE,   ARM_BUFFERABLE,   ARM_ACCESS_PERM_RW_RW); /* SDRAM */
    X_ARM_MMU_SECTION(0xA00, 0xA00,   0x20,  ARM_CACHEABLE,   ARM_BUFFERABLE,   ARM_ACCESS_PERM_RW_RW); /* Flash */
    X_ARM_MMU_SECTION(0xB40, 0xB40,   0x10,  ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* External I/O */
    X_ARM_MMU_SECTION(0xB50, 0xB50,   0x8,   ARM_CACHEABLE,   ARM_BUFFERABLE,   ARM_ACCESS_PERM_RW_RW); /* PSRAM */
    X_ARM_MMU_SECTION(0xB80, 0xB80,   0x10,  ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* EIM control*/
    X_ARM_MMU_SECTION(CPLD_MMU_AB, CPLD_MMU_VB, CPLD_MMU_SIZE, ARM_UNCACHEABLE, ARM_UNBUFFERABLE, ARM_ACCESS_PERM_RW_RW); /* CPLD */
}

//
// Platform specific initialization
//

unsigned int g_clock_src;

void cpld_lcdblk(int on)
{
    CYG_BYTE value;

    value = readb(CPLD_BASE + CPLD_LCR);
    if (on)
        value |= CPLD_LCR_LCDBLKEN;
    else
        value &= ~CPLD_LCR_LCDBLKEN;
    writeb(value, CPLD_BASE + CPLD_LCR);
}

void plf_hardware_init(void)
{
    int i;
    unsigned int *p;
    unsigned int val;
    g_clock_src = FREQ_26MHZ;

    p = (unsigned int *)(IOMUXC_BASE_ADDR+0x154);
    for (i = 0; i < 110; ++i) {
        writel(_iomux_pad_data[i], p++);
    }   

    /* Configure the PC_BVD1 and PC_BVD2 to UART5_RXD and UART5_TXD. */
    iomux_config_mux(MX31_PIN_PC_BVD1, OUTPUTCONFIG_ALT2, INPUTCONFIG_ALT2);
    iomux_config_mux(MX31_PIN_PC_BVD2, OUTPUTCONFIG_ALT2, INPUTCONFIG_ALT2);

    // UAT1
    writel(0x12121212, IOMUXC_BASE_ADDR + 0x7C);
    writel(0x12121212, IOMUXC_BASE_ADDR + 0x80);

    // UART2
    writel(0x13131300, IOMUXC_BASE_ADDR + 0x70);
    writel(0x00001313, IOMUXC_BASE_ADDR + 0x74);
    writel(0x00000040, IOMUXC_BASE_ADDR + 0x7C);
    writel(0x40400000, IOMUXC_BASE_ADDR + 0x78);

	// init LCS1 - BEGIN
	iomux_config_mux(MX31_PIN_LCS1, OUTPUTCONFIG_GPIO, INPUTCONFIG_NONE);	// LCS1
	val = readl(0x53fa4004);
	val |= (1<<24);
    writel(val,0x53fa4004);

    val = readl(0x53fa4000);//poll down LCS1
    val &= ~(1<<24);
    writel(val,0x53fa4000);

	// init LCS1 - END
	
    /* Get CPLD_VR to record the board phase and PCB version*/
    val = readb(CPLD_BASE + CPLD_VR);
    pcb_ver = val & 0x07;
    bd_phase = (val & 0xE0) >> 5;
	
    mxc_pmic_init();
    check_batt_low();
	//lcd_init();
    //check_power_on();
    mxc_kpp_init();
    cpld_init();
    gps_init();
}

extern void iomux_config_mux(unsigned int pin, int out, int in);

void lcd_init(void)
{
	unsigned int val;

	hal_delay_us(10000);
	
	val = readl(0x53fa4000);
	val |= (1<<24);
    writel(val,0x53fa4000);
}

void mxc_kpp_init(void)
{
    /* sw_mux_ctl_key_col0 ~ 7 */
    writel(0x12121212, IOMUXC_BASE_ADDR + 0x60);
    writel(0x12121212, IOMUXC_BASE_ADDR + 0x64);

    /* sw_mux_ctl_key_row0 ~ 7 */
    writel(0x12121212, IOMUXC_BASE_ADDR + 0x68);
    writel(0x12121212, IOMUXC_BASE_ADDR + 0x6C);

    mxc_kpp_set_clock(1);

    /* KCO = 1, configure columns as open-drain */
    insw(0xFF00, KPP_BASE_ADDR + 0x00, 0xFF00);

    /* KRE = 1, include all rows in the keypad */
    insw(0x00FF, KPP_BASE_ADDR + 0x00, 0x00FF);

    /* KCD = 0, write 0 to all columns */
    insw(0x0000, KPP_BASE_ADDR + 0x06, 0xFF00);

    /* KCDD = 1, columns as output */
    insw(0xFF00, KPP_BASE_ADDR + 0x04, 0xFF00);

    /* KRDD = 0, rows as input */
    insw(0x0000, KPP_BASE_ADDR + 0x04, 0x00FF);

    mxc_kpp_set_clock(0);
}

void mxc_kpp_set_clock(int on)
{
    if (on) {
        insl(0x00300000, CCM_BASE_ADDR + 0x24, 0x00300000);
    } else {
        insl(0x00000000, CCM_BASE_ADDR + 0x24, 0x00300000);
    }
}

cyg_uint8 mxc_kpp_scan(void)
{
    cyg_uint16 key;

    mxc_kpp_set_clock(1);
    key = readw(KPP_BASE_ADDR + 0x06);
    key = ~key;
    mxc_kpp_set_clock(0);

    return (cyg_uint8)key;
}

void cpld_init(void)
{
    /* CPLD CCR */
    insb(CPLD_CCR_VPLLSW, CPLD_BASE + CPLD_CCR, CPLD_CCR_VPLLSW);
}

void gps_init(void)
{
    insb(                0, CPLD_BASE + CPLD_CCR, CPLD_CCR_GPSRESET);
    hal_delay_us(100000);
    insb(CPLD_CCR_GPSRESET, CPLD_BASE + CPLD_CCR, CPLD_CCR_GPSRESET);
}

#ifdef CYG_HAL_ARM_G23_TARGET_TYPE_EVT
void usb2uart(void)
{
    /* sw_mux_ctl_usbotg_data1 & sw_mux_ctl_usbotg_data2 */
    insl(0x20200000, IOMUXC_BASE_ADDR + 0x004C, 0x8080FFFF);

    /* set CONMODE0-3 bit to UART4 mode */
    pmic_reg_set(49, 0x00085004, 0x0009D004);
	
    /* VUSBEN =1 (regardless of USBEN pin) */
    pmic_reg_set(50, 0x0000002E, 0x0000012C);

    /* enable usb to uart */
    insb(CPLD_CCR_USBUARTS, CPLD_BASE + CPLD_CCR, CPLD_CCR_USBUARTS);
}
#endif

void led_shine(bool enable)
{
	if(enable) {
		pmic_reg_set(52,    1 <<  8, 0xFFFFFF);
		pmic_reg_set(51,    1 <<  0, 0xFFFFFF);
		pmic_reg_set(55, 0x1f << 16, 0xFFFFFF);
	} else {
		pmic_reg_set(52,    0, 0xFFFFFF);
		pmic_reg_set(51,    0, 0xFFFFFF);
		pmic_reg_set(55, 0x1f << 16, 0xFFFFFF);
	}
}

extern void draw_up(void);
extern void draw_down(void);

static void board_redboot_init()
{
    cyg_uint8 key;
    cyg_uint32 press_count = 0;
    cyg_uint32 dummy_count = 0;
	cyg_uint32 stat;
    struct cmd *cmd_struct;
    unsigned char *boot_select = (unsigned char *)REDBOOT_IMAGE_SIZE;
    char argv_address[] = "0x12345678";
    char *argv[] = {"nand", "fatread", "-f", "bootsel.txt",
                    "-b", argv_address, "-l", "1"};

    volatile cyg_uint32 intr_sense;

    #define PRESS_TIME	0x200000	// about 1sec
    #define DUMMY_TIME	0x400000	// about 2sec

    /* multi boot */
    enum {
        normal_boot = 1,
        recover_boot,
        diagnostic_boot,
    };

    /* multi boot config */
    extern int boot_config;

	
    mxc_framebuffer_init();
    lcd_init();//move here for LCS1 pin reset
	check_power_on();
	
    /* read USB status for auto detect UART */
    intr_sense = pmic_reg(2, 0, 0);

    if (((intr_sense & USB_MASK) == USB_SONY) ||
        ((intr_sense & USB_MASK) == USB_SONY_PLUS)) {
#ifdef CYG_HAL_ARM_G23_TARGET_TYPE_EVT
        usb2uart();
#endif
    }

    /*
     * we have 4 condition.
     * No key   -> it is normal, but it would be check
     *             bootsel.txt and use bootsel.txt to boot up.
     * Menu key -> into detect Diagnostic procedure.
     * Pos key  -> into detect Recover procedure.
     * Menu + Pos key -> reserve(no use).
     */

    /* first time, which is key press */	
    key = mxc_kpp_scan();

	/* default: recover mode */
	boot_config = recover_boot;

	stat = pmic_reg(22,0,0);
	if ( stat == 0x7ff0 ) {
		// Reboot from diagnostic mode.
		boot_config = diagnostic_boot;
		
		key = mxc_kpp_scan();

		if ((key&0x10) == 0x10) {
			// Cancel for lba test
			pmic_reg_set( 3,1,0x2);
			pmic_reg_set( 4,1,0x2);
			pmic_reg_set(20, 0x1, 0x1FFFF);
			pmic_reg_set(21, 0x0, 0x1FFFF);
			pmic_reg_set(22, 0x0, 0x7FFF);
			pmic_reg_set(23, 0x0, 0x7FFF);
		}
	} else {
		if ((key&0x18) == 0x18) { // detect reserve(no use)
			boot_config = normal_boot;
			
		} else if (key == 0x0) { // detect NORMAL
	        boot_config = normal_boot;

	        cmd_struct = cmd_search(__NAND_cmds_TAB__, &__NAND_cmds_TAB_END__,
	                                argv[1]);
	        diag_sprintf(argv_address, "%p", boot_select);
	        *boot_select = 0;
	        cmd_struct->fun(8, argv);
	        if ('N' == *boot_select || 'n' == *boot_select) {
	            boot_config = normal_boot;
	        } else if ('R' == *boot_select || 'r' == *boot_select) {
	            boot_config = recover_boot;
	        } else {
	        	boot_config = recover_boot;
	        }
		} else if ((key&0x8) == 0x8) { // detect DIAGNOSTIC step-1
			
			// DIAGNOSTIC step-2
			press_count=0;
			dummy_count=0;
			while (1) {
	            key = mxc_kpp_scan();

	            if ( ((key&0x10)==0x10)) {
	                press_count++;
	                if (press_count==PRESS_TIME) {
						// run DIAGNOSTIC step-3
	                    break;
	                }
	            }

				if (key == 0x0) {
					dummy_count++;
					if (dummy_count==DUMMY_TIME) {
	                    boot_config = normal_boot;
	                    goto job_finish;
	                }
				}
	        }

			// DIAGNOSTIC step-3
			press_count=0;
			dummy_count=0;
			while (1) {
	            key = mxc_kpp_scan();

	            if ( ((key&0x8)==0x8)) {
	                press_count++;
	                if (press_count==PRESS_TIME) {
						boot_config = diagnostic_boot;
	                    break;
	                }
	            }

				if (key == 0x0) {
					dummy_count++;
					if (dummy_count==DUMMY_TIME) {
	                    boot_config = normal_boot;
	                    goto job_finish;
	                }
				}
	        }
		} else if ((key&0x10) == 0x10) { // detect RECOVER step-1

			// RECOVER step-2
			press_count=0;
			dummy_count=0;
			//led_shine(true);
			//draw_up();
			//cpld_lcdblk(1);
			
			while (1) {
	            key = mxc_kpp_scan();

	            if ( ((key&0x8)==0x8)) {
	                press_count++;
	                if (press_count==PRESS_TIME) {
						// run RECOVER step-3
						//led_shine(false);
						//draw_down();
						//cpld_lcdblk(1);
	                    break;
	                }
	            }

				if (key == 0x0) {
					dummy_count++;
					if (dummy_count==DUMMY_TIME) {
	                    boot_config = normal_boot;
	                    goto job_finish;
	                }
				}
	        }

			// RECOVER step-3
			press_count=0;
			dummy_count=0;
			while (1) {
	            key = mxc_kpp_scan();

	            if ( ((key&0x10)==0x10)) {
	                press_count++;
	                if (press_count==PRESS_TIME) {
						boot_config = recover_boot;
	                    break;
	                }
	            }

				if (key == 0x0) {
					dummy_count++;
					if (dummy_count==DUMMY_TIME) {
	                    boot_config = normal_boot;
	                    goto job_finish;
	                }
				}
	        }
		}
	}
job_finish:
	led_shine(false);
	
    /* clear ON1B event */
    pmic_reg(3, 0x00000008, 1);

    //mxc_framebuffer_init();
    //lcd_init();//move here for LCS1 pin reset
    paint_logo();
    cpld_lcdblk(1);
}

RedBoot_init(board_redboot_init, RedBoot_INIT_FIRST);

#include CYGHWR_MEMORY_LAYOUT_H

typedef void code_fun(void);

void board_program_new_stack(void *func)
{
    register CYG_ADDRESS stack_ptr asm("sp");
    register CYG_ADDRESS old_stack asm("r4");
    register code_fun *new_func asm("r0");
    old_stack = stack_ptr;
    stack_ptr = CYGMEM_REGION_ram + CYGMEM_REGION_ram_SIZE - sizeof(CYG_ADDRESS);
    new_func = (code_fun*)func;
    new_func();
    stack_ptr = old_stack;
}

cyg_bool check_power_key(void)
{
    cyg_uint32 stat;

    stat = pmic_reg(3, 0, 0);
    if (stat & 0x8) {
        /* clear power key status */
        pmic_reg_set(3, 0x00000000, 0xFFFFFFF7);
        return true;
    }

    return false;
}

void power_off(void)
{
	/* Clean RESTART flag */
	if (pcb_ver == Japan && bd_phase >= BOARD_PHASE_DVT)
		pmic_reg_set(19, 0x0, 0xFFFFFF);

    /* Turn off the system */
    insb(CPLD_CCR_WDI, CPLD_BASE + CPLD_CCR, CPLD_CCR_WDI);
}

void check_power_on(void)
{
    cyg_uint32 stat, count, ONOFD1S,ONOFD1I;
	cyg_uint32 usb_type;
	
	if (pcb_ver == Japan && bd_phase >= BOARD_PHASE_DVT){
		stat = pmic_reg(19,0,0);
		// From kernel : Set CPLD_CCR RESTART or Watchdog's RESTART
		if (stat == RESTART)
			return;
		else
			pmic_reg_set(19, RESTART, 0x000001);
	}

	stat = pmic_reg(18,0,0);
	if (stat == 0x78) {
		// Reboot from Kernel, clean reg18 for reboot next time.
		pmic_reg_set(18, 0x000000, 0xFFFFFF);
		return;
	}

	// Clean reg18 for reboot next time.
	pmic_reg_set(18, 0x000000, 0xFFFFFF);
	
	ONOFD1S = pmic_reg(5, 0, 0);
	ONOFD1I = pmic_reg(3, 0, 0);
	if (!(ONOFD1S & 8) || (ONOFD1I & 8)) {
		/* Press power key */
		return;
	} else {
		stat = pmic_reg(5, 0, 0);
		if (stat & 8) {
			hal_delay_us(70000);
			stat = pmic_reg(5, 0, 0);
			if (stat & 8) {
				usb_type = pmic_reg(2, 0, 0);
				if( (usb_type&USB_MASK)==USB_PC ||
					(usb_type&USB_MASK)==USB_CLA ||
					(usb_type&USB_MASK)==USB_POWERSUPPLY ||
					(usb_type&USB_MASK)==USB_ADAPTER ||
					(usb_type&USB_MASK)==USB_SONY) {
		     	   return;
				}
			}
		}
	}

	power_off();

}

void check_batt_low(void)
{
    cyg_uint32 stat;

    /* BPDET = 10. For checking battery low voltage. */
    pmic_reg_set(13, 0x020000, 0x030000);
    stat = pmic_reg(2, 0, 0);
    /* Check LOBATHI sense bit. */
    if (~stat & (1 << 14)) {
#ifdef DEBUG_POWERON
        /* Use green LED instead of power off. */
        pmic_reg_set(52,    1 <<  8, 0xFFFFFF);
        pmic_reg_set(51,    1 <<  0, 0xFFFFFF);
        pmic_reg_set(55, 0x1f <<  6, 0xFFFFFF);
#else
        power_off();
#endif
    }
}

void get_cpld_pcb_version(cyg_int8 *VR_pcb)
{
	*VR_pcb = pcb_ver;
}

void get_cpld_board_phase(cyg_int8 *VR_phase)
{	
	*VR_phase = bd_phase;
}


void board_redboot_mainloop(void)
{
}

static void display_clock_src(void)
{
    diag_printf("\n");
    if (g_clock_src == FREQ_27MHZ) {
        diag_printf("Clock input is 27 MHz");
    } else if (g_clock_src == FREQ_26MHZ) {
        diag_printf("Clock input is 26 MHz");
    } else if (g_clock_src == FREQ_32768HZ) {
        diag_printf("Clock input is 32KHz");
    } else {
        diag_printf("Unknown clock input source. Something is wrong!");
    }
}
RedBoot_init(display_clock_src, RedBoot_INIT_LAST);

