/*
  ******************************************************************************
  * @file    HAL_EFlash.c
  * @author  Firmware Team
  * @version V1.0.1
  * @date    2021  
  * @brief   EFlash HAL module driver.
  *          This file provides firmware functions to manage the following 
  *          functionalities of the internal FLASH memory:
  *           @ Program operations functions
  *           @ Erase   operations functions
  ******************************************************************************
  ******************************************************************************
*/
#include "ACM32Fxx_HAL.h"

#define REG(x) 		(*(volatile UINT32 *)(x))  
#define PAGE_SIZE		512U 

void HAL_EFlash_ReWrite_Word(UINT32 addr, UINT32 value)	
{
	UINT32 buff[128];
	UINT32 i;
	UINT32 *dst;
	UINT32 dst_addr;
	UINT32 page_addr;  		

	if(REG(addr)==value)
	{
		return;
	}
	
	page_addr = addr&0xFFFFFE00;
	
	dst = (UINT32 *)(page_addr);
	for(i=0;i<(PAGE_SIZE/4); i++)
	{
		buff[i]=*dst++;
	}
	buff[(addr-page_addr)/4] = value; 
	
	HAL_EFlash_ErasePage(page_addr);
	
	dst_addr = page_addr;
	for(i=0;i<(PAGE_SIZE/4); i++)
	{
		HAL_EFlash_Program_Word(dst_addr,buff[i]);
		dst_addr +=4;
	}		
}

void HAL_EFlash_Return_to_Boot(void)	 
{
    HAL_EFlash_ReWrite_Word(0x00080400, 0xFFFFFFFFU);    
}

void HAL_EFlash_Remap_Enable(void)	       
{
    HAL_EFlash_ReWrite_Word(0x00080400, 0x89BC3F51U);      
}

void HAL_EFlash_JTAG_Enable(void)	 
{
    HAL_EFlash_ReWrite_Word(0x0008041C, 0xFFFFFFFFU);      
}  

void HAL_EFlash_JTAG_Diable(void)	 
{
    HAL_EFlash_ReWrite_Word(0x0008041C, 0x89BC3F51U);        
}

void HAL_EFlash_Option_LOCK(void) 	 
{
    HAL_EFlash_ReWrite_Word(0x000805FC, 0x55AA77EEU);        
}  

void HAL_EFlash_Init_Para(uint32_t fu32_freq)
{
    uint32_t lu32_RDWait;
    uint32_t lu32_TERASE;
    uint32_t lu32_TPROG;
    uint32_t lu32_TNVS;
    
    /* Eflash Config */
    
    lu32_TERASE = 35 * (fu32_freq/10000U)   + 1;   // 3.5 ms 
    lu32_TPROG  = 9  * (fu32_freq/1000000U) + 1;   // 9us
    lu32_TNVS   = (51 * (fu32_freq/1000000U))/10 + 5;   // 5.1us  
    
    if(fu32_freq > 40000000) 
    {
        lu32_RDWait = 1;   
    }  
    else
    {
       lu32_RDWait = 0;
    }

    EFC->NVS   = lu32_TNVS;
    EFC->CTRL   = (EFC->CTRL & ~(0x1F << 7)) | (lu32_RDWait << 7);
    EFC->TERASE = lu32_TERASE;
    EFC->TPROG  = lu32_TPROG;       
}  






