/*
 *
 * mflash.h - Mellanox Technilogies LTD. Flash access lib heared file
 * ==================================================================
 *
 * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
 * Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *  Version: $Id: $
 *
 */

#ifndef MFLASH_H
#define MFLASH_H

#include <compatibility.h>
#include <mtcr.h>
#include "mflash_types.h"
#include "mflash_common_structs.h"

#include <mlxfwops/uefi_c/mft_uefi_common.h>
 // Timer definitions (needed when polling flash semaphore in windows)
#ifndef __WIN__
#define TIMER_INIT(...)
#define TIMER_STOP(...)
#define TIMER_PRINT(...)
#define TIMER_GET_DIFF(...)
#define TIMER_INIT_AND_START(...)
#define TIMER_STOP_GET_DIFF(...)
#define TIMER_CHECK(...)
#else
#include <windows.h>
#define TIMER_INIT() \
    SYSTEMTIME _start, _end; \
    int _diff_in_sec, _diff_in_ms; \
    (void)_diff_in_sec; \
    (void)_diff_in_ms
#define TIMER_START() \
    GetSystemTime(&_start)
#define TIMER_STOP() \
    GetSystemTime(&_end)
#define TIMER_PRINT(...) \
    _diff_in_sec = _end.wSecond - _start.wSecond; \
    _diff_in_ms = (_end.wMilliseconds - _start.wMilliseconds; \
                   printf(__VA_ARGS__); \
                   printf("it took %d sec %d and ms to run.\n", _diff_in_sec, _diff_in_ms)
#define TIMER_GET_DIFF(diff_in_sec, diff_in_ms) \
    diff_in_sec = _end.wSecond - _start.wSecond; \
    diff_in_ms = _end.wMilliseconds - _start.wMilliseconds
#define TIMER_INIT_AND_START() \
    TIMER_INIT(); \
    TIMER_START()
#define TIMER_STOP_GET_DIFF(diff_in_sec, diff_in_ms) \
    TIMER_STOP(); \
    TIMER_GET_DIFF(diff_in_sec, diff_in_ms)
#define TIMER_CHECK(max_sec, max_ms, action_on_tout) \
    TIMER_STOP(); \
    _diff_in_sec = _end.wSecond - _start.wSecond; \
    _diff_in_ms = _end.wMilliseconds - _start.wMilliseconds; \
    if (_diff_in_sec >= max_sec && _diff_in_ms > max_ms) { \
        action_on_tout; \
    }
#endif

#ifdef __cplusplus
#define EXTERN_C_START extern "C" {
#define EXTERN_C_END   }
#else
#define EXTERN_C_START
#define EXTERN_C_END
#endif

EXTERN_C_START

#ifndef UEFI_BUILD
#define FLASH_ACCESS_DPRINTF(args)        do { char *reacDebug = getenv("FLASH_ACCESS_DEBUG"); \
                                  if (reacDebug != NULL) {  printf("\33[2K\r"); \
                                      printf("[FLASH_ACCESS_DEBUG]: -D- "); printf args; fflush(stdout);} } while (0)
#else
#define FLASH_ACCESS_DPRINTF(...)
#endif

typedef struct gpio_toggle_conf_cx6 {
    u_int32_t lock_addr;
    u_int32_t lock_val;
    u_int32_t functional_enable0_addr;
    u_int32_t functional_enable1_addr;
    u_int32_t mode1_set_addr;
    u_int32_t mode0_set_addr;
    u_int32_t dataset_addr;
} gpio_toggle_conf_cx6;

typedef struct gpio_toggle_conf_cx7 {
    u_int32_t select_synced_data_out_addr;
    u_int32_t fw_control_set_addr;
    u_int32_t hw_data_in_addr;
    u_int32_t fw_output_enable_set_addr;
    u_int32_t fw_data_out_set_addr;
} gpio_toggle_conf_cx7;

typedef enum MfCommandSet {
    CS_INTEL   = 1,
    CS_AMD     = 2,

    MCS_STSPI  = 0x80,  // This is not a "real" CFI command set - it's used as a "Meta" command set number.
    MCS_SSTSPI = 0x81
} MfCommandSet;

/////////////////////////////////////////////
//
// MFLASH INTERFACE FUNCTIONS
//
// Return value:
// All functions returns MfError enum values.
//
/////////////////////////////////////////////

struct mfile_t;


