/*********************************************************************************************************************
* RT1064DVL6A Opensourec Library RT1064DVL6A Դ⣩һڹٷ SDK ӿڵĵԴ
* Copyright (c) 2022 SEEKFREE ɿƼ
* 
* ļ RT1064DVL6A Դһ
* 
* RT1064DVL6A Դ 
* Ըᷢ GPLGNU General Public License GNUͨù֤
*  GPL ĵ3棨 GPL3.0ѡģκκİ汾·/޸
* 
* Դķϣܷãδκεı֤
* ûԻʺض;ı֤
* ϸμ GPL
* 
* ӦյԴͬʱյһ GPL ĸ
* ûУ<https://www.gnu.org/licenses/>
* 
* ע
* Դʹ GPL3.0 Դ֤Э Ϊİ汾
* Ӣİ libraries/doc ļµ GPL3_permission_statement.txt ļ
* ֤ libraries ļ ļµ LICENSE ļ
* ӭλʹò ޸ʱ뱣ɿƼİȨ
* 
* ļ          zf_driver_flash
* ˾          ɶɿƼ޹˾
* 汾Ϣ          鿴 libraries/doc ļ version ļ 汾˵
*           IAR 8.32.4 or MDK 5.33
* ƽ̨          RT1064DVL6A
*           https://seekfree.taobao.com/
* 
* ޸ļ¼
*                               ע
* 2022-09-21        SeekFree            first version
********************************************************************************************************************/

#include "fsl_cache.h"
#include "zf_common_debug.h"
#include "zf_common_interrupt.h"
#include "zf_driver_romapi.h"
#include "zf_driver_flash.h"


flexspi_nor_config_t config;

uint32 flash_instance = 1;

flash_data_union flash_union_buffer[FLASH_DATA_BUFFER_SIZE];               // FLASH ݻ



//-------------------------------------------------------------------------------------------------------------------
//      У FLASH Ƿ
// ˵     sector_num      Ҫд Χ <0 - 127>
// ˵     page_num        ǰҳı   Χ <FLASH_PAGE_0-FLASH_PAGE_7>
// ز     uint8           1- 0-û ҪݵдµӦöв
// ʹʾ     flash_check(FLASH_SECTION_127, FLASH_PAGE_3);
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_check (uint32 sector_num, flash_page_enum page_num)
{
    uint16 i;
    
    status_t state = kStatus_Success;
    DCACHE_CleanInvalidateByRange(FLASH_BASE_ADDR + sector_num * FLASH_SECTOR_SIZE + page_num * FLASH_PAGE_SIZE, FLASH_PAGE_SIZE);//ȡflashǰջ
    
    for(i=0; i<FLASH_PAGE_SIZE/4; i++)
    {
        if(0xFFFFFFFF != flash_read(sector_num, page_num, i, uint32))
        {
            state =  kStatus_Fail;//flashҪ
            break;
        }
    }
    
    return state;
}

//-------------------------------------------------------------------------------------------------------------------
//      
// ˵     sector_num      Ҫ Χ <0 - 127>
// ˵     page_num        ǰҳı   Χ <FLASH_PAGE_0-FLASH_PAGE_7>
// ز     uint8           1-ʾʧ 0-ʾɹ
// ʹʾ     flash_erase_page(FLASH_SECTION_127, FLASH_PAGE_3);
// עϢ     Ȼǲҳʵǲһɾǽҳʹõ
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_erase_page (uint32 sector_num, flash_page_enum page_num)
{
    uint32 primask;
    status_t state = kStatus_Success;
    primask = interrupt_global_disable();
    state = rom_api_flexspi_nor_flash_erase(flash_instance, &config, sector_num * FLASH_SECTOR_SIZE + page_num * FLASH_PAGE_SIZE, FLASH_PAGE_SIZE);
    interrupt_global_enable(primask);
    if(state != kStatus_Success)
    {
        state = kStatus_Fail;
    }
    
    return state;
}

//-------------------------------------------------------------------------------------------------------------------
//      ȡһҳ
// ˵     sector_num      Ҫȡ Χ <0 - 127>
// ˵     page_num        ǰҳı   Χ <FLASH_PAGE_0-FLASH_PAGE_7>
// ˵     buf             Ҫȡݵַ   ͱΪuint32
// ˵     len             Ҫдݳ   Χ 1-1024
// ز     void
// ʹʾ     flash_read_page(FLASH_SECTION_127, FLASH_PAGE_3, data_buffer, 256);
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
void flash_read_page (uint32 sector_num, flash_page_enum page_num, uint32 *buf, uint16 len)
{
    DCACHE_CleanInvalidateByRange(FLASH_BASE_ADDR + sector_num * FLASH_SECTOR_SIZE, len * 4);//ȡflashǰջ
    
    rom_api_flexspi_nor_flash_read(flash_instance, &config, buf, sector_num * FLASH_SECTOR_SIZE + page_num * FLASH_PAGE_SIZE, len * 4);
}

