/*
 * diag_main_menu.c
 *
 * Matthew Millman
 */
 
#include <common.h>
#include <version.h>
#include <linux/ctype.h>
#include <diag.h>
#include <asm/processor.h>
#include <asm/byteorder.h>
#ifdef CONFIG_BOOTMENU
#include <bootmenu.h>
#endif

DECLARE_GLOBAL_DATA_PTR;

int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);

static const unsigned char consolehexlowerchars[] = "0123456789abcdef";

#if 1
// Removed due to CR 19528
static const char splash[] = "";
#else
#if defined(CONFIG_DIAGNOSTICS_SPLASH_XCALIBUR)

static const char splash[] = 
"                       .__  ._____.                 \n"
"  ___  ___ ____ _____  |  | |__\\_ |__  __ _________ \n"
"  \\  \\/  // ___\\\\__  \\ |  | |  || __ \\|  |  \\_  __ \\\n"
"   >    <\\  \\___ / __ \\|  |_|  || \\_\\ \\  |  /|  | \\/\n"
"  /__/\\_ \\\\___  >____  /____/__||___  /____/ |__|   \n"
"        \\/    \\/     \\/             \\/              \n";

#elif defined(CONFIG_DIAGNOSTICS_SPLASH_RAPTOR)

static const char splash[] = 
"                          __            \n"
"    ____________  _______/  |_  ___________ \n"
"    \\_  __ \\__  \\ \\____ \\   __\\/  _ \\_  __ \\\n"
"     |  | \\// __ \\|  |_> >  | (  <_> )  | \\/\n"
"     |__|  (____  /   __/|__|  \\____/|__|   \n"
"                \\/|__|                      \n";

#else
static const char splash[] = "";
#endif
#endif /* 1 */

void diag_decimal_out( long decimalLong )
{
	unsigned char	txChar;
	unsigned char	buff[16];
	u32	 	i;

	if ( decimalLong == 0 )
	{
		txChar = '0';
		serial_putc( txChar );
	}
	else
	{
		i = 0;
		do
		{
			buff[ i ] = ( unsigned char )( decimalLong % 10 + '0' );
			decimalLong /= 10;
			i++;
		} while ( decimalLong > 0 );
					
		for ( ; i; i-- )
		{
			txChar = buff[ i - 1 ];
			serial_putc( txChar );
		}
	}

}

void diag_hex4byte_out( u32 hexLong )
{
	diag_hexbyte_out((hexLong >> 24) & 0xff);
	diag_hexbyte_out((hexLong >> 16) & 0xff);
	diag_hexbyte_out((hexLong >> 8) & 0xff);
	diag_hexbyte_out((hexLong >> 0) & 0xff);
}

void diag_hex2byte_out( u16 hexWord )
{
	diag_hexbyte_out((hexWord >> 8) & 0xff);
	diag_hexbyte_out((hexWord >> 0) & 0xff);
}

void diag_hexbyte_out( u8 hexByte )
{
	unsigned char	*chPt;
	unsigned char	*inPt;
	unsigned char	txChar;

	chPt = ( unsigned char * )&consolehexlowerchars[ 0 ];
	inPt = ( unsigned char * )&hexByte;
	txChar = chPt[ ( *inPt >> 4 ) ];
	serial_putc( txChar );
	txChar = chPt[ ( *inPt & 0x0f ) ];
	serial_putc( txChar );

}

void diag_printf (const char *fmt, ...)
{
	va_list args;
	uint i;
	char printbuffer[2048];

	if (!(gd->flags & GD_FLG_DIAGS_STAGE2) && !(gd->flags & GD_FLG_DIAGS))
		return;
	
	
	va_start (args, fmt);

	/* For this to work, printbuffer must be larger than
	* anything we ever want to print.
	*/
	i = vsprintf (printbuffer, fmt, args);
	va_end (args);

	/* Print the string */
	serial_puts (printbuffer);
}

u8 diag_query_quit(void)
{
	if (gd->flags & GD_FLG_QUIT)
	{
		gd->flags &= ~GD_FLG_QUIT;
		return 1;
	}
	return 0;
}