//
// open/close functions:
// This lib is used pretty much like a C file: open it, use and close when done.
//
// mf_open(): Allocates and init the mflash object to be used with the other lib funcs.
//   OUT: pmfl - The opened mflash struct is returned here.
//   IN : dev  - The string name of the crspace device to use.
//
// mf_opend(): Same as mf_open, but uses an already opened crspace device.
//
// mf_open_ignore_lock() :
//   THIS FUNCTION IS NOT SAFE -
//   It ignores the flash semaphore during flash init sequence.
//   Use only after one of the above open() failed because of MFE_SEM_LOCKED
//   and you are absolutely sure that the lock can be overridden (E.G. semaphore
//   remained in locked state due to previous kill of the burning app).
//
// mf_close() : Deallocates mflash resources.
//   Note: User should call mf_close() even if mf_open failed (and the returning mfl is not NULL)
//
int     mf_open(mflash **pmfl, const char *dev, int num_of_banks, flash_params_t *flash_params,
                int ignore_cache_rep_guard);
//int     mf_opend(mflash **pmfl, struct mfile_t *mf, int num_of_banks,  flash_params_t *flash_params,
  //               int ignore_cache_rep_guard);
int     mf_open_adv(mflash **pmfl, const char *dev, int num_of_banks, flash_params_t *flash_params,
                    int ignore_cache_rep_guard, int cx3_fw_access);

int     mf_open_uefi(mflash **pmfl, uefi_Dev_t *uefi_dev, uefi_dev_extra_t *dev_extra);

int     mf_open_ignore_lock(mflash *mfl);
void     mf_close(mflash *mfl);

//
// Flash access functions:
// The data buffer should be pre-allocated by caller. The rest is quite self explanatory. .
//
int     mf_read(mflash *mfl, u_int32_t addr, u_int32_t len, u_int8_t *data, bool verbose);
int     mf_write(mflash *mfl, u_int32_t addr, u_int32_t len, u_int8_t *data);
void    mf_set_cpu_utilization(mflash *mfl, int cpuPercent);
// mf_erase performs an erase on the smallest block
int     mf_erase(mflash *mfl, u_int32_t addr);
// adv erasing
int     mf_erase_64k_sector(mflash *mfl, u_int32_t addr);
int     mf_erase_4k_sector(mflash *mfl, u_int32_t addr);

// swap between erasing 4KB or 64KB chunks (performance optimization)


//
// Crspace access through mflash:
//
int     mf_cr_read(mflash *mfl, u_int32_t cr_addr, u_int32_t *data);
int     mf_cr_write(mflash *mfl, u_int32_t cr_addr, u_int32_t data);

int     mf_update_boot_addr(mflash *mfl, u_int32_t boot_addr);

//
// mf_get_attr(): Returns the flash_attr struct
//
int     mf_get_attr(mflash *mfl, flash_attr *attr);

int     mf_get_jedec_id(mflash *mfl, u_int32_t *jedec_id);

int     mf_set_quad_en(mflash *mfl, u_int8_t quad_en);
int     mf_get_quad_en(mflash *mfl, u_int8_t *quad_en);

int     mf_set_driver_strength(mflash *mfl, u_int8_t driver_strength);
int     mf_get_driver_strength(mflash *mfl, u_int8_t *driver_strength);

int     mf_set_write_protect(mflash *mfl, u_int8_t bank_num, write_protect_info_t *protect_info);
int     mf_get_write_protect(mflash *mfl, u_int8_t bank_num, write_protect_info_t *protect_info);

int     mf_set_dummy_cycles(mflash *mfl, u_int8_t num_of_cycles);
int     mf_get_dummy_cycles(mflash *mfl, u_int8_t *num_of_cycles);

//
// Set/Get for some options.
//
int     mf_set_opt(mflash *mfl, MfOpt opt, int val);
int     mf_get_opt(mflash *mfl, MfOpt opt, int *val);

int     mf_is_fifth_gen(mflash *mfl);

int     mf_enable_hw_access(mflash *mfl, u_int64_t key);
int     mf_disable_hw_access_with_key(mflash *mfl, u_int64_t key);
int     mf_disable_hw_access(mflash *mfl);
int     mf_release_semaphore(mflash *mfl);

// get mfile object
mfile* mf_get_mfile(mflash *mfl);

//
// err code to string translation for printing.
//
const char* mf_err2str(int err_code);

void mf_flash_list(char *flash_list, int flash_arr_size);
int mf_get_write_protect_direct_access(mflash *mfl, u_int8_t bank_num, write_protect_info_t *protect_info);
int mf_set_write_protect_direct_access(mflash *mfl, u_int8_t bank_num, write_protect_info_t *protect_info);
int mf_get_quad_en_direct_access(mflash *mfl, u_int8_t *quad_en_p);
int mf_set_quad_en_direct_access(mflash *mfl, u_int8_t quad_en);
int mf_get_driver_strength_direct_access(mflash *mfl, u_int8_t *driver_strength_p);
int mf_set_driver_strength_direct_access(mflash *mfl, u_int8_t driver_strength);
int mf_get_dummy_cycles_direct_access(mflash *mfl, u_int8_t *dummy_cycles_p);
int mf_set_dummy_cycles_direct_access(mflash *mfl, u_int8_t num_of_cycles);
EXTERN_C_END

#endif // MFLASH_H
