#ifndef _SONY_FPGA_H_
#define _SONY_FPGA_H_

/**
 * @file sony_fpga.h
 * @brief sony_fpga定義
 */
#include <nv-p2p.h>
#include <linux/io.h>
#include "sony_fpga_cmd.h"

#define SONY_FPGA_DRIVER_NAME "sony_fpga"
#define SONY_FPGA_DEVFILE     "sony_fpga"

#define SONY_FPGA_DRIVER_VERSION "2.40_7"

#define SONY_FPGA_DID_ULM   (0x0000)
#define SONY_FPGA_DID_VIDEO (0x0001)
#define SONY_FPGA_DID_NEM   (0x0002)
#define SONY_FPGA_DID_BIM   (0x0003)
#define SONY_FPGA_DID_XPT   (0x0004)
#define SONY_FPGA_DID_SIS   (0x0005)
#ifndef SONY_FPGA_VID
#define SONY_FPGA_VID (0x104D)
#endif

#define NUM_BARS              (6)
#define FPGA_CTRL_BAR         (0)
#define FPGA_BAR1             (1)
#define FPGA_BAR2             (2)
#define FPGA_BAR5             (5)
#define FPGA_BAR0_SIZE        (0x00008000)  /* 32KB */

#define DATE_2_YEAR(x)     (x >> 16)
#define DATE_2_MONTH(x)    ((x >> 8) & 0xff)
#define DATE_2_DAY(x)      (x & 0xff)

#define FPGA_TYPE(x)       ((((x >> 4) & 0xf) == 0) ? "4K" : (((x >> 4) & 0xf) == 2) ? "720" : "HD")
#define IS_NEW_XPT_BOARD(x)  (((x >> 12) & 0xf) > 1)
#define BOARD_REVISION(x)  ((x >> 12) & 0xf)
#define IS_GIF_VIDEO(ctrl) (ctrl->pci_dev->device == SONY_FPGA_DID_VIDEO)

#define BOARD_TYPE(x)      ((x >> 8) & 0xf)
#define DEV_ID(x)      ((x >> 4) & 0xf)
#define SLOT_ID(x)         (x & 0xf)

#define BOARD_TYPE_VIF81   0x4
#define BOARD_TYPE_VIF81B  0xa
#define BOARD_TYPE_VIF81A  0x6
#define BOARD_TYPE_VPR149  0x3
#define BOARD_TYPE_NET53   0x2
#define BOARD_TYPE_XPT42   0x5
#define BOARD_TYPE_IO293   0x7

#define PROCESS_STATUS_SIZE 128
enum {
    FPGA_KIND_GIF = 0,
    FPGA_KIND_SWR,
    FPGA_KIND_SDI,
    FPGA_KIND_NEM,
    FPGA_KIND_BIM,
    FPGA_KIND_XPT,
    FPGA_KIND_GIF2,
    FPGA_KIND_SIS,
    FPGA_KIND_MAX
};
#define FPGA_KIND(x)       (x & 0b1111)

enum {
    FPGA_MODE_4K = 0,
    FPGA_MODE_HD,
    FPGA_MODE_720,
    FPGA_MODE_MAX
};
#define FPGA_MODE(x)       ((x >> 4) & 0b1111)

#define FPGA_PRODUCT_CODE(x)       ((x >> 8) & 0xff)

/* 4K YCbCrK 4:2:2:4 10bit 1 frame   4096x2160x20/8   => 5400*PAGE_SIZE */
/* 4K YCbCrK 4:2:2:4 10bit 1 strip   4096x2160x20/8/4 => 1350*PAGE_SIZE */
/* 3G YCbCrK 4:2:2:4 10bit 1 strip   1920x1080x20/8/4 => 317*PAGE_SIZE */
/* descriptor一枚が16byteなので 1350毎で6(5.3) ページ */
/* descriptor一枚が16byteなので 317毎で2(1.2) ページ */
#define NUM_VIDEO_DESCRIPTOR_PAGES_4K  (432) /* 4strips * 2(R/W) * 9ch分取っておく */

#define NUM_DESCRIPTOR_PAGES (4) /* TODO FM用未定 */
#ifndef FPGA_LAST_PAGE
#define FPGA_LAST_PAGE 255
#endif

