/*
 * All Rights Reserved (C) 2021-2025
 * Exoligent SARL (Colombes, France)
 * Website: www.exoligent.com
 * Author : Maxime Coroyer <maxime.coroyer@exoligent.com>
 */

#ifndef __POWERFIP_DRV_H__
#define __POWERFIP_DRV_H__

#if defined (__linux__)
#   include <asm/types.h>
#   include <linux/types.h>
#elif defined (_WIN32) || defined (_WIN64)
#   ifdef PWRFIP_WIN_DRV
#       include <ntddk.h>
#       define uint8_t UCHAR
#       define uint16_t USHORT
#       define uint32_t ULONG
#       define uint64_t ULONGLONG
#   else
#       include <windows.h>
#       include <winioctl.h>
#       include <stdint.h>
#   endif
#endif

#include "powerfip-mbox-common.h"
#include "powerfip-common.h"

#define MAX_FA_BOARD 16
#define BAR_MAX 6
#define BAR_BOARD 0
#define BAR_PWRFIP 1

//**** OFFSETS (BAR0)
/* resource register */
#define RES_REG 0x58u
/* sensor register */
#define SNSR_REG 0x64u
/* factory serial number */
#define FSN_LO_REG 0x68u
#define FSN_HI_REG 0x6Cu
/* dma registers */
#define DMA_AREA_PCI_OFFSET 0x400u
#define DMA_WSZ 0x10u
#define DMA_BSZ ((DMA_WSZ) * 4)
#define DMA_BASE_ADDR(x) ((x) * (DMA_BSZ))
#define DMA_SRC_PARAM_REG(x) (DMA_BASE_ADDR(x))
#define DMA_DST_PARAM_REG(x) ((DMA_BASE_ADDR(x)) + (0x04u))
#define DMA_SRC_ADDR_LO_REG(x) ((DMA_BASE_ADDR(x)) + (0x08u))
#define DMA_SRC_ADDR_HI_REG(x) ((DMA_BASE_ADDR(x)) + (0x0Cu))
#define DMA_DST_ADDR_LO_REG(x) ((DMA_BASE_ADDR(x)) + (0x10u))
#define DMA_DST_ADDR_HI_REG(x) ((DMA_BASE_ADDR(x)) + (0x14u))
#define DMA_LEN_REG(x) ((DMA_BASE_ADDR(x)) + (0x18u))
#define DMA_CTRL_REG(x) ((DMA_BASE_ADDR(x)) + (0x1Cu))
#define DMA_STA_REG(x) ((DMA_BASE_ADDR(x)) + (0x20u))
#define DMA_PRC_LEN_REG(x) ((DMA_BASE_ADDR(x)) + (0x24u))
#define DMA_SHR_ACC_REG(x) ((DMA_BASE_ADDR(x)) + (0x28u))
#define DMA_OP_R 0 /* read dma operation */
#define DMA_OP_W 1 /* write dma operation */
#define DMA_TMO_US 200000 /* dma timeout in us */
#define DMA_BUFFER_BSZ (1u << 20) /* 1MB */
/* msi registers */
#define MSI_ADDR_LO_REG 0x500u
#define MSI_ADDR_HI_REG 0x504u

/**
 * RES_REG register: MASK & SHIFT
 */
/* dma capacity */
#define RES_DMA_MASK    0x01u
#define RES_DMA_SHIFT   19u
/* magic number */
#define RES_MAG_NUM     0x57
#define RES_MAG_MASK    0xFFu
#define RES_MAG_SHIFT   24u

enum pwrfip_reg_res {
    RES_DMA = ((RES_DMA_MASK) << (RES_DMA_SHIFT)),
};

/**
 * DMA_SRC_PARAM_REG register: MASK & SHIFT
 */
/* dma read operation (vs write) */
#define DMA_SRC_PARAM_OP_R_MASK     0x01u
#define DMA_SRC_PARAM_OP_R_SHIFT    0u

enum pwrfip_reg_dma_src_param {
    DMA_SRC_PARAM_OP_R = ((DMA_SRC_PARAM_OP_R_MASK) << (DMA_SRC_PARAM_OP_R_SHIFT)),
};

/**
 * DMA_CTRL_REG register: MASK & SHIFT
 */
/* start/abort dma operation */
#define DMA_CTRL_OP_STRT_ABRT_MASK  0x01u
#define DMA_CTRL_OP_STRT_ABRT_SHIFT 0u

