// Author: Xianjun Jiao, Michael Mehari, Wei Liu
// SPDX-FileCopyrightText: 2019 UGent
// SPDX-License-Identifier: AGPL-3.0-or-later

#ifndef OPENWIFI_SDR
#define OPENWIFI_SDR

#include "pre_def.h"

// -------------------for leds--------------------------------
struct gpio_led_data { //please always align with the leds-gpio.c in linux kernel
	struct led_classdev cdev;
	struct gpio_desc *gpiod;
	u8 can_sleep;
	u8 blinking;
	gpio_blink_set_t platform_gpio_blink_set;
};

struct gpio_leds_priv { //please always align with the leds-gpio.c in linux kernel
	int num_leds;
	struct gpio_led_data leds[];
};

struct openwifi_rf_ops {
	char *name;
//	void (*init)(struct ieee80211_hw *);
//	void (*stop)(struct ieee80211_hw *);
	void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
//	u8 (*calc_rssi)(u8 agc, u8 sq);
};

struct openwifi_buffer_descriptor {
	// u32 num_dma_byte;
    // u32 sn;
    // u32 hw_queue_idx;
    // u32 retry_limit;
    // u32 need_ack;
    u16 seq_no;
    struct sk_buff *skb_linked;
    dma_addr_t dma_mapping_addr;
    // u32 reserved;
} __packed;

struct openwifi_ring {
	struct openwifi_buffer_descriptor *bds;
    u32 bd_wr_idx;
	u32 bd_rd_idx;
    u32 stop_flag; // track the stop/wake status between tx interrupt and openwifi_tx
	// u32 num_dma_symbol_request;
	// u32 reserved;
} __packed;

struct openwifi_vif {
	struct ieee80211_hw *dev;

	int idx; // this vif's idx on the dev

	/* beaconing */
	struct delayed_work beacon_work;
	bool enable_beacon;
};

union u32_byte4 {
	u32 a;
	u8 c[4];
};
union u16_byte2 {
	u16 a;
	u8 c[2];
};

#define MAX_NUM_LED 4
#define OPENWIFI_LED_MAX_NAME_LEN 32

// ------------ software reg definition ------------
#define MAX_NUM_DRV_REG            8
#define DRV_TX_REG_IDX_RATE        0
#define DRV_TX_REG_IDX_FREQ_BW_CFG 1
#define DRV_TX_REG_IDX_PRINT_CFG   (MAX_NUM_DRV_REG-1)

#define DRV_RX_REG_IDX_FREQ_BW_CFG 1
#define DRV_RX_REG_IDX_EXTRA_FO    2
#define DRV_RX_REG_IDX_PRINT_CFG   (MAX_NUM_DRV_REG-1)

#define DRV_XPU_REG_IDX_LBT_TH     0
#define DRV_XPU_REG_IDX_GIT_REV    (MAX_NUM_DRV_REG-1)

// ------end of software reg definition ------------

#define MAX_NUM_VIF 4

//#define LEN_PHY_HEADER 16
#define LEN_PHY_CRC 4
#define LEN_MPDU_DELIM 4

#define RING_ROOM_THRESHOLD 4
#define NUM_BIT_NUM_TX_BD 6
#define NUM_TX_BD (1<<NUM_BIT_NUM_TX_BD) // !!! should align to the fifo size in tx_bit_intf.v

#ifdef USE_NEW_RX_INTERRUPT
#define NUM_RX_BD 8
#else
#define NUM_RX_BD 16
#endif

#define TX_BD_BUF_SIZE (8192)
#define RX_BD_BUF_SIZE (8192)

#define NUM_BIT_MAX_NUM_HW_QUEUE 2
#define MAX_NUM_HW_QUEUE 4 // number of queue in FPGA
#define MAX_NUM_SW_QUEUE 4 // number of queue in Linux, depends on the number we report by dev->queues in openwifi_dev_probe
#define NUM_BIT_MAX_PHY_TX_SN 10 // decrease 12 to 10 to reserve 2 bits storing related linux prio idx
#define MAX_PHY_TX_SN ((1<<NUM_BIT_MAX_PHY_TX_SN)-1)