#define CONFIG_DATA_BLOCK_SIZE  (64*1024)

enum {
    SDI_TYPE_SD = 0,
    SDI_TYPE_HD,
    SDI_TYPE_3GA,
    SDI_TYPE_3GB,
    SDI_TYPE_6G,
    SDI_TYPE_12G
};

enum {
    CTRL_DMAC_WRITE_NORMAL,
    CTRL_DMAC_WRITE_COMPARE,
    CTRL_DMAC_WRITE_INTEL,
    CTRL_DMAC_WRITE_MAX,
};

//TODO 折り返しで試験していた時代の名残。
#ifndef TARGET_MEM_LAST_PAGE
#define TARGET_MEM_LAST_PAGE 127 //(NUM_KERNEL_MEM_PAGES-1)
#endif

#define REGISTER_BUFFER_PAGES (256*1024/PAGE_SIZE+1)

/// Write DMA (Status Read)領域のページ数
#define CTRL_DMAC_WRITE_DMA_PAGES (4)
extern void* register_buffer;
extern dma_addr_t register_bus_addr;
extern struct pci_dev* alloc_pcidev;

// for submodule
extern struct ctrl_dmac_ignore_mng ignore_list;
extern u32* process_status_area;
extern u32* process_status_area_xpt;
extern struct attribute_group attr_group;
extern struct file_operations sony_fpga_fops;
extern int module_param_video_format_wait;
extern int module_param_ctrl_dmac_debug_enable;

extern const u32 CTRL_DMAC_WRITE_SIZE[CTRL_DMAC_WRITE_MAX][FPGA_KIND_MAX];
extern ulong module_param_board_revision;
extern ulong module_param_gif1_busno;
extern u32 vd_counter;

struct dma_desc {
    u8  terminator;
    u8  reserved[3];
    u32 local_addr;
    u64 pcie_addr;
} __attribute__ ((packed));

typedef struct version_info_t {
    u8 debug_version;
    u8 minor_version;
    u8 major_version;
    u8 res;
} version_info;

typedef struct cpu_descriptor_addr_t {
    u32 addr_l;
    u32 addr_u;
} cpu_descriptor_addr;

enum {
    VD_0 = 0,
    VD_1,
    VD_2,
    VD_3,
    VD_NUM
};

enum {
    DMAC_CH1 = 0,
    DMAC_CH2,
    DMAC_CH3,
    DMAC_CH4,
    DMAC_CH_NUM
};

enum {
    DIRECTION_WRITE = 0,
    DIRECTION_READ,
    DIRECTION_NUM
};

typedef struct dmac_file_register_t {
    u32 module_version;
    u32 module_date;
    u32 module_ctrl;
    u32 module_status;
    u32 header1;
    u32 header2;
    u32 header3;
    u32 memory_write;
    u32 memory_read;
    u32 memory_write_next;
    u32 reserved[(0x30-0x28) / 4];
    u32 file_install;
    u32 file_target;
    u32 file_block;
    u32 checksum;
    u32 status_clear;
    u32 reserved2[(0x200-0x44) / 4];
} dmac_file_register;

typedef struct dmac_media_register_t {
    u32 dma_type;
    u32 dma_disable;

    u8 res[0x100-8];

    cpu_descriptor_addr desc_addr[DMAC_CH_NUM][DIRECTION_NUM][VD_NUM];
} dmac_media_register;

struct desc_set {
    struct dma_desc* start_ptr;
    u32 cnt;
};

enum {
    DMA_PORT_YC1 = 0,
    DMA_PORT_K1,
    DMA_PORT_YC2,
    DMA_PORT_K2,
    DMA_PORT_YC3,
    DMA_PORT_YC4,
    DMA_PORT_YC5,
    DMA_PORT_YC6,
    DMA_PORT_YC7,
    DMA_PORT_NUM
};

#ifdef SIGNAL_SELECT_4K
enum {
    GPU_ASSIGN_DME = 0,
    GPU_ASSIGN_SLK,
    GPU_ASSIGN_SHARE
};
#endif

/* FPGA Register */
struct sony_fpga_register {

    version_info pcie_version;
    u32 pcie_date;

