/*
* Copyright (c) 2023-2028, SpaceTouch Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date          Author      Notes
* 2023-08-11    jinyaoh         the first version
*/

#include "hal_efuse.h"
#include "platform.h"


uint8_t hal_efuse_write(HAL_EFUSE_SECTOR sector,HAL_EFUSE_VALUE addr,uint32_t value)
{
	uint8_t j;
	uint32_t read_data;
	DEV_CMU->CLKEN0  |= DEV_CMU_CLKEN0_EFUSE | DEV_RMU_RSTEN0_AON;
	DEV_RMU->RSTEN0  |= DEV_RMU_RSTEN0_EFUSE | DEV_RMU_RSTEN0_AON;
	AON_PMU->PWR_CTL |= AON_PMU_PWR_CTL_VDDQ_NORM_EN;
	delay_ms(24 * MHz, 10);
	DEV_EFUSE->CMD  |= (1<<3)+(sector <<4 ); //sleep fast mode:1: pull up
	delay_ms(10);
	for(j=0; j<32; j++)
	{
		if(value & (1<<j))
		{
			DEV_EFUSE->CMD_f.PG_MODE = 1;
			DEV_EFUSE->ADR = (SECTOR0 + sector) * 256 + (EFUSE0 + addr) * 32 + j;
			DEV_EFUSE->CMD |=(2<<1) | (1<<0);
			while((DEV_EFUSE->CMD & 0x1) != 0)//wait for program done
			delay_ms(1);
			DEV_EFUSE->CMD_f.PG_MODE = 0;
		}
	}
	DEV_EFUSE->CMD   = 0; //sleep fast mode:1: pull down
	delay_ms(24 * MHz, 10);
	DEV_EFUSE->CMD  |= (1<<3); //sleep fast mode:1: pull up
	delay_ms(24 * MHz, 10);
	DEV_EFUSE->CMD =1;
	while((DEV_EFUSE->CMD & 0x1) != 0);//wait for read ready
	delay_ms(24 * MHz, 10);
	read_data = *(volatile uint32_t *)(addr);
	if(read_data != value)
	{
      return 1;
	}
	return 0;
}

/**
 * this function will read efuse value
 *
 * @param sector： The value of sector ranges from SECTOR0 to SECTOR4
 * @param efuse： The value of efuse ranges from EFUSE0 to EFUSE7
 *
 * @return Returns the corresponding efuse value.
 */
uint32_t hal_efuse_read(HAL_EFUSE_SECTOR sector, HAL_EFUSE_VALUE efuse)
{
    uint32_t efuse_value = 0;

    DEV_CMU->CLKEN0  |= DEV_CMU_CLKEN0_EFUSE | DEV_RMU_RSTEN0_AON;
	DEV_RMU->RSTEN0  |= DEV_RMU_RSTEN0_EFUSE | DEV_RMU_RSTEN0_AON;
	AON_PMU->PWR_CTL |= AON_PMU_PWR_CTL_VDDQ_NORM_EN;
	delay_ms(24 * MHz, 10);


    DEV_EFUSE->CMD_f.SECTOR = sector;
    DEV_EFUSE->CMD_f.CMD = DEV_EFUSE_CMD_EFUSEREAD;
    DEV_EFUSE->CMD_f.RUN = DEV_EFUSE_CMD_RUN;

    while (DEV_EFUSE->CMD_f.RUN);

    switch (efuse)
    {
    case EFUSE0:
        efuse_value = DEV_EFUSE->VALUE0;
        break;

    case EFUSE1:
        efuse_value = DEV_EFUSE->VALUE1;
        break;

    case EFUSE2:
        efuse_value = DEV_EFUSE->VALUE2;
        break;

    case EFUSE3:
        efuse_value = DEV_EFUSE->VALUE3;
        break;

    case EFUSE4:
        efuse_value = DEV_EFUSE->VALUE4;
        break;

    case EFUSE5:
        efuse_value = DEV_EFUSE->VALUE5;
        break;

    case EFUSE6:
        efuse_value = DEV_EFUSE->VALUE6;
        break;

    case EFUSE7:
        efuse_value = DEV_EFUSE->VALUE7;
        break;

    default:
        ;
    }

    return efuse_value;
}

/**
 * This function will turn efuse programming on or off
 *
 * @param state： DISABLE or ENABLE
 *
 * @return None
 */
void hal_efuse_program_mode(Options_EnableEnum state)
{
    if (state == ENABLE)
        DEV_EFUSE->CMD_f.PG_MODE = 1;
    else
        DEV_EFUSE->CMD_f.PG_MODE = 0;
}

/**
 * This function will program the addr address of efuse
 *
 * @param addr： Unprogrammed address
 *
 * @return None
 */
void hal_efuse_write_bit(uint32_t addr)
{
    DEV_EFUSE->ADR = addr;
    DEV_EFUSE->CMD_f.CMD = 2;
    DEV_EFUSE->CMD_f.RUN = 1;

    while (DEV_EFUSE->CMD_f.RUN);
}
