/*
 * Copyright (C) Jan 2013 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.
 */

/*
 * mflash_inband.h
 *
 *  Created on: Jul 6, 2011
 *      Author: mohammad
 */

#ifndef MFLASH_ACCESS_LAYER_H_
#define MFLASH_ACCESS_LAYER_H_

#include <compatibility.h>

#include "mflash_common_structs.h"
#define MAX_FLASH_PROG_SEM_RETRY_CNT 40

#ifdef ESS
#define MREAD4(offs, val)       \
    do                          \
    {                           \
        *val = READ_WORD(offs); \
    } while (0)
#define MWRITE4(offs, val)     \
    do                         \
    {                          \
        WRITE_WORD(offs, val); \
    } while (0)
#else
#define MREAD4(offs, val)                                                                                  \
    do                                                                                                     \
    {                                                                                                      \
        if (mread4(mfl->mf, offs, val) != 4)                                                               \
        {                                                                                                  \
            /*fprintf(stderr, "-E- Cr read (0x%08x) failed: %s(%d)\n", (u_int32_t)(offs), strerror(errno), \
             * (u_int32_t)errno);*/                                                                        \
            return 2;                                                                                      \
        } /*printf("-D- %s:%d mread4: offs = %#x, val = %#x\n", __FUNCTION__, __LINE__, offs, val);*/      \
    } while (0)

#define MWRITE4(offs, val)                                                                                           \
    do                                                                                                               \
    {                                                                                                                \
        if (mwrite4(mfl->mf, offs, val) != 4)                                                                        \
        {                                                                                                            \
            /*fprintf(stderr, "-E- Cr write (0x%08x, 0x%08x) failed: %s(%d)\n", (u_int32_t)(offs), (u_int32_t)(val), \
             * strerror(errno), (u_int32_t)errno);*/                                                                 \
            return 2;                                                                                                \
        } /*printf("-D- %s:%d mwrite4: offs = %#x, val = %#x\n",   __FUNCTION__, __LINE__, offs, val);*/             \
    } while (0)
#endif

enum FlashConstant
{
    // All time values are in usecs
    WRITE_BLOCK_INIT_DELAY = 10,
    WRITE_ADDITIONAL_BYTE_DELAY = 1,
    WRITE_BLOCK_RETRY_DELAY = 10,
    WRITE_BLOCK_RETRIES = 30000,

    ERASE_SUBSECTOR_INIT_DELAY = 20000,
    ERASE_SUBSECTOR_RETRY_DELAY = 300,
    ERASE_SUBSECTOR_RETRIES = 10000,

    FLASH_CMD_CNT = 5000, // Number of reads till flash cmd is zeroed

    GPIO_SEM_TRIES = 1024, // Number of tries to obtain a GPIO sem.

    MAX_WRITE_BUFFER_SIZE = 256, // Max buffer size for buffer write devices

    WRITE_STATUS_REGISTER_DELAY_CYPRESS = 750,
    WRITE_STATUS_REGISTER_DELAY_MICRON = 1000,
    WRITE_STATUS_REGISTER_DELAY_MIN = 40,

    DUMMY_CYCLES_OFFSET_ST = 12,

    QUAD_EN_OFFSET_WINBOND_CYPRESS = 1,
    QUAD_EN_OFFSET_MICRON = 3,
    QUAD_EN_OFFSET_ISSI_MACRONIX = 6,
    QUAD_EN_OFFSET_GIGABYTE = 1,
    DRIVER_STRENGTH_OFFSET_WINBOND = 5,
    DRIVER_STRENGTH_BIT_LEN_WINBOND = 2,
    DRIVER_STRENGTH_VAL_100_WINBOND = 0,
    DRIVER_STRENGTH_VAL_75_WINBOND = 1,
    DRIVER_STRENGTH_VAL_50_WINBOND = 2,
    DRIVER_STRENGTH_VAL_25_WINBOND = 3,
    TB_OFFSET_MACRONIX = 3,
    SEC_OFFSET = 6,
    TB_OFFSET = 5,
    TB_OFFSET_ISSI = 1,
    TB_OFFSET_CYPRESS_WINBOND_256 = 6,
    BP_OFFSET = 2,
    BP_4TH_BIT_OFFSET_MICRON = 6,
    BP_SIZE = 3,
    PROTECT_BITS_SIZE = 5
};
//
// Relevant CR addresses, Bit offset and bit size
//

enum CrConstans
{
    CR_FLASH_ADDR_7NM = 0xf0420,
    // CR_FLASH_DATA = 0xf0408,
    CR_FLASH_CS = 0xf0418,
    CR_GPIO_LOCK = 0xf00ec,
    BO_READ_OP = 0,
    BO_ADDR_INCR = 1,
    BO_LPC_STOP = 3,
    BO_SPI_NO_DATA = 4,
    BO_SPI_NO_ADDR = 5,
    BO_SPI_SPECIAL = 6,
    BO_STATUS = 26,
    BS_STATUS = 4,
    BO_BUSY = 30,
    BO_SPI_ADDR = 0,
    BS_SPI_ADDR = 24,
    BO_SPI_CMD = 24,
    BS_SPI_CMD = 8,
    BO_SPI_GPIO = 25,
    BS_SPI_GPIO = 4
};

int check_access_type(mflash* mfl);
int sx_get_flash_info_by_type(mflash* mfl, flash_info_t* type_index, int* log2size, u_int8_t* no_flash);
int sx_block_read_by_type(mflash* mfl, u_int32_t blk_addr, u_int32_t blk_size, u_int8_t* data);
int sx_block_write_by_type(mflash* mfl, u_int32_t addr, u_int32_t size, u_int8_t* data);
int sx_flash_lock_by_type(mflash* mfl, int lock_state);
int sx_erase_sect_by_type(mflash* mfl, u_int32_t addr, u_int32_t erase_size);
int mf_update_boot_addr_by_type(mflash* mfl, u_int32_t boot_addr);
int mfl_com_lock(mflash* mfl);
flash_access_commands_t gen_4byte_address_access_commands();
flash_access_commands_t gen_3byte_address_access_commands();
int release_semaphore(mflash* mfl, int ignore_writer_lock);
int sx_set_quad_en(mflash* mfl, u_int8_t quad_en);
int sx_get_quad_en(mflash* mfl, u_int8_t* quad_en);
int sx_set_driver_strength(mflash* mfl, u_int8_t driver_strength);
int sx_get_driver_strength(mflash* mfl, u_int8_t* driver_strength);
int sx_set_write_protect(mflash* mfl, u_int8_t bank_num, write_protect_info_t* protect_info);
int sx_get_write_protect(mflash* mfl, u_int8_t bank_num, write_protect_info_t* protect_info);
int sx_set_dummy_cycles(mflash* mfl, u_int8_t num_of_cycles);
int sx_get_dummy_cycles(mflash* mfl, u_int8_t* num_of_cycles);
int gw_wait_ready(mflash* mfl, const char* msg);

#endif /* MFLASH_ACCESS_LAYER_H_ */