    u8 res1[0x80 - 8];
    version_info fpga_version;
    u32 fpga_date;
    u32 fpga_uniq_id;
    u32 video_format;
    u32 com_e_init;
    u32 system_reset;
    u32 irq_ref_lock;
    u32 gpu_exist;
    u32 irq_enable_1;
    u32 irq_enable_2;
    u32 irq_enable_3;
    u32 irq_nios;
    u32 multipurpose;
    u32 clk_pll_lock_status;
    u8 res2[0xc0 - 0xb8];
    u32 memory_status;
    u32 memory_reset;
    u32 sdi_init;
    u8 res3[0xd0 - 0xcc];
    u32 local_id;
    u32 box_mode;
    u32 ptp_sel;
    u32 misc_ctrl;
    u8 res4[0x100 - 0xe0];

    /* DMAC */
    u32 ctrl_dmac_control;
    u32 video_dmac_control;
    u32 file_dmac_control;
    u32 ctrl_master_mode;
    u32 com_e_vd_count;
    u32 irq_vd_count;
    u32 irq_vd_control;
    u32 multi_cast_start;
    u64 ctrl_dmac_write_adrs;
    u64 ctrl_dmac_read_adrs;
    u64 frame_count_adrs;
    u64 multi_cast1_write_adrs;
    u64 multi_cast2_write_adrs;
    u64 multi_cast3_write_adrs;
    u64 multi_cast4_write_adrs;
    u64 multi_cast5_write_adrs;
    u64 multi_cast6_write_adrs;
    u64 multi_cast7_write_adrs;
    u64 multi_cast8_write_adrs;
    u64 file_dmac_write_adrs;
    u64 file_dmac_read_adrs;
    u32 ctrl_dmac_size;
    u32 cmp_test_ctrl;
    u32 pug_media_mode;
    u32 pug_media_clear;

    u8 res5[0x200 - 0x198];

    dmac_file_register dmac_file;

    /* for gif video */
    dmac_media_register dmac_media[DMA_PORT_NUM];

};

static const u32 REF_MGR_START_OFFSET = 0xc000;
struct ref_mgr_reg {
    u32 tof_gen_00;
    u32 tof_gen_01;
    u32 res1[2];
    u32 ckx_gen_00;
    u32 ckx_gen_sub_00;
    u32 ckx_gen_01;
    u32 ckx_gen_sub_01;
    u32 ckx_gen_02;
    u32 ckx_gen_sub_02;
    u32 ckx_gen_03;
    u32 ckx_gen_sub_03;
    u32 res2[(0x40 - 0x30) / 4];
    u32 debug_mon_cntl;
    u32 res3[(0x60 - 0x44) / 4];
    u32 misc_ctrl;
};

static const u32 BIM_C2C_AURORA_OFFSET   = 0x8a00;
static const u32 BIM_RTP_AURORA_OFFSET   = 0x8200;
static const u32 BIM_SWR_AURORA_OFFSET   = 0x8400;
static const u32 BIM_XPT_AURORA_OFFSET   = 0x8600;
static const u32 BIM_BIM_AURORA_OFFSET   = 0x8800;

static const u32 NEM_C2C_AURORA_A_OFFSET = 0x8000;
static const u32 NEM_C2C_AURORA_B_OFFSET = 0x8200;
static const u32 NEM_RTP_AURORA_A_OFFSET = 0x8400;
static const u32 NEM_RTP_AURORA_B_OFFSET = 0x8600;

static const u32 XPT_AURORA_0_OFFSET     = 0x8000;
static const u32 XPT_AURORA_1_OFFSET     = 0x8200;
static const u32 XPT_AURORA_2_OFFSET     = 0x8400;
static const u32 XPT_AURORA_3_OFFSET     = 0x8600;
static const u32 XPT_AURORA_4_OFFSET     = 0x8800;
static const u32 XPT_AURORA_5_OFFSET     = 0x8a00;
static const u32 XPT_AURORA_6_OFFSET     = 0x8c00;
static const u32 XPT_AURORA_7_OFFSET     = 0x8e00;
static const u32 XPT_SWR_AURORA_OFFSET   = 0x9000;

static const u32 SIS_AURORA_OFFSET       = 0x00008600;