#define AD9361_RADIO_OFF_TX_ATT 89750 //please align with ad9361.c
#define AD9361_RADIO_ON_TX_ATT 000    //please align with rf_init.sh

#define SDR_SUPPORTED_FILTERS	\
	(FIF_ALLMULTI |				\
	FIF_BCN_PRBRESP_PROMISC |	\
	FIF_CONTROL |				\
	FIF_OTHER_BSS |				\
	FIF_PSPOLL |				\
	FIF_PROBE_REQ)

#define HIGH_PRIORITY_DISCARD_FLAG ((~0x040)<<16) // don't force drop OTHER_BSS by high priority discard
//#define HIGH_PRIORITY_DISCARD_FLAG ((~0x140)<<16) // don't force drop OTHER_BSS and PROB_REQ by high priority discard

/* 5G chan 36 - chan 64*/
#define SDR_5GHZ_CH36_64 REG_RULE(5150-10, 5350+10, 80, 0, 20, 0)
/* 5G chan 32 - chan 173*/
#define SDR_5GHZ_CH32_173 REG_RULE(5160-10, 5865+10, 80, 0, 20, 0)
/* 5G chan 36 - chan 48*/
#define SDR_5GHZ_CH36_48 REG_RULE(5150-10, 5270+10, 80, 0, 20, 0)

/*
 *Only these channels all allow active
 *scan on all world regulatory domains
 */
#define SDR_2GHZ_CH01_13	REG_RULE(2412-10, 2472+10, 40, 0, 20, NL80211_RRF_NO_CCK) // disable 11b
#define SDR_2GHZ_CH01_14	REG_RULE(2412-10, 2484+10, 40, 0, 20, NL80211_RRF_NO_CCK) // disable 11b

// regulatory.h alpha2
//  *	00 - World regulatory domain
//  *	99 - built by driver but a specific alpha2 cannot be determined
//  *	98 - result of an intersection between two regulatory domains
//  *	97 - regulatory domain has not yet been configured
static const struct ieee80211_regdomain sdr_regd = { // for wiphy_apply_custom_regulatory
	.n_reg_rules = 2,
	.alpha2 = "99",
	.dfs_region = NL80211_DFS_ETSI,
	.reg_rules = {
		//SDR_2GHZ_CH01_13,
		//SDR_5GHZ_CH36_48, //Avoid radar!
		SDR_2GHZ_CH01_14,
		// SDR_5GHZ_CH36_64,
		SDR_5GHZ_CH32_173,
		}
};

#define CHAN2G(_channel, _freq, _flags) { \
	.band			= NL80211_BAND_2GHZ, \
	.hw_value		= (_channel), \
	.center_freq		= (_freq), \
	.flags			= (_flags), \
	.max_antenna_gain	= 0, \
	.max_power		= 0, \
}

#define CHAN5G(_channel, _freq, _flags) { \
	.band			= NL80211_BAND_5GHZ, \
	.hw_value		= (_channel), \
	.center_freq		= (_freq), \
	.flags			= (_flags), \
	.max_antenna_gain	= 0, \
	.max_power		= 0, \
}

static const struct ieee80211_rate openwifi_5GHz_rates[] = {
	{ .bitrate = 10,  .hw_value = 0,  .flags = 0},
	{ .bitrate = 20,  .hw_value = 1,  .flags = 0},
	{ .bitrate = 55,  .hw_value = 2,  .flags = 0},
	{ .bitrate = 110, .hw_value = 3,  .flags = 0},
	{ .bitrate = 60,  .hw_value = 4,  .flags = IEEE80211_RATE_MANDATORY_A},
	{ .bitrate = 90,  .hw_value = 5,  .flags = IEEE80211_RATE_MANDATORY_A},
	{ .bitrate = 120, .hw_value = 6,  .flags = IEEE80211_RATE_MANDATORY_A},
	{ .bitrate = 180, .hw_value = 7,  .flags = IEEE80211_RATE_MANDATORY_A},
	{ .bitrate = 240, .hw_value = 8,  .flags = IEEE80211_RATE_MANDATORY_A},
	{ .bitrate = 360, .hw_value = 9,  .flags = IEEE80211_RATE_MANDATORY_A},
	{ .bitrate = 480, .hw_value = 10, .flags = IEEE80211_RATE_MANDATORY_A},
	{ .bitrate = 540, .hw_value = 11, .flags = IEEE80211_RATE_MANDATORY_A},
};