u8 diag_test_quit(void)
{
	unsigned char	key;
	u8		retValue;
	
	retValue = 0;
	
	if (tstc() && (gd->flags & GD_FLG_DIAGS_STAGE2))
	{
		key = serial_getc();
		if ( key == 'Q' || key == 'q' || key == 0x03)
		{
			gd->flags |= GD_FLG_QUIT;
			retValue = 1;
		}
	}
	return( retValue );

} 

void diag_run1( void )
{
	char		key;
	u8		quit;

	quit = 0;

	while ( !quit )
	{

/*		Display the menu
 */
		diag_printf( "\n\nBootup Stage 1 Diagnostics Menu:\n\n"
		                   "  0. Restart\n"
#ifndef CONFIG_ATRD_X300
				   "  1. Full RAM test\n"
				   "  2. Quick RAM test\n"
#ifdef CONFIG_NVS_SIZE
				   "  3. Battery backed RAM (NVS) test\n"
#endif
		                   "  4. Bootloader ROM checksum test\n"
#endif
				   "  ----------------------------------\n"
				   "  7. Bootup stage 2 diagnostics menu\n"
				   "  ----------------------------------\n"
				   "  8. Quit to U-Boot shell\n"	
				   "  9. Quit and continue booting\n"	
		                   "\nEnter selection ==> " );

		key = serial_getc();

		if ( key >= '0' && key <= '9' )
		{
			diag_printf("%c\n\n", key);
		}

		switch ( key )
		{
			case '0':
				do_reset(NULL, 0, 0, NULL);
				break;
#if !defined(CONFIG_ATRD_X300)
			case '1':
				diag_ram_pattern_test( 0 );	
				break;

			case '2':
				diag_ram_pattern_test( 1 /* quickTest */ );
				break;

#ifdef CONFIG_NVS_SIZE
			case '3':
				diag_nvs_pattern_test();
				break;
#endif
			case '4':
				diag_rom_checksum_test();
				break;
#endif
			case '7':
				gd->flags |= GD_FLG_DIAGS_STAGE2;
				diag_printf("Entering stage 2...\n");
				quit = 1;
				break;
			case '8':
				gd->flags |= GD_FLG_UBSHELL;
				quit = 1;
				break;
			case '9':
				quit = 1;
				break;
			default:	
				break;
		}
	}

}


void diag_run2( void )
{
	char		key;
	u8		quit = 0;
	char		program_passwd[] = "PROGRAM";
	char		*pt;

	while ( !quit )
	{
		diag_printf( "\n\nBootup Stage 2 Diagnostics Menu:\n\n"
				"  0. Restart\n"	);	
		if (atl_bootrom_board_attached())
			diag_printf(		
				"  1. Test FLASH (All flash)\n" );
		diag_printf( 	"  2. Test FLASH (Filesystem only)\n");
		if (atl_bootrom_board_attached())
			diag_printf(		
				"  3. Erase FLASH (All flash)\n");

		diag_printf(	"  4. Erase FLASH (Filesystem only)\n");

#ifdef CONFIG_MMC_SPI
		diag_printf(	"  5. Card slot test\n");
#endif
#ifdef CONFIG_CMD_W1
		diag_printf(	"  6. Probe 1-wire bus\n");
#endif
#ifdef CONFIG_DIAG_USB
		diag_printf(	"  7. USB slot test\n");
#endif /* CONFIG_DIAG_USB */
		diag_printf(	"  ----------------------------------\n"
				"  8. Quit to U-Boot shell\n"
				"  9. Quit and continue booting\n"	
				"\nEnter selection ==> " );

		key = serial_getc();

		if ( key >= '0' && key <= '9' )
		{
			diag_printf("%c\n\n", key);
		}

		switch ( key )
		{
			case '0':
				do_reset(NULL, 0, 0, NULL);
				break;
			case '1':
				if (atl_bootrom_board_attached())
				{
#ifdef DIAG_FLASH
                    	              diag_flash_test(1);
#endif
				}
				break;
			case '2':
#ifdef DIAG_FLASH
				diag_flash_test(0);
#endif
				break;
			case '3':
#ifdef DIAG_FLASH
				diag_erase_all_flash(0, 1);
#endif
				break;
			case '4':
#ifdef DIAG_FLASH
				diag_erase_all_flash(0, 0);
#endif
				break;
			case '=':
				for (pt = &program_passwd[0]; *pt; pt++) {
					key = toupper(serial_getc());
					if (key != *pt) {
						break;
					}
					diag_printf("%c", *pt);
				}
				if (*pt == '\0') {
#ifdef CONFIG_DIAG_EPI3
					diag_epi3_menu_run();
#endif /* CONFIG_DIAG_EPI3 */
#ifdef CONFIG_DIAG_IDPROM
					diag_idprom_menu_run();
#endif /* CONFIG_DIAG_IDPROM */
				}
				break;
			case '5':
#ifdef CONFIG_MMC_SPI
				diag_card_slot_test();
#endif
				break;
			case '6':
#ifdef CONFIG_CMD_W1
				diag_probe_w1();
#endif /* CONFIG_CMD_W1 */
				break;
			case '7':
#ifdef CONFIG_DIAG_USB
				diag_usb_test();
#endif /* CONFIG_DIAG_USB */
				break;
			case '8':
				gd->flags |= GD_FLG_UBSHELL;
				quit = 1;
				break;
			case '9':
				quit = 1;
				break;
			default:	
				break;
		}
	}
	
	gd->flags &= ~GD_FLG_DIAGS_STAGE2;

}