struct aurora_duplex {
    u32 aurora_ip_loopback;
    u32 res1;
    u32 aurora_reset;
    u32 res2;
    u32 aurora_loopback;
    u32 res3;
    u32 aurora_nStop;
    u32 res4;
    u32 aurora_status_0;
    u32 aurora_status_1;
    u32 aurora_status_2;
    u32 res5;
    u32 StreamTxCount_0;
    u32 StreamTxCount_1;
    u32 StreamTxCount_2;
    u32 StreamTxCount_3;
    u32 StreamRxCount_0;
    u32 StreamRxCount_1;
    u32 StreamRxCount_2;
    u32 StreamRxCount_3;
    u32 res6[12];
    u32 tx_diff_ctrl_0;
    u32 tx_diff_ctrl_1;
    u32 res7[2];
    u32 tx_post_cursor_0;
    u32 tx_post_cursor_1;
    u32 res8[2];
    u32 tx_pre_cursor_0;
    u32 tx_pre_cursor_1;
};

struct aurora_simplex {
    u32 aurora_loopback;
    u32 res1;
    u32 aurora_reset;
    u32 res2;
    u32 aurora_test_en;
    u32 aurora_test_id;
    u32 aurora_test_result;
    u32 res4;
    u32 aurora_status_0;
    u32 aurora_status_1;
    u32 aurora_status_2;
    u32 res5;
    u32 StreamTxCount_0;
    u32 StreamTxCount_1;
    u32 StreamTxCount_2;
    u32 StreamTxCount_3;
    u32 StreamTxCount_4;
    u32 StreamTxCount_5;
    u32 StreamTxCount_6;
    u32 StreamTxCount_7;
    u32 StreamRxCount_0;
    u32 StreamRxCount_1;
    u32 StreamRxCount_2;
    u32 StreamRxCount_3;
    u32 StreamRxCount_4;
    u32 StreamRxCount_5;
    u32 StreamRxCount_6;
    u32 StreamRxCount_7;
    u32 res6[4];
    u32 tx_diff_ctrl_0;
    u32 tx_diff_ctrl_1;
    u32 res7[2];
    u32 tx_post_cursor_0;
    u32 tx_post_cursor_1;
    u32 res8[2];
    u32 tx_pre_cursor_0;
    u32 tx_pre_cursor_1;
    u32 res9[(0x100 - 0xa8) / 4];
    u32 physical_box_id;
    u32 test_sel;
    u32 test_enable;
    u32 test_result_clear;
    u32 connect_result_pri_0;
    u32 res10;
    u32 connect_result_meo;
    u32 res11;
    u32 compare_result_pri_0;
    u32 res12;
    u32 compare_result_meo;
};

struct xpt_aurora_qsfp {
    u32 aurora_loopback;
    u32 res1;
    u32 aurora_reset;
    u32 res2;
    u32 aurora_test_en;
    u32 aurora_test_id;
    u32 aurora_test_result;
    u32 res3;
    u32 aurora_status_0;
    u32 aurora_status_1;
    u32 aurora_status_2;
    u32 res4;
    u32 StreamTxCount_0;
    u32 StreamTxCount_1;
    u32 StreamTxCount_2;
    u32 StreamTxCount_3;
    u32 StreamTxCount_4;
    u32 StreamTxCount_5;
    u32 StreamTxCount_6;
    u32 StreamTxCount_7;
    u32 StreamTxCount_8;
    u32 StreamTxCount_9;
    u32 StreamTxCount_10;
    u32 StreamTxCount_11;
    u32 res5[4];
    u32 StreamRxCount_0;
    u32 StreamRxCount_1;
    u32 StreamRxCount_2;
    u32 StreamRxCount_3;
    u32 StreamRxCount_4;
    u32 StreamRxCount_5;
    u32 StreamRxCount_6;
    u32 StreamRxCount_7;
    u32 StreamRxCount_8;
    u32 StreamRxCount_9;
    u32 StreamRxCount_10;
    u32 StreamRxCount_11;
    u32 res6[12];
    u32 tx_diff_ctrl_0;
    u32 tx_diff_ctrl_1;
    u32 tx_diff_ctrl_2;
    u32 res7;
    u32 tx_post_cursor_0;
    u32 tx_post_cursor_1;
    u32 tx_post_cursor_2;
    u32 res8;
    u32 tx_pre_cursor_0;
    u32 tx_pre_cursor_1;
    u32 tx_pre_cursor_2;
    u32 res9;
    u32 physical_box_id;
    u32 test_sel;
    u32 test_enable;
    u32 test_result_clear;
    u32 connect_result_pri_0;
    u32 connect_result_pri_1;
    u32 connect_result_meo;
    u32 res10;
    u32 compare_result_pri_0;
    u32 compare_result_pri_1;
    u32 compare_result_meo;
};