static const struct ieee80211_rate openwifi_2GHz_rates[] = {
	{ .bitrate = 10,  .hw_value = 0,  .flags = 0},
	{ .bitrate = 20,  .hw_value = 1,  .flags = 0},
	{ .bitrate = 55,  .hw_value = 2,  .flags = 0},
	{ .bitrate = 110, .hw_value = 3,  .flags = 0},
	{ .bitrate = 60,  .hw_value = 4,  .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
	{ .bitrate = 90,  .hw_value = 5,  .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
	{ .bitrate = 120, .hw_value = 6,  .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
	{ .bitrate = 180, .hw_value = 7,  .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
	{ .bitrate = 240, .hw_value = 8,  .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
	{ .bitrate = 360, .hw_value = 9,  .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
	{ .bitrate = 480, .hw_value = 10, .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
	{ .bitrate = 540, .hw_value = 11, .flags = IEEE80211_RATE_MANDATORY_G|IEEE80211_RATE_ERP_G},
};

static const struct ieee80211_channel openwifi_2GHz_channels[] = {
	CHAN2G(1, 2412, 0),
	CHAN2G(2, 2417, 0),
	CHAN2G(3, 2422, 0),
	CHAN2G(4, 2427, 0),
	CHAN2G(5, 2432, 0),
	CHAN2G(6, 2437, 0),
	CHAN2G(7, 2442, 0),
	CHAN2G(8, 2447, 0),
	CHAN2G(9, 2452, 0),
	CHAN2G(10, 2457, 0),
	CHAN2G(11, 2462, 0),
	CHAN2G(12, 2467, 0),
	CHAN2G(13, 2472, 0),
	CHAN2G(14, 2484, 0),
};

static const struct ieee80211_channel openwifi_5GHz_channels[] = {
	CHAN5G(32, 5160, 0),
	CHAN5G(34, 5170, 0),
	CHAN5G(36, 5180, 0),
	CHAN5G(38, 5190, 0),
	CHAN5G(40, 5200, 0),
	CHAN5G(42, 5210, 0),
	CHAN5G(44, 5220, 0),
	CHAN5G(46, 5230, 0),
	CHAN5G(48, 5240, 0),
	CHAN5G( 50, 5250, IEEE80211_CHAN_RADAR),
	CHAN5G( 52, 5260, IEEE80211_CHAN_RADAR),
	CHAN5G( 54, 5270, IEEE80211_CHAN_RADAR),
	CHAN5G( 56, 5280, IEEE80211_CHAN_RADAR),
	CHAN5G( 58, 5290, IEEE80211_CHAN_RADAR),
	CHAN5G( 60, 5300, IEEE80211_CHAN_RADAR),
	CHAN5G( 62, 5310, IEEE80211_CHAN_RADAR),
	CHAN5G( 64, 5320, IEEE80211_CHAN_RADAR),
	CHAN5G( 68, 5340, IEEE80211_CHAN_RADAR),
	CHAN5G( 96, 5480, IEEE80211_CHAN_RADAR),
	CHAN5G(100, 5500, IEEE80211_CHAN_RADAR),
	CHAN5G(102, 5510, IEEE80211_CHAN_RADAR),
	CHAN5G(104, 5520, IEEE80211_CHAN_RADAR),
	CHAN5G(106, 5530, IEEE80211_CHAN_RADAR),
	CHAN5G(108, 5540, IEEE80211_CHAN_RADAR),
	CHAN5G(110, 5550, IEEE80211_CHAN_RADAR),
	CHAN5G(112, 5560, IEEE80211_CHAN_RADAR),
	CHAN5G(114, 5570, IEEE80211_CHAN_RADAR),
	CHAN5G(116, 5580, IEEE80211_CHAN_RADAR),
	CHAN5G(118, 5590, IEEE80211_CHAN_RADAR),
	CHAN5G(120, 5600, IEEE80211_CHAN_RADAR),
	CHAN5G(122, 5610, IEEE80211_CHAN_RADAR),
	CHAN5G(124, 5620, IEEE80211_CHAN_RADAR),
	CHAN5G(126, 5630, IEEE80211_CHAN_RADAR),
	CHAN5G(128, 5640, IEEE80211_CHAN_RADAR),
	CHAN5G(132, 5660, IEEE80211_CHAN_RADAR),
	CHAN5G(134, 5670, IEEE80211_CHAN_RADAR),
	CHAN5G(136, 5680, IEEE80211_CHAN_RADAR),
	CHAN5G(138, 5690, IEEE80211_CHAN_RADAR),
	CHAN5G(140, 5700, IEEE80211_CHAN_RADAR),
	CHAN5G(142, 5710, IEEE80211_CHAN_RADAR),
	CHAN5G(144, 5720, IEEE80211_CHAN_RADAR),
	CHAN5G(149, 5745, IEEE80211_CHAN_RADAR),
	CHAN5G(151, 5755, IEEE80211_CHAN_RADAR),
	CHAN5G(153, 5765, IEEE80211_CHAN_RADAR),
	CHAN5G(155, 5775, IEEE80211_CHAN_RADAR),
	CHAN5G(157, 5785, IEEE80211_CHAN_RADAR),
	CHAN5G(159, 5795, IEEE80211_CHAN_RADAR),
	CHAN5G(161, 5805, IEEE80211_CHAN_RADAR),
	// CHAN5G(163, 5815, IEEE80211_CHAN_RADAR),
	CHAN5G(165, 5825, IEEE80211_CHAN_RADAR),
	CHAN5G(167, 5835, IEEE80211_CHAN_RADAR),
	CHAN5G(169, 5845, IEEE80211_CHAN_RADAR),
	CHAN5G(171, 5855, IEEE80211_CHAN_RADAR),
	CHAN5G(173, 5865, IEEE80211_CHAN_RADAR),
};

static const struct ieee80211_iface_limit openwifi_if_limits[] = {
	{ .max = MAX_NUM_VIF,	.types = BIT(NL80211_IFTYPE_STATION) },
	{ .max = MAX_NUM_VIF,	.types =
#ifdef CONFIG_MAC80211_MESH
				 BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
				 BIT(NL80211_IFTYPE_AP)},
};

static const struct ieee80211_iface_combination openwifi_if_comb = {
	.limits = openwifi_if_limits,
	.n_limits = ARRAY_SIZE(openwifi_if_limits),
	.max_interfaces = MAX_NUM_VIF,
	.num_different_channels = 1,
	.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) |
					BIT(NL80211_CHAN_WIDTH_20) |
					BIT(NL80211_CHAN_WIDTH_40) |
					BIT(NL80211_CHAN_WIDTH_80),
};

static const u8  wifi_rate_table_mapping[24] =     { 0,  0,  0,   0,  0,  0,   0,   0,  10,   8,   6,   4,  11,   9,   7,  5,   0,    1,   2,   3,   4,   5,   6,   7};
static const u16 wifi_rate_table[24] =             { 0,  0,  0,   0,  0,  0,   0,   0, 480, 240, 120,  60, 540, 360, 180, 90,  65,  130, 195, 260, 390, 520, 585, 650};
static const u16 wifi_rate_all[20] =               {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540,  65, 130, 195, 260, 390, 520, 585, 650};
static const u8  wifi_mcs_table_11b_force_up[16] = {11, 11, 11,  11, 11, 15,  10,  14,   9,  13,   8,  12,   0,   0,   0,  0};
static const u16 wifi_n_dbps_table[16] =           {24, 24, 24,  24, 24, 36,  48,  72,  96, 144, 192, 216,   0,   0,   0,  0};
static const u16 wifi_n_dbps_ht_table[16] =        {26, 26, 26,  26, 26, 52,  78, 104, 156, 208, 234, 260,   0,   0,   0,  0};
// static const u8 wifi_mcs_table[8] =             {6,9,12,18,24,36,48,54};
// static const u8 wifi_mcs_table_phy_tx[8]    =   {11,15,10,14,9,13,8,12};

// ===== copy from adi-linux/drivers/iio/frequency/cf_axi_dds.c =====
struct cf_axi_dds_state {
	struct device			*dev_spi;
	struct clk			*clk;
	struct cf_axi_dds_chip_info	*chip_info;
	struct gpio_desc		*plddrbypass_gpio;
	struct gpio_desc		*interpolation_gpio;

	bool				standalone;
	bool				dp_disable;
	bool				enable;
	bool				pl_dma_fifo_en;
	enum fifo_ctrl			gpio_dma_fifo_ctrl;

	struct iio_info			iio_info;
	size_t				regs_size;
	void __iomem			*regs;
	void __iomem			*slave_regs;
	void __iomem			*master_regs;
	u64				dac_clk;
	unsigned int			ddr_dds_interp_en;
	unsigned int			cached_freq[16];
	unsigned int			version;
	unsigned int			have_slave_channels;
	unsigned int			interpolation_factor;
	struct notifier_block		clk_nb;
};
// ===== end of copy from adi-linux/drivers/iio/frequency/cf_axi_dds.c =====

#define RX_DMA_CYCLIC_MODE
struct openwifi_priv {
	struct platform_device *pdev;
	struct ieee80211_vif *vif[MAX_NUM_VIF];

	const struct openwifi_rf_ops *rf;
	enum openwifi_fpga_type fpga_type;

	struct cf_axi_dds_state *dds_st;  //axi_ad9361 hdl ref design module, dac channel
	struct axiadc_state *adc_st;      //axi_ad9361 hdl ref design module, adc channel
	struct ad9361_rf_phy *ad9361_phy; //ad9361 chip
	struct ctrl_outs_control ctrl_out;

	int rx_freq_offset_to_lo_MHz;
	int tx_freq_offset_to_lo_MHz;
	u32 rf_bw;
	u32 actual_rx_lo;

	struct ieee80211_rate rates_2GHz[12];
	struct ieee80211_rate rates_5GHz[12];
	struct ieee80211_channel channels_2GHz[14];
	struct ieee80211_channel channels_5GHz[53];
	struct ieee80211_supported_band band_2GHz;
	struct ieee80211_supported_band band_5GHz;
	bool rfkill_off;

	int rssi_correction; // dynamic RSSI correction according to current channel in _rf_set_channel()
	
	enum rx_intf_mode rx_intf_cfg;
	enum tx_intf_mode tx_intf_cfg;
	enum openofdm_rx_mode openofdm_rx_cfg;
	enum openofdm_tx_mode openofdm_tx_cfg;
	enum xpu_mode xpu_cfg;

	int irq_rx;
	int irq_tx;

	// u32 call_counter;
	u8 *rx_cyclic_buf;
	dma_addr_t rx_cyclic_buf_dma_mapping_addr;
	struct dma_chan *rx_chan;
	struct dma_async_tx_descriptor *rxd;
	dma_cookie_t rx_cookie;

	struct openwifi_ring tx_ring[MAX_NUM_SW_QUEUE];
	struct scatterlist tx_sg;
	struct dma_chan *tx_chan;
	struct dma_async_tx_descriptor *txd;
	dma_cookie_t tx_cookie;
	// struct completion tx_dma_complete;
	// bool openwifi_tx_first_time_run;

	// int phy_tx_sn;
	u32 slice_idx;
	u32 dest_mac_addr_queue_map[MAX_NUM_HW_QUEUE];
	u8 mac_addr[ETH_ALEN];
	u16 seqno;

	bool use_short_slot;
	u8 band;
	u16 channel, tid;

	u32 ampdu_reference;

	u32 drv_rx_reg_val[MAX_NUM_DRV_REG];
	u32 drv_tx_reg_val[MAX_NUM_DRV_REG];
	u32 drv_xpu_reg_val[MAX_NUM_DRV_REG];
	int last_auto_fpga_lbt_th;
	// u8 num_led;
	// struct led_classdev *led[MAX_NUM_LED];//zc706 has 4 user leds. please find openwifi_dev_probe to see how we get them.
	// char led_name[MAX_NUM_LED][OPENWIFI_LED_MAX_NAME_LEN];

	spinlock_t lock;
};

#endif /* OPENWIFI_SDR */