enum pwrfip_reg_dma_ctrl {
    DMA_CTRL_OP_STRT_ABRT = ((DMA_CTRL_OP_STRT_ABRT_MASK) << (DMA_CTRL_OP_STRT_ABRT_SHIFT)),
};

/**
 * DMA_STA_REG register: MASK & SHIFT
 */
/* dma completion ok */
#define DMA_STA_COMPL_OK_MASK   0x01u
#define DMA_STA_COMPL_OK_SHIFT  0u
/* dma completion with error */
#define DMA_STA_COMPL_ERR_MASK  0x01u
#define DMA_STA_COMPL_ERR_SHIFT 3u
/* dma watchdog error */
#define DMA_STA_ERR_WDT_MASK    0x01u
#define DMA_STA_ERR_WDT_SHIFT   5u
/* dma stopped by user */
#define DMA_STA_ERR_USR_MASK    0x01u
#define DMA_STA_ERR_USR_SHIFT   6u
/* dma buffer error */
#define DMA_STA_ERR_END_MASK    0x01u
#define DMA_STA_ERR_END_SHIFT   7u

enum pwrfip_reg_dma_sta {
    DMA_STA_COMPL_OK = ((DMA_STA_COMPL_OK_MASK) << (DMA_STA_COMPL_OK_SHIFT)),
    DMA_STA_COMPL_ERR = ((DMA_STA_COMPL_ERR_MASK) << (DMA_STA_COMPL_ERR_SHIFT)),
    DMA_STA_ERR_WDT = ((DMA_STA_ERR_WDT_MASK) << (DMA_STA_ERR_WDT_SHIFT)),
    DMA_STA_ERR_USR = ((DMA_STA_ERR_USR_MASK) << (DMA_STA_ERR_USR_SHIFT)),
    DMA_STA_ERR_END = ((DMA_STA_ERR_END_MASK) << (DMA_STA_ERR_END_SHIFT)),
};

//**** OFFSETS (BAR1)
/* global control register */
#define PWRFIP_GCTL_REG 0x4u
/* mbox area */
#define PWRFIP_DPM_AREA_PCI_OFFSET  0x1000u
/* sram area */
#define PWRFIP_SRAM_AREA_PCI_OFFSET 0x01000000u

/* Subsystem Device ID (SSDID) */
enum pwrfip_ssdid {
    /* copper physical layer */
    PWRFIP_SSDID_PCI_COP = 0x5211,
    PWRFIP_SSDID_PCIE_COP = 0x5311,
    PWRFIP_SSDID_PCI104_COP = 0x5411,
    PWRFIP_SSDID_PCIE104_COP = 0x5511,
    PWRFIP_SSDID_PXI_COP = 0x5611,
    PWRFIP_SSDID_PXIE_COP = 0x5711,
    PWRFIP_SSDID_MPCIE_COP = 0x5811,
    PWRFIP_SSDID_CPCI_COP = 0x5911,
    /* optical physical layer */
    PWRFIP_SSDID_PCI_OPT = 0x7211,
    PWRFIP_SSDID_PCIE_OPT = 0x7311,
    PWRFIP_SSDID_PCI104_OPT = 0x7411,
    PWRFIP_SSDID_PCIE104_OPT = 0x7511,
    PWRFIP_SSDID_PXI_OPT = 0x7611,
    PWRFIP_SSDID_PXIE_OPT = 0x7711,
    PWRFIP_SSDID_MPCIE_OPT = 0x7811,
    PWRFIP_SSDID_CPCI_OPT = 0x7911,
};

enum pwrfip_board_format {
    _PWRFIP_BOARD_MIN = 2,
    PWRFIP_BOARD_PCI = _PWRFIP_BOARD_MIN,
    PWRFIP_BOARD_PCIE = 3,
    PWRFIP_BOARD_PCI104 = 4,
    PWRFIP_BOARD_PCIE104 = 5,
    PWRFIP_BOARD_PXI = 6,
    PWRFIP_BOARD_PXIE = 7,
    PWRFIP_BOARD_MPCIE = 8,
    PWRFIP_BOARD_CPCI = 9,
    _PWRFIP_BOARD_MAX,
};