//-------------------------------------------------------------------------------------------------------------------
//      һҳ
// ˵     sector_num      Ҫд Χ <0 - 127>
// ˵     page_num        ǰҳı   Χ <FLASH_PAGE_0-FLASH_PAGE_7>
// ˵     buf             Ҫдݵַ   ͱΪuint32
// ˵     len             Ҫдݳ   Χ 1-1024
// ز     uint8           1-ʾʧ 0-ʾɹ
// ʹʾ     flash_write_page(FLASH_SECTION_127, FLASH_PAGE_3, data_buffer, 256);
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_write_page (uint32 sector_num, flash_page_enum page_num, const uint32 *buf, uint16 len)
{
#define PAGE_BUFFER_SIZE 64                                                     // д뻺ĴС
    uint8 i = 0;
    uint32 primask;
    status_t state = kStatus_Success;
    flash_data_union block[PAGE_BUFFER_SIZE] = {0};                             // ÿдҪд64uint32
    
    zf_assert(len <= FLASH_DATA_BUFFER_SIZE);                                   // жǷһҳĴС 1024uint32         
    
    if(flash_check(sector_num, page_num))                                       // жǷ ı ֹûд
    {
        flash_erase_page(sector_num, page_num);                                 // һҳ
    }
    
    for(i=0; i < (len / PAGE_BUFFER_SIZE); i++)                                 // дû
    {
        primask = interrupt_global_disable();
                                                                                // ѭдû
        state = rom_api_flexspi_nor_flash_page_program(flash_instance, &config, sector_num * FLASH_SECTOR_SIZE + page_num * FLASH_PAGE_SIZE + (i * (FLASH_PAGE_SIZE / FLASH_PAGE_NUM_DRIVER)),(uint32 *)(buf+i * PAGE_BUFFER_SIZE));
        interrupt_global_enable(primask);
        if(state != kStatus_Success)
        {
            state = kStatus_Fail;
            break;
        }
    }
    if(0 != len % PAGE_BUFFER_SIZE)                                             // жϳǻС
    {
        memset(block, 0, sizeof(block));                                        // ջ
                                                                                // ûݳֵݴ뻺0
        memcpy(block, (uint32 *)(buf + (i * PAGE_BUFFER_SIZE)), (len - (i * PAGE_BUFFER_SIZE)) * 4);
        primask = interrupt_global_disable();
                                                                                // д뻺
        state = rom_api_flexspi_nor_flash_page_program(flash_instance, &config, sector_num * FLASH_SECTOR_SIZE + page_num * FLASH_PAGE_SIZE + (i * (FLASH_PAGE_SIZE / FLASH_PAGE_NUM_DRIVER)),(uint32 *)block);
        interrupt_global_enable(primask);
        if(state != kStatus_Success)
        {
            state = kStatus_Fail;
        }
    }
    return state;
}

//-------------------------------------------------------------------------------------------------------------------
//      ָ FLASH ָҳȡݵ
// ˵     sector_num      Ҫȡ Χ <0 - 127>
// ˵     page_num        ǰҳı   Χ <FLASH_PAGE_0-FLASH_PAGE_7>
// ز     void
// ʹʾ     flash_read_page_to_buffer(FLASH_SECTION_127, FLASH_PAGE_3);
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
void flash_read_page_to_buffer (uint32 sector_num, flash_page_enum page_num)
{
    DCACHE_CleanInvalidateByRange(FLASH_BASE_ADDR + sector_num * FLASH_SECTOR_SIZE, FLASH_PAGE_SIZE);//ȡflashǰջ
    
    rom_api_flexspi_nor_flash_read(flash_instance, &config, (uint32 *)&flash_union_buffer[0], sector_num * FLASH_SECTOR_SIZE + page_num * FLASH_PAGE_SIZE, FLASH_PAGE_SIZE);
}

//-------------------------------------------------------------------------------------------------------------------
//      ָ FLASH ָҳд뻺
// ˵     sector_num      Ҫд Χ <0 - 127>
// ˵     page_num        ǰҳı   Χ <FLASH_PAGE_0-FLASH_PAGE_7>
// ز     uint8           1-ʾʧ 0-ʾɹ
// ʹʾ     flash_write_page_from_buffer(FLASH_SECTION_127, FLASH_PAGE_3);
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_write_page_from_buffer (uint32 sector_num, flash_page_enum page_num)
{
    uint32 primask;
    status_t state = kStatus_Success;
    primask = interrupt_global_disable();
    flash_write_page(sector_num, page_num, (const uint32 *)&flash_union_buffer[0], FLASH_DATA_BUFFER_SIZE);
    interrupt_global_enable(primask);
    return state;
}

//-------------------------------------------------------------------------------------------------------------------
//      ݻ
// ˵     void
// ز     void
// ʹʾ     flash_buffer_clear();
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
void flash_buffer_clear (void)
{
    memset(flash_union_buffer, 0xFF, FLASH_PAGE_SIZE);
}

//-------------------------------------------------------------------------------------------------------------------
//      flashʼ
// ˵     void
// ز     void
// ʹʾ     flash_init();
// עϢ     
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_init (void)
{
    serial_nor_config_option_t option;
    
    option.option0.U = 0xC0000008; // QuadSPI NOR, Frequency: 133MHz
    
    rom_api_init();
    if(rom_api_flexspi_nor_get_config(flash_instance, &config, &option) !=  kStatus_Success)
    {
        return kStatus_Fail;
    }
    return kStatus_Success;
}