struct xpt_aurora_mb {
    u32 aurora_loopback0;
    u32 res1;
    u32 aurora_reset;
    u32 res2;
    u32 aurora_test_en;
    u32 aurora_test_id;
    u32 aurora_test_result;
    u32 res3;
    u32 aurora_status_0;
    u32 aurora_status_1;
    u32 aurora_status_2;
    u32 aurora_status_3;
    u32 StreamTxCount_0;
    u32 StreamTxCount_1;
    u32 StreamTxCount_2;
    u32 StreamTxCount_3;
    u32 StreamTxCount_4;
    u32 StreamTxCount_5;
    u32 StreamTxCount_6;
    u32 StreamTxCount_7;
    u32 StreamTxCount_8;
    u32 StreamTxCount_9;
    u32 StreamTxCount_10;
    u32 StreamTxCount_11;
    u32 StreamTxCount_12;
    u32 StreamTxCount_13;
    u32 StreamTxCount_14;
    u32 StreamTxCount_15;
    u32 StreamRxCount_0;
    u32 StreamRxCount_1;
    u32 StreamRxCount_2;
    u32 StreamRxCount_3;
    u32 StreamRxCount_4;
    u32 StreamRxCount_5;
    u32 StreamRxCount_6;
    u32 StreamRxCount_7;
    u32 StreamRxCount_8;
    u32 StreamRxCount_9;
    u32 StreamRxCount_10;
    u32 StreamRxCount_11;
    u32 StreamRxCount_12;
    u32 StreamRxCount_13;
    u32 StreamRxCount_14;
    u32 StreamRxCount_15;
    u32 res6[8];
    u32 tx_diff_ctrl_0;
    u32 tx_diff_ctrl_1;
    u32 tx_diff_ctrl_2;
    u32 tx_diff_ctrl_3;
    u32 tx_post_cursor_0;
    u32 tx_post_cursor_1;
    u32 tx_post_cursor_2;
    u32 tx_post_cursor_3;
    u32 tx_pre_cursor_0;
    u32 tx_pre_cursor_1;
    u32 tx_pre_cursor_2;
    u32 tx_pre_cursor_3;
};

struct gpu_region
{
    nvidia_p2p_page_table_t* pages;
};

#define CBUSNO(ctrl_data) (ctrl_data->pci_dev->bus->number)
#define CDEVICE(ctrl_data) (&ctrl_data->pci_dev->dev)

#define DESC_SET_MAX 16
#define VIDEO_DESC_SET_MAX 288 // 9port x 2(R/W) x 4ch x 4strip

struct qsfp_control {
    struct sony_fpga_ctrl* fpga_ctrl_addr;
    u32 ctrl_addr;
    u32 io_expander_addr;
    u32 ctrl_index;

    struct qsfp_status status[8];
    struct mutex qsfp_mutex;
    struct task_struct* poll_thread;
    u32 led_status[8];
    u32 counter;
    bool pause;
};

struct vd_wait_queue {
    bool initialized;
    wait_queue_head_t queue;
};
typedef struct vd_wait_queue vd_wait_queue_t;

#define vd_init_waitqueue_head(Q)         \
do {                                      \
    if (Q != NULL && !(Q)->initialized) { \
        init_waitqueue_head(&(Q)->queue); \
        (Q)->initialized = true;          \
    }                                     \
} while (0)

#define vd_wake_up_interruptible(Q)         \
do {                                        \
    if (Q != NULL && (Q)->initialized) {   \
        wake_up_interruptible(&(Q)->queue); \
    }                                       \
} while (0)