void diag_printf_always (const char *fmt, ...)
{
    va_list args;
    uint i;
    char printbuffer[CONFIG_SYS_PBSIZE];
	
    va_start (args, fmt);

	/* For this to work, printbuffer must be larger than
    * anything we ever want to print.
        */
    i = vsprintf (printbuffer, fmt, args);
    va_end (args);

    /* Print the string */
    serial_puts (printbuffer);
}

u8 diag_enter_shell(void)
{
	if (gd->flags & GD_FLG_UBSHELL)
		return 1;
	else
		return 0;
}

void diag_restore_shell(void)
{
	gd->flags &= ~GD_FLG_SILENT;
}

void diagnostics2(void)
{
#ifdef CONFIG_DIAGNOSTICS
	if (gd->flags & GD_FLG_DIAGS_STAGE2)
		diag_run2();
#endif
}

void diagnostics(void)
{
	int i;
	int j;
	int delay = 0;
	char *bootdelay;
	
	serial_puts("\nBootloader ");
	serial_puts(ATL_EXTRA_VERSION);
	serial_puts(" loaded\n");
#ifdef CONFIG_BOOTMENU
	serial_puts("Press <Ctrl+B> for the Boot Menu");
#endif
	bootdelay = getenv("bootdelay");
	if (bootdelay)
		delay = simple_strtoul(bootdelay, NULL, 10);
	
	if (!delay)
		delay = 1;
	
	for (i = 0; i < delay; i++)
	{
		for (j=0; j<100; ++j) 
		{
			if (tstc()) {
				char c;
				
				c = serial_getc();
				
				switch (c)
				{
					case 4: /* Ctrl+D: Diagnostics */
						serial_puts("\n");
#ifndef CONFIG_DIAGNOSTICS
						diag_printf("There is no diagnostics menu in the boot software currently installed\n");
#else
						serial_puts(splash);
						gd->flags |= GD_FLG_DIAGS;
						diag_run1();
						gd->flags &= ~GD_FLG_DIAGS;
#endif
						goto done;
					case 21: /* Ctrl+U: U-boot shell */
						serial_puts("\n");
						serial_puts("Entering U-Boot shell\n");
						gd->flags |= GD_FLG_UBSHELL;
						goto done;
#ifdef CONFIG_BOOTMENU
					case 2: /* Ctrl+B: bootmenu */
						serial_puts("\n");
						gd->flags |= GD_FLG_BOOTMENU;
						goto done;
#endif
					case 15: /* Ctrl+O U-Boot shell and turn on all output */
						serial_puts("\n");
						gd->flags &= ~GD_FLG_SILENT;
						gd->flags |= GD_FLG_UBSHELL;
						goto done;
						
				}
				
			}
				
			udelay (10000);
		}
	}
	serial_puts("\n");

done:
#if defined(CONFIG_X200_GE) || defined(CONFIG_X200_X400_FE) || defined(CONFIG_X210_ATRD) || defined(CONFIG_X510)
	diag_quick_ram_test(CONFIG_DIAG_RAM_START);
#elif defined(CONFIG_ATRD_X300)
	// no quick ram test on x300
#else
	diag_quick_ram_test(0);
#endif
	return;

}
