/*
 * @file qsee_secboot.c
 * @brief Contains test code for most of the QSEE fuse APIs.
 *
 * */
/*===========================================================================
 *    Copyright (c) 2011 by Qualcomm Technologies, Incorporated.  All Rights Reserved.
 *    ===========================================================================*/

/*===========================================================================
 *
 *  EDIT HISTORY FOR FILE
 *  $Header: 
 *  $DateTime: 
 *  $Author: pwbldsvc $
 *  # when       who     what, where, why
 *  #
 * ===========================================================================*/

#include <stdbool.h>
#include "qsee_log.h"
#include "qsee_heap.h"
#include "qsee_fuse.h"
#include "qfprom.h"
#include "bksecapp_fuse_location.h"
#include "oem_pk_hash.h"
#include "bksecapp_secboot.h"

/* Bus frequency is required when calling the qfprom APIs, 
 *    but the value is not actually used.*/
#define BUS_FREQUENCY 0 

#define CHECK_OEM_PK_HASH	0
#define CHECK_SEC_BOOT		1
#define CHECK_OEM_CONFIG	2
#define CHECK_RW_PERM		3
#define CHECK_SEC_HW_KEY	4

extern uint32 get_anti_rollback_en(void);

int32 check_oem_sec_boot_row()
{
	uint32 qfprom_status = 0;
	uint32 row_data_read[2] = {0x0, 0x0};
	uint32 fuse_addr;
	uint32 ret = 0;

	fuse_addr = HWIO_QFPROM_RAW_OEM_SEC_BOOT_ROWn_LSB_ADDR(0);
#ifdef DEBUG_LOG_ENABLE	
	qsee_log(QSEE_LOG_MSG_ERROR, "Read Fuse address [%x]", fuse_addr);
#endif	
	
	/*Read the fuse value*/
	qsee_fuse_read(fuse_addr, QFPROM_ADDR_SPACE_RAW, row_data_read, &qfprom_status);
	if(qfprom_status != QFPROM_NO_ERR)
	{
		qsee_log(QSEE_LOG_MSG_ERROR, "Initial read returned error: %d", qfprom_status);
		return -1;
	}
#ifdef DEBUG_LOG_ENABLE	
	else
	{
		qsee_log(QSEE_LOG_MSG_ERROR, "Initial read value: %x %x",row_data_read[0], row_data_read[1]);
	}
#endif	

	ret = row_data_read[0] ^ OEM_SECURE_BOOT_BLOWN_ALL;
	qsee_log(QSEE_LOG_MSG_ERROR, "SECURE BOOT TEST RESULT = 0x%x", ret);

	/* ret == 0 means SECURE BOOT ENABLED properly */

	return ret;
}

int32 check_oem_config_row()
{
	uint32 qfprom_status = 0;
	uint32 row_data_read[2] = {0x0, 0x0};
	uint32 fuse_addr;
	uint32 ret = 0;

	fuse_addr = HWIO_QFPROM_RAW_OEM_CONFIG_ROW0_LSB_ADDR;
#ifdef DEBUG_LOG_ENABLE	
	qsee_log(QSEE_LOG_MSG_ERROR, "Read Fuse address [%x]", fuse_addr);
#endif	
	/*Read the fuse value*/
	qsee_fuse_read(fuse_addr, QFPROM_ADDR_SPACE_RAW, row_data_read, &qfprom_status);
	if(qfprom_status != QFPROM_NO_ERR)
	{
		qsee_log(QSEE_LOG_MSG_ERROR, "Initial read returned error: %d", qfprom_status);
		return -1;
	}
#ifdef DEBUG_LOG_ENABLE	
	else
	{
		qsee_log(QSEE_LOG_MSG_ERROR, "Initial read value: %x %x",row_data_read[0], row_data_read[1]);
	}
#endif	
		ret = ( ( (row_data_read[0] & QFPROM_RAW_OEM_CONFIG_BOOT_LSB_BLOWN_ALL) ^ QFPROM_RAW_OEM_CONFIG_BOOT_LSB_BLOWN_ALL) | ( (row_data_read[1] & QFPROM_RAW_OEM_CONFIG_BOOT_MSB_BLOWN_ALL) ^ QFPROM_RAW_OEM_CONFIG_BOOT_MSB_BLOWN_ALL) );
#ifdef DEBUG_LOG_ENABLE	
	qsee_log(QSEE_LOG_MSG_ERROR, "OEM CONFIG ROW TEST RESULT = 0x%x", ret);
#endif		

	/* ret == 0 means OEM Config Row properly fused */
	return ret;
}