#define vd_wait_event_interruptible(Q, condition)     \
({                                                    \
    long __ret;                                       \
    if (Q.initialized) {                              \
        wait_event_interruptible(Q.queue, condition); \
        __ret = 0;                                    \
    } else {                                          \
        __ret = -1;                                   \
    }                                                 \
    __ret;                                            \
})

#define vd_wait_event_interruptible_timeout(Q, condition, timeout_ms)             \
({                                                                                \
    long __ret = 0;                                                               \
    if (Q.initialized) {                                                          \
        __ret = wait_event_interruptible_timeout(Q.queue, condition, timeout_ms); \
    } else {                                                                      \
        __ret = -1;                                                               \
    }                                                                             \
    __ret;                                                                        \
})

struct sony_fpga_ctrl {
    // PCI関連
    struct pci_dev* pci_dev;
    void __iomem*   bar[NUM_BARS];
    size_t          bar_size[NUM_BARS];
    char            msi_enabled;

    u32 fpga_uniq_id;
    u32 local_id;

    u32 video_format;
    // chdev
    dev_t  cdevno;
    struct cdev cdev;

    // Ctrl DMAC
    struct mutex ctrl_dmac_mutex;
    u32          ctrl_dmac_pages;
    dma_addr_t   ctrl_dmac_buffer_bus_addr;
    void*        ctrl_dmac_buffer;
    u32*         ctrl_dmac_wp;
    u32          cmp_test_ctrl;

   /* GIF_VIDEO_ONLY */
    struct gpu_region gd;
    /* GIF Video用 Descriptor */
    int              video_descriptor_pages;
    u8*              video_descriptor_virt_addr;
    dma_addr_t       video_descriptor_bus_addr;
    struct dma_desc* free_video_descriptor;
    u32 free_video_descriptor_cnt;
    int video_dmac_control;
    int video_dmac_pause;
    struct mutex video_dmac_mutex;
    struct delayed_work video_dmac_start_work;

    struct desc_set* video_desc_set;
    u32 current_desc_set_index;

#if 0 // nem driverが割込を受けるべくGlobal変数化

    /* GIF_FPGA_ONLY */
    wait_queue_head_t vd_wait_queue;
    u32 int_counter; /* 1/4 VD単位のカウンタ */
#endif

    int        user_pid;

    dma_addr_t   file_dmac_descriptor_bus_addr;
    u64*         file_dmac_descriptor_virt_buffer;
    u32          file_dmac_descriptor_size;
    struct mutex file_dmac_mutex;

    struct qsfp_control* qsfp_ctrl;
    u32 i2c_index;

    struct report_data {
        u32 etime;
        u32 page_num;
        u32 direction;
        char target[4];
        struct timeval start;
        struct timeval delta;
    } report_data[2][100];
    u32 report_idx[2];

    struct mutex nios_mutex;
#ifdef DEBUG
    struct dentry* dfs_root;
#endif
#ifdef FPGA_DUMMY
    u8 dummy_fpga_reg[sizeof(struct sony_fpga_register)];
#endif
};

#define IGNORE_LIST_MAX 255
struct ctrl_dmac_ignore_mng {
    u32 block_cnt;
    u32 data[IGNORE_LIST_MAX];
};

#define ARRAY_FOREACH(x_, i_) \
    for (i_ = 0; i_ < ARRAY_SIZE(x_); i_++)

#ifdef FPGA_DUMMY
#define IO_READ_32(addr)         (ctrl_data->dummy_fpga_reg[addr - ctrl_data->bar[FPGA_CTRL_BAR]])
#define IO_WRITE_32(data, addr)  { \
    *(u32*)&(ctrl_data->dummy_fpga_reg[addr - ctrl_data->bar[FPGA_CTRL_BAR]]) = data; \
}
#define IO_WRITE_64(data, addr)  { \
    *(u64*)&(ctrl_data->dummy_fpga_reg[addr - ctrl_data->bar[FPGA_CTRL_BAR]]) = data; \
}
#else
#define IO_READ_32    ioread32
#define IO_WRITE_32   iowrite32
#ifdef ENABLE_DFX
#define IO_WRITE_64(data, addr) { \
    iowrite32((data) >> 32, addr+4); \
    iowrite32((data) & 0xffffffff, addr); \
}
#else
#define IO_WRITE_64   writeq
#endif
#endif
#endif /* _SONY_FPGA_H_ */
