/*
 * @file exo_ahw_vdp_mt25ql512.c
 *
 * @brief This file contains the vendor driver porting function of mt25ql512_ flash memory
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "exo_ahw_vdp_mt25ql512.h"
#include "mt25ql512.h"
#include "exo_osal_mem_management.h"
#include "exo_common.h"
 // memory offset allocated for qspi flash memory in linker
#define MT25QL512_MEMORY_MAP_ADDR 0x90000000
#define MT25QL512_MEMORY_END_ADDR MT25QL512_MEMORY_MAP_ADDR+MEMORY_FLASH_SIZE

/**
 * @brief Ahw_io mapping with the Ahw_io_lookup_table
 */
extern ahw_io_map *ahw_io_lookup_tble[MAX_AH_INST_ID];

/**
 * @brief  Ahw Instance handle pointer.
 *
 */
extern void *intf_inst_hdle_ptr[MAX_IO_INST_ID];



/**
 * @brief Wrapper API to initializes the mt25ql512_ memory chip
 *
 */
hal_ret_sts	ahw_al_vdp_mt25ql512_init(ahw_al_ext_mem_hdl *al_em_h)
{
    hal_ret_sts sts = HAL_SCS;
    mt25ql512_dev_t* vdh_mem = (mt25ql512_dev_t*)os_malloc(sizeof(mt25ql512_dev_t));

    /* IO interface for MX25L will be determined based on AHW lookup table which is a configurable table
     * updated in ahw_io_lookup_table_updt()
     */
    vdh_mem->io_intf_hdle = intf_inst_hdle_ptr[ahw_io_lookup_tble[al_em_h->ahw_gen_info.ahw_inst_id]->io_instance_id];

    /* update io interface & vdp handle */
    al_em_h->ahw_gen_info.vdp_inst_hdle = (void*)vdh_mem;
    al_em_h->ahw_gen_info.io_intf_hdle=vdh_mem->io_intf_hdle;
    al_em_h->erase_mode = ERASE_BY_SECTOR;
    al_em_h->flash_size = MEMORY_FLASH_SIZE;

    if(HAL_SCS == (hal_ret_sts)mt25ql512_init(vdh_mem))
    {
        sts = HAL_SCS;
    }
    else
    {
        sts = HAL_AH_DRIVER_ERR;
    }

#ifdef LINUX_TEMP_PORT
    sts = HAL_SCS;
#endif
    return sts;
}





/**
 * @brief Wrapper API to de initializes mt25ql512_ memory chip
 */
hal_ret_sts	ahw_al_vdp_mt25ql512_deinit(ahw_al_ext_mem_hdl *al_em_h)
{
    hal_ret_sts sts = HAL_SCS;

    // TODO : De initialize needs to be done

#ifdef LINUX_TEMP_PORT
    sts = HAL_SCS;
#endif
    return sts;
}




/**
 * @brief Wrapper API to write data into mt25ql512_ memory chip
 *
 */
hal_ret_sts ahw_vdp_mt25ql512_write(ahw_al_ext_mem_hdl *al_em_h, uint32_t address, uint8_t *data, uint32_t size)
{
    hal_ret_sts sts;
    mt25ql512_dev_t vdh_mem;
    uint32_t end_add;
    vdh_mem.io_intf_hdle = al_em_h->ahw_gen_info.io_intf_hdle;

    end_add = address + size;
    if(address >= MT25QL512_MEMORY_MAP_ADDR && end_add <= MT25QL512_MEMORY_END_ADDR )
    {
    	address -= MT25QL512_MEMORY_MAP_ADDR;
        if(HAL_SCS == (hal_ret_sts)mt25ql512_write(&vdh_mem, data, address, size))
        {
            sts = HAL_SCS;
        }
        else
        {
            sts = HAL_AH_DRIVER_ERR;
        }
    }
    else
    {
    	/* input address is not in range */
        sts = HAL_AH_DRIVER_ERR;
    }


    return sts;
}


/**
 * @brief Wrapper API to read data from mt25ql512_ memory chip
 *
 */
hal_ret_sts ahw_vdp_mt25ql512_read(ahw_al_ext_mem_hdl *al_em_h, uint32_t address, uint8_t *data, uint32_t size)
{
    hal_ret_sts sts;
    mt25ql512_dev_t vdh_mem;
    vdh_mem.io_intf_hdle = al_em_h->ahw_gen_info.io_intf_hdle;
	address -= MT25QL512_MEMORY_MAP_ADDR;
    if(HAL_SCS == (hal_ret_sts)mt25ql512_read(&vdh_mem, data, address, size))
    {
        sts = HAL_SCS;
    }
    else
    {
        sts = HAL_AH_DRIVER_ERR;
    }
    return sts;
}



/**
 * @brief Wrapper API to erase memory of mt25ql512_ memory chip
 *
 */
hal_ret_sts ahw_vdp_mt25ql512_erase(ahw_al_ext_mem_hdl *al_em_h, uint32_t start_address, uint32_t end_address)
{
    hal_ret_sts sts;
    mt25ql512_dev_t vdh_mem;
    vdh_mem.io_intf_hdle = al_em_h->ahw_gen_info.io_intf_hdle;

    start_address -= MT25QL512_MEMORY_MAP_ADDR;
    end_address -= MT25QL512_MEMORY_MAP_ADDR;
    // TODO : here erase mode has been skipped in mt25ql12 chip but it was enabled in mx25l512
    if(HAL_SCS == (hal_ret_sts)mt25ql512_EraseSector(&vdh_mem, start_address, end_address))
    {
        sts = HAL_SCS;
    }
    else
    {
        sts = HAL_AH_DRIVER_ERR;
    }
    return sts;
}



/**
 * @brief Mapping API to enable memory mapped mode for mt25ql512_ memory chip
 *
 */
hal_ret_sts ahw_vdp_mt25ql512_memmap_enable(ahw_al_ext_mem_hdl *al_em_h)
{
    hal_ret_sts sts;
    mt25ql512_dev_t vdh_mem;
    vdh_mem.io_intf_hdle = al_em_h->ahw_gen_info.io_intf_hdle;
    if(HAL_SCS == (hal_ret_sts)mt25ql512_EnableMemoryMappedMode(&vdh_mem))
    {
        sts = HAL_SCS;
    }
    else
    {
        sts = HAL_AH_DRIVER_ERR;
    }
    return sts;
}

hal_ret_sts	ahw_al_vdp_mt25ql512_reinit(ahw_al_ext_mem_hdl *al_em_h)
{
	hal_ret_sts sts = 0;
	mt25ql512_dev_t vdh_mem;
	vdh_mem.io_intf_hdle = al_em_h->ahw_gen_info.io_intf_hdle;
	if(HAL_SCS == (hal_ret_sts)mt25ql512_init(&vdh_mem))
	    {
	        sts = HAL_SCS;
	    }
	    else
	    {
	        sts = HAL_AH_DRIVER_ERR;
	    }
	    return sts;
}