#pragma pack(1) // 1 byte alignment
struct pwrfip_dev_irq {
    uint32_t src; /**< irq source event (see enum pwrfip_irq_flags) */
    uint64_t cnt;
    /* extras: used for synchronous events */
    struct pwrfip_event evt;
};

struct pwrfip_dev_infos {
    uint32_t    index;
    uint64_t    fsn; /**< factory serial number */
    /* device general info */
    uint16_t    vid;
    uint16_t    did;
    uint16_t    ssvid;
    uint16_t    ssdid;
    /* physical BAR addresses */
    int         bar_cnt; /**< number of BAR for this device */
    uint64_t    bar_bsz[BAR_MAX]; /**< size of the BAR area */
    uint64_t    bar_base[BAR_MAX]; /**< memory BAR (start phy address) */
    /* irq infos */
    int         irq_number;
    /* driver infos */
    uint32_t    drv_version; /**< driver version */
    uint32_t    drv_date; /**< driver build date */
};

struct pwrfip_dev_sensors {
    uint32_t value[10];
};

struct pwrfip_dev_report {
    float temperature;
};

struct pwrfip_dev_rw_data {
    int bar_num;
    uint64_t bar_off;
    uint64_t data_ptr;
    uint32_t data_wsz;
    uint32_t data_max_wsz;
};
#define PWRFIP_DEV_RW_DATA_BSZ (sizeof(struct pwrfip_dev_rw_data))

struct pwrfip_dev_mbox_info {
    int num; /* mbox index */
    int type; /* MBOX_IN, MBOX_OUT */
    uint32_t min_pkt_wsz; /* maximum packet data size */
    uint32_t max_pkt_wsz; /* minimum packet data size */
    uint32_t config_init; /* initial config register value */
};
#define PWRFIP_DEV_MBOX_INFO_BSZ (sizeof(struct pwrfip_dev_mbox_info))

#if defined (_WIN32) || defined (_WIN64)
struct pwrfip_dev_remap_infos {
    int remap_cnt;
    uint64_t remap[BAR_MAX];
};
#elif defined (__linux__)
struct arg_io {
    uint64_t i_ptr;
    uint64_t o_ptr;
    uint32_t i_bsz;
    uint32_t o_bsz;
    uint32_t status;
};
#endif

struct pwrfip_dev_mbox_req_hdr {
    uint32_t tmo_ms; /* mbox timeout in ms */
    uint32_t it_cap; /* mbox it capability */
    uint32_t data_bsz;
};
#define PWRFIP_DEV_MBOX_REQ_HDR_BSZ (sizeof(struct pwrfip_dev_mbox_req_hdr))

struct pwrfip_dev_mbox_req {
    struct pwrfip_dev_mbox_req_hdr hdr;
    uint32_t data[MBOX_WSZ];
};

struct pwrfip_dev_mbox_rep_hdr {
    uint32_t status; /* mbox status register */
    uint32_t reserved;
    uint32_t data_bsz;
};
#define PWRFIP_DEV_MBOX_REP_HDR_BSZ (sizeof(struct pwrfip_dev_mbox_rep_hdr))

struct pwrfip_dev_mbox_rep {
    struct pwrfip_dev_mbox_rep_hdr hdr;
    uint32_t data[MBOX_WSZ];
};

#pragma pack()

enum pwrfip_ioctl_cmd {
#if defined (_WIN32) || defined (_WIN64)
    PWRFIP_INFO_GET = 0x801,
    PWRFIP_MMAP,
    PWRFIP_MUNMAP,
#else
    PWRFIP_INFO_GET,
#endif
    PWRFIP_SNSRS_GET,
    PWRFIP_FW_LOAD,
    PWRFIP_MBOX_INIT,
    PWRFIP_MBOX_EXIT,
    PWRFIP_POST_N_WAIT_ACK,
    PWRFIP_POST_N_WAIT_RES,
    PWRFIP_RESET,
    PWRFIP_IRQ_WAIT_FOR,
    PWRFIP_IRQ_RESUME,
};

