/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2009 One Laptop per Child, Association, Inc.
 *
 * This program 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; version 2 of the License.
 *
 * This program 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.
 */

void WaitMicroSec(UINTN MicroSeconds)
{
	u32 i;

	for (i = 0; i < 1024 * MicroSeconds; i++) {
		__asm__ volatile ("nop\n\t");
	}

	return;
}

/*===================================================================
Function   : via_write_phys()
Precondition :
Input      :  addr
                  value
Output     : void
Purpose    :
Reference  : None
===================================================================*/

void via_write_phys(volatile u32 addr, volatile u32 value)
{
	volatile u32 *ptr;
	ptr = (volatile u32 *)addr;
	*ptr = (volatile u32)value;
}

/*===================================================================
Function   : via_read_phys()
Precondition :
Input      :  addr
Output     : u32
Purpose    :
Reference  : None
===================================================================*/

u32 via_read_phys(volatile u32 addr)
{
	volatile u32 y;
	y = *(volatile u32 *)addr;
	return y;
}

/*===================================================================
Function   : DimmRead()
Precondition :
Input      :  x
Output     : u32
Purpose    :
Reference  : None
===================================================================*/

u32 DimmRead(volatile u32 x)
{				//  volatile u32 z;
	volatile u32 y;
	y = *(volatile u32 *)x;

	return y;
}

/*===================================================================
Function   : DramBaseTest()
Precondition : this function used to verify memory
Input      :
                 BaseAdd,
                 length,
                 mode
Output     : u32
Purpose    :write into and read out to verify if dram is correct
Reference  : None
===================================================================*/
BOOLEAN DramBaseTest(u32 BaseAdd, u32 Length,
		     DRAM_TEST_MODE Mode, BOOLEAN PrintFlag)
{
	u32 TestSpan;
	u32 Data, Address, Address2;
	u8 i, TestCount;

	//decide the test mode is continous or step
	if (Mode == EXTENSIVE) {
		//the test mode is continuos and must test each unit
		TestSpan = 4;
		TestCount = 1;
	} else if (Mode == SPARE) {
		// the test mode is step and test some unit
		TestSpan = STEPSPAN;
		TestCount = TESTCOUNT;
	} else {
		PRINT_DEBUG_MEM("the test mode is error\r");
		return FALSE;
	}

	//write each test unit the value with TEST_PATTERN
	for (Address = BaseAdd; Address < BaseAdd + Length; Address += TestSpan) {
		for (i = 0; i < TestCount; i++)
			via_write_phys(Address + i * 4, TEST_PATTERN);
		if (PrintFlag) {
			if ((u32) Address % 0x10000000 == 0) {
				PRINT_DEBUG_MEM("Write in Addr =");
				PRINT_DEBUG_MEM_HEX32(Address);
				PRINT_DEBUG_MEM("\r");
			}
		}
	}

	//compare each test unit with the value of TEST_PATTERN
	//and write it with compliment of TEST_PATTERN
	for (Address = BaseAdd; Address < BaseAdd + Length; Address += TestSpan) {
		for (i = 0; i < TestCount; i++) {
			Data = via_read_phys(Address + i * 4);
			via_write_phys(Address + i * 4, (u32) (~TEST_PATTERN));
			if (Data != TEST_PATTERN) {
				PRINT_DEBUG_MEM("TEST_PATTERN ERROR !!!!! ");
				Address2 = Address + i * 4;
				PRINT_DEBUG_MEM_HEX32(Address2);
				PRINT_DEBUG_MEM(" : ");
				PRINT_DEBUG_MEM_HEX32(Data);
				PRINT_DEBUG_MEM(" \r");
				return FALSE;
			}
		}
		if (PrintFlag) {
			if ((u32) Address % 0x10000000 == 0) {
				PRINT_DEBUG_MEM("Write in Addr =");
				PRINT_DEBUG_MEM_HEX32(Address);
				PRINT_DEBUG_MEM("\r");
			}
		}
	}

	//compare each test unit with the value of ~TEST_PATTERN
	for (Address = BaseAdd; Address < BaseAdd + Length; Address += TestSpan) {
		for (i = (u8) (TestCount); i > 0; i--) {
			Data = via_read_phys(Address + (i - 1) * 4);
			if (Data != ~TEST_PATTERN) {

				PRINT_DEBUG_MEM("~TEST_PATTERN ERROR !!!!! ");
				Address2 = Address + (i - 1) * 4;
				PRINT_DEBUG_MEM_HEX32(Address2);
				PRINT_DEBUG_MEM(" : ");
				PRINT_DEBUG_MEM_HEX32(Data);
				PRINT_DEBUG_MEM(" \r");
				return FALSE;
			}
		}
	}

	return TRUE;
}

/*===================================================================
Function   : DumpRegisters()
Precondition :
Input      :
                pPCIPPI,
                DevNum,
                FuncNum
Output     : Void
Purpose    :
Reference  : None
===================================================================*/

void DumpRegisters(INTN DevNum, INTN FuncNum)
{
	INTN i, j;
	u8 ByteVal;

	ByteVal = 0;
	PRINT_DEBUG_MEM("\rDev %02x Fun %02x\r");
	PRINT_DEBUG_MEM
	    ("\r    00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\r");
	PRINT_DEBUG_MEM
	    ("---------------------------------------------------\r");
	for (i = 0; i < 0x10; i++) {
		PRINT_DEBUG_MEM_HEX32((u32)i);
		for (j = 0; j < 0x10; j++) {
			ByteVal =
			    pci_read_config8(PCI_DEV(0, DevNum, FuncNum),
					     i * 0x10 + j);
			PRINT_DEBUG_MEM_HEX8(ByteVal);
			PRINT_DEBUG_MEM(" ");

		}
		PRINT_DEBUG_MEM("\r");
	}
	return;
}

/*===================================================================
Function   : dumpnorth()
Precondition :
Input      :
                pPCIPPI,
                Func
Output     : Void
Purpose    :
Reference  : None
===================================================================*/

void dumpnorth(u8 Func)
{
	u16 r, c;
	u8 ByteVal;
	PRINT_DEBUG_MEM("Dump North!!!\r");
	for (r = 0; r < 32; r++) {
		for (c = (u16) (r << 3); c < (r << 3) + 8; c++) {
			ByteVal = 0;
			ByteVal = pci_read_config8(PCI_DEV(0, 0, Func), c);
			PRINT_DEBUG_MEM_HEX16(c);
			PRINT_DEBUG_MEM("= ");
			PRINT_DEBUG_MEM_HEX8(ByteVal);
		}
		PRINT_DEBUG_MEM("\r");
	}
}