int32 check_rw_perm_row()
{
	uint32 qfprom_status = 0;
	uint32 row_data_read[2] = {0x0, 0x0};
	uint32 fuse_addr,anti_en;
	uint32 ret = 0;

	fuse_addr = HWIO_QFPROM_RAW_WR_PERM_LSB_ADDR;
#ifdef DEBUG_LOG_ENABLE	
	qsee_log(QSEE_LOG_MSG_ERROR, "Read Fuse address [%x]", fuse_addr);
#endif	
	/*Read the fuse value*/
	qsee_fuse_read(fuse_addr, QFPROM_ADDR_SPACE_RAW, row_data_read, &qfprom_status);
	if(qfprom_status != QFPROM_NO_ERR)
	{
		qsee_log(QSEE_LOG_MSG_ERROR, "Initial read returned error: %d", qfprom_status);
		return -1;
	}
#ifdef DEBUG_LOG_ENABLE	
	else
	{
		qsee_log(QSEE_LOG_MSG_ERROR, "Initial read value: %x %x",row_data_read[0], row_data_read[1]);
	}
#endif	

	anti_en = get_anti_rollback_en();
	if(anti_en)
		ret = ( (row_data_read[0] & QFPROM_RAW_WR_PERM_BLOWN_ALL_BMSK_WITH_RP) ^ QFPROM_RAW_WR_PERM_BLOWN_ALL_VALUE_WITH_RP ) ; 
	else
		ret = ( (row_data_read[0] & QFPROM_RAW_WR_PERM_BLOWN_ALL_BMSK_WITHOUT_RP) ^ QFPROM_RAW_WR_PERM_BLOWN_ALL_VALUE_WITHOUT_RP ) ; 

	/* ret == 0 means RW Row properly fused */
	qsee_log(QSEE_LOG_MSG_ERROR, "RD WR PERM ROW TEST RESULT = 0x%x", ret);
	return ret;
}

int32 check_oem_pk_hash_rows()
{
	uint32 length = sizeof(qfprom_oem_pk_hash_array) / sizeof(single_row_type);
	uint32 qfprom_status = 0;
	uint32 row_data_read[2] = {0x0, 0x0};
	uint32 fuse_addr;
	uint32 ret = 0,i;

	for (i = 0; i < length; i++)
	{
 		fuse_addr=qfprom_oem_pk_hash_array[i].raw_row_address;
#ifdef DEBUG_LOG_ENABLE		
		qsee_log(QSEE_LOG_MSG_ERROR, "Read Fuse address [%x]", fuse_addr);
#endif		
		/*Read the fuse value*/
		qsee_fuse_read(fuse_addr, QFPROM_ADDR_SPACE_RAW, row_data_read, &qfprom_status);
		if(qfprom_status != QFPROM_NO_ERR)
		{
			qsee_log(QSEE_LOG_MSG_ERROR, "Initial read returned error: %d", qfprom_status);
			return -1;
		}
#ifdef DEBUG_LOG_ENABLE		
		else
		{
			qsee_log(QSEE_LOG_MSG_ERROR, "Initial read value: %x %x",row_data_read[0], row_data_read[1]);
		}
#endif		
                if (qfprom_oem_pk_hash_array[i].row_data_lsb != row_data_read[0]
                || qfprom_oem_pk_hash_array[i].row_data_msb != row_data_read[1])
                {
                    break;
                }
            }
            if (i < length)
            {
                qsee_log(QSEE_LOG_MSG_ERROR, "QFPROM CHECK_OEM_PK_HASH[%d] value mismatch ", i);
                ret = 1;
            }
	    else
		ret = 0;		/* ret == 0 means PK Hash properly fused */

	    qsee_log(QSEE_LOG_MSG_ERROR, "OEM PK HASH ROWS TEST RESULT = 0x%x", ret);
	    return ret;
}

int32 is_secboot_enable()
{
    int32 blown=0, type;
    int ret;
    qsee_log(QSEE_LOG_MSG_ERROR, "is_secboot_enable");

    for(type = CHECK_OEM_PK_HASH; type < CHECK_SEC_HW_KEY; type++)
    {
	switch(type)
	{
		case CHECK_OEM_PK_HASH :
			ret = check_oem_pk_hash_rows();
			if(ret == -1)
				return -1;
			if(ret)
				continue;
			qsee_log(QSEE_LOG_MSG_ERROR, "OK CHECK_OEM_PK_HASH");
			break;
		case CHECK_SEC_BOOT :
			ret = check_oem_sec_boot_row();
			if(ret == -1)
				return -1;
			if(ret)
				continue;
			qsee_log(QSEE_LOG_MSG_ERROR, "OK CHECK_SEC_BOOT");
			break;
		case CHECK_OEM_CONFIG :
			ret = check_oem_config_row();
			if(ret == -1)
				return -1;
			if(ret)
				continue;
			qsee_log(QSEE_LOG_MSG_ERROR, "OK CHECK_OEM_CONFIG");
			break;
		case CHECK_RW_PERM :
			ret = check_rw_perm_row();
			if(ret == -1)
				return -1;
			if(ret)
				continue;
			qsee_log(QSEE_LOG_MSG_ERROR, "OK CHECK_RW_PERM");
			break;
	}
	blown |= (1<<type);
    }
    
	return blown ;
}