#if defined (_WIN32) || defined (_WIN64)
#   define C_FIP_TYPE 0x8CAF
#   define PWRFIP_IOCTL_INFO_GET CTL_CODE(C_FIP_TYPE, PWRFIP_INFO_GET, METHOD_BUFFERED, FILE_READ_ACCESS)
#   define PWRFIP_IOCTL_MMAP CTL_CODE(C_FIP_TYPE, PWRFIP_MMAP, METHOD_BUFFERED, FILE_READ_ACCESS)
#   define PWRFIP_IOCTL_MUNMAP CTL_CODE(C_FIP_TYPE, PWRFIP_MUNMAP, METHOD_BUFFERED, FILE_ANY_ACCESS)
#   define PWRFIP_IOCTL_SNSRS_GET CTL_CODE(C_FIP_TYPE, PWRFIP_SNSRS_GET, METHOD_BUFFERED, FILE_READ_ACCESS)
#   define PWRFIP_IOCTL_FW_LOAD CTL_CODE(C_FIP_TYPE, PWRFIP_FW_LOAD, METHOD_BUFFERED, FILE_ANY_ACCESS)
#   define PWRFIP_IOCTL_MBOX_INIT CTL_CODE(C_FIP_TYPE, PWRFIP_MBOX_INIT, METHOD_BUFFERED, FILE_ANY_ACCESS)
#   define PWRFIP_IOCTL_MBOX_EXIT CTL_CODE(C_FIP_TYPE, PWRFIP_MBOX_EXIT, METHOD_BUFFERED, FILE_ANY_ACCESS)
#   define PWRFIP_IOCTL_POST_N_WAIT_ACK CTL_CODE(C_FIP_TYPE, PWRFIP_POST_N_WAIT_ACK, METHOD_BUFFERED, FILE_ANY_ACCESS)
#   define PWRFIP_IOCTL_POST_N_WAIT_RES CTL_CODE(C_FIP_TYPE, PWRFIP_POST_N_WAIT_RES, METHOD_BUFFERED, FILE_ANY_ACCESS)
#   define PWRFIP_IOCTL_RESET CTL_CODE(C_FIP_TYPE, PWRFIP_RESET, METHOD_BUFFERED, FILE_ANY_ACCESS)
#   define PWRFIP_IOCTL_IRQ_WAIT_FOR CTL_CODE(C_FIP_TYPE, PWRFIP_IRQ_WAIT_FOR, METHOD_BUFFERED, FILE_READ_ACCESS)
#   define PWRFIP_IOCTL_IRQ_RESUME CTL_CODE(C_FIP_TYPE, PWRFIP_IRQ_RESUME, METHOD_BUFFERED, FILE_ANY_ACCESS)
#elif defined (__linux__)
#   define PWRFIP_IOCTL_MAGIC 0xFF
#   define PWRFIP_IOCTL_INFO_GET _IOR(PWRFIP_IOCTL_MAGIC, PWRFIP_INFO_GET, struct pwrfip_dev_infos)
#   define PWRFIP_IOCTL_SNSRS_GET _IOR(PWRFIP_IOCTL_MAGIC, PWRFIP_SNSRS_GET, struct pwrfip_dev_sensors)
#   define PWRFIP_IOCTL_FW_LOAD _IOWR(PWRFIP_IOCTL_MAGIC, PWRFIP_FW_LOAD, struct arg_io)
#   define PWRFIP_IOCTL_MBOX_INIT _IOWR(PWRFIP_IOCTL_MAGIC, PWRFIP_MBOX_INIT, struct arg_io)
#   define PWRFIP_IOCTL_MBOX_EXIT _IOWR(PWRFIP_IOCTL_MAGIC, PWRFIP_MBOX_EXIT, struct arg_io)
#   define PWRFIP_IOCTL_POST_N_WAIT_ACK _IOWR(PWRFIP_IOCTL_MAGIC, PWRFIP_POST_N_WAIT_ACK, struct arg_io)
#   define PWRFIP_IOCTL_POST_N_WAIT_RES _IOWR(PWRFIP_IOCTL_MAGIC, PWRFIP_POST_N_WAIT_RES, struct arg_io)
#   define PWRFIP_IOCTL_RESET _IO(PWRFIP_IOCTL_MAGIC, PWRFIP_RESET)
#   define PWRFIP_IOCTL_IRQ_WAIT_FOR _IOR(PWRFIP_IOCTL_MAGIC, PWRFIP_IRQ_WAIT_FOR, struct pwrfip_dev_irq)
#   define PWRFIP_IOCTL_IRQ_RESUME _IO(PWRFIP_IOCTL_MAGIC, PWRFIP_IRQ_RESUME)
#endif

#endif // __POWERFIP_DRV_H__
