unplugged-kernel/drivers/misc/mediatek/eccci/hif/ccci_hif_dpmaif.h

528 lines
14 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2016 MediaTek Inc.
*/
#ifndef __MODEM_DPMA_H__
#define __MODEM_DPMA_H__
#include <linux/device.h>
#include <linux/pm_wakeup.h>
#include <linux/dmapool.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/skbuff.h>
#include "mt-plat/mtk_ccci_common.h"
#include "ccci_bm.h"
#include "ccci_hif_internal.h"
/*
* hardcode, max queue number should be synced with port array in port_cfg.c
*/
#ifndef _E1_SB_SW_WORKAROUND_
#define BAT_CNT_BURST_UPDATE /* update with pit cnt update */
#endif
#define DPMAIF_RXQ_NUM 1
#define DPMAIF_TXQ_NUM 4
/*Default DPMAIF DL common setting*/
#define DPMAIF_HW_BAT_REMAIN 64
#ifndef DPMAIF_PKT_SIZE
#define DPMAIF_PKT_SIZE (128*28) /* 3584 ==SKB_4K */
#define DPMAIF_FRG_SIZE (128) /* ==, no used */
#endif
#define DPMAIF_HW_BAT_PKTBUF DPMAIF_PKT_SIZE
#define DPMAIF_HW_FRG_PKTBUF DPMAIF_FRG_SIZE
#define DPMAIF_HW_BAT_RSVLEN 0 /* 88 */
#define DPMAIF_HW_PKT_BIDCNT 1 /* 3-->1 should be 1 in E1 */
#define DPMAIF_HW_PKT_ALIGN 64
#define DPMAIF_HW_MTU_SIZE (3*1024 + 8)
#define DPMAIF_BUF_PKT_SIZE DPMAIF_PKT_SIZE
#define DPMAIF_BUF_FRAG_SIZE DPMAIF_FRG_SIZE
#ifdef MT6297
#define DPMAIF_HW_CHK_BAT_NUM 62
#define DPMAIF_HW_CHK_FRG_NUM DPMAIF_HW_CHK_BAT_NUM
#define DPMAIF_HW_CHK_PIT_NUM (DPMAIF_HW_CHK_BAT_NUM*2)
#define DPMAIF_HW_CHK_RB_PIT_NUM 64
#else
#define DPMAIF_HW_CHK_PIT_NUM 6
#define DPMAIF_HW_CHK_BAT_NUM 3
#define DPMAIF_HW_CHK_FRG_NUM 3
#endif
#ifdef MT6297
#define DPMAIF_DL_BAT_ENTRY_SIZE 8192 /* <- 1024 <- 128 */
#else
#define DPMAIF_DL_BAT_ENTRY_SIZE 1024 /* 128 */
#endif
/* 2048*/ /* 256, 100pkts*2*10ms=2000*12B=>24k */
#define DPMAIF_DL_PIT_ENTRY_SIZE (DPMAIF_DL_BAT_ENTRY_SIZE * 2)
#define DPMAIF_UL_DRB_ENTRY_SIZE 2048 /* from 512 */
#ifdef MT6297
#define DPMAIF_DL_PIT_BYTE_SIZE 16
#else
#define DPMAIF_DL_PIT_BYTE_SIZE 12
#endif
#define DPMAIF_DL_BAT_BYTE_SIZE 8
#define DPMAIF_UL_DRB_BYTE_SIZE 8
#define DPMAIF_DL_PIT_SIZE (DPMAIF_DL_PIT_ENTRY_SIZE*DPMAIF_DL_PIT_BYTE_SIZE)
#define DPMAIF_DL_BAT_SIZE (DPMAIF_DL_BAT_ENTRY_SIZE*DPMAIF_DL_BAT_BYTE_SIZE)
#define DPMAIF_UL_DRB_SIZE (DPMAIF_UL_DRB_ENTRY_SIZE*DPMAIF_UL_DRB_BYTE_SIZE)
#ifdef _HW_REORDER_SW_WORKAROUND_
#define DPMAIF_DUMMY_PIT_MAX_NUM 0x3fffff
#define DPMAIF_DUMMY_PIT_AIDX 1024
#endif
struct ringbuf_str {
unsigned int rd_idx;
unsigned int wrt_idx;
unsigned int buf_len;
};
/****************************************************************************
* Structure of DL PIT
****************************************************************************/
#if MD_GENERATION < 6297
struct dpmaifq_normal_pit {
unsigned int packet_type:1; /* 0-payload packet; 1-message packet */
unsigned int c_bit:1;/* 1-1/n; 0-the last one */
unsigned int buffer_type:1; /* 0-pkt bat buffer; 1-frag bat buffer */
unsigned int buffer_id:13; /* BAT index */
unsigned int data_len:16;
unsigned int p_data_addr;
unsigned int data_addr_ext:8;
unsigned int reserved:24;
};
#else
struct dpmaifq_normal_pit {
unsigned int packet_type:1;
unsigned int c_bit:1;
unsigned int buffer_type:1;
unsigned int buffer_id:13;
unsigned int data_len:16;
unsigned int p_data_addr;
unsigned int data_addr_ext;
unsigned int pit_seq:16;
unsigned int ig:1;
unsigned int reserved2:7;
unsigned int ulq_done:6;
unsigned int dlq_done:2;
};
#endif
/* packet_type */
#define DES_PT_PD 0x00
#define DES_PT_MSG 0x01
/* c_bit */
#define PKT_LAST_ONE 0x0
/* buffer_type */
#define PKT_BUF_FRAG 0x1
#if MD_GENERATION < 6297
struct dpmaifq_msg_pit {
unsigned int packet_type:1;
unsigned int c_bit:1;
unsigned int check_sum:2;
unsigned int error_bit:1;
unsigned int reserved:11;
unsigned int channel_id:8;
unsigned int network_type:3;
unsigned int reserved2:5;
unsigned int count_l:16;
unsigned int flow:4;
unsigned int cmd:3;
unsigned int reserved3:9;
unsigned int reserved4;
};
#else
struct dpmaifq_msg_pit {
unsigned int packet_type:1;
unsigned int c_bit:1;
unsigned int check_sum:2;
unsigned int error_bit:1;
unsigned int src_qid:3;
unsigned int reserved:8;
unsigned int channel_id:8;
unsigned int network_type:3;
unsigned int reserved2:4;
unsigned int dp:1;
unsigned int count_l:16;
unsigned int flow:5;
unsigned int reserved3:3;
unsigned int cmd:3;
unsigned int reserved4:5;
unsigned int reserved5:3;
unsigned int vbid:13;
unsigned int reserved6:16;
unsigned int pit_seq:16;
unsigned int ig:1;
unsigned int reserved7:7;
unsigned int ulq_done:6;
unsigned int dlq_done:2;
};
#endif
/****************************************************************************
* Structure of DL BAT
****************************************************************************/
struct dpmaif_bat_t {
unsigned int p_buffer_addr;
unsigned int buffer_addr_ext:8;
unsigned int reserved:24;
};
struct dpmaif_bat_skb_t {
struct sk_buff *skb;
dma_addr_t data_phy_addr;
unsigned int data_len;
};
struct dpmaif_bat_page_t {
struct page *page;
dma_addr_t data_phy_addr;
unsigned long offset;
unsigned int data_len;
};
#define MAX_BD_NUM (MAX_SKB_FRAGS + 1)
#define DPMAIF_TRAFFIC_MONITOR_INTERVAL 10
#define SKB_RX_LIST_MAX_LEN 0xFFFFFFFF
struct dpmaif_bat_request {
void *bat_base;
dma_addr_t bat_phy_addr; /* physical address for DMA */
unsigned int bat_size_cnt;
unsigned short bat_wr_idx;
unsigned short bat_rd_idx;
unsigned short bat_rel_rd_idx;
void *bat_skb_ptr;/* collect skb linked to bat */
unsigned int skb_pkt_cnt;
unsigned int pkt_buf_sz;
#if defined(_97_REORDER_BAT_PAGE_TABLE_)
unsigned char bid_btable[DPMAIF_DL_BAT_ENTRY_SIZE];
#endif
/* for debug */
int check_bid_fail_cnt;
};
enum error_num {
LOW_MEMORY_ERR = -15,
LOW_MEMORY_PIT,
LOW_MEMORY_BAT,
LOW_MEMORY_SKB,
LOW_MEMORY_DRB,
LOW_MEMORY_TYPE_MAX, /* -10 */
DMA_MAPPING_ERR,
FLOW_CHECK_ERR,
DATA_CHECK_FAIL,
HW_REG_CHK_FAIL,
HW_REG_TIME_OUT,
ERROR_STOP_MAX, /* -4 */
};
struct dpmaif_rx_queue {
unsigned char index;
bool que_started;
unsigned short budget;
void *pit_base;
dma_addr_t pit_phy_addr; /* physical address for DMA */
unsigned int pit_size_cnt;
unsigned short pit_rd_idx;
unsigned short pit_wr_idx;
unsigned short pit_rel_rd_idx;
unsigned int reg_int_mask_bak;
#ifdef _HW_REORDER_SW_WORKAROUND_
unsigned long pit_dummy_cnt;
unsigned long pit_dummy_idx;
unsigned char pit_reload_en;
#endif
struct dpmaif_bat_request bat_req;
#ifdef HW_FRG_FEATURE_ENABLE
struct dpmaif_bat_request bat_frag;
#endif
struct tasklet_struct dpmaif_rxq0_task;
wait_queue_head_t rx_wq;
struct task_struct *rx_thread;
struct workqueue_struct *worker;
struct work_struct dpmaif_rxq0_work;
spinlock_t rx_lock;
atomic_t rx_processing;
unsigned int cur_chn_idx:8;
unsigned int check_sum:2;
int skb_idx;
struct ccci_skb_queue skb_list;
unsigned int pit_dp;
};
/****************************************************************************
* Structure of UL DRB
****************************************************************************
*/
/*
* UL unit: WORD == 4bytes, && 1drb == 8bytes,
* so 1 drb = size_cnt * 2, rd_idx_sw = rd_idx_hw/2.
*/
#define DPMAIF_UL_DRB_ENTRY_WORD 2 /* (sizeof(dpmaif_drb_pd)/4)*/
struct dpmaif_drb_pd {
unsigned int dtyp:2;
unsigned int c_bit:1;
unsigned int reserved:5;
unsigned int data_addr_ext:8;
unsigned int data_len:16;
unsigned int p_data_addr;
};
/* drb->dtype */
#define DES_DTYP_PD 0x00
#define DES_DTYP_MSG 0x01
#define DES_DRB_CBIT 0x01
struct dpmaif_drb_msg {
unsigned int dtyp:2;
unsigned int c_bit:1;
unsigned int reserved:13;
unsigned int packet_len:16;
unsigned int count_l:16;
unsigned int channel_id:8;
unsigned int network_type:3;
unsigned int r:1;
unsigned int ipv4:1; /* enable ul checksum offload for ipv4 header */
unsigned int l4:1; /* enable ul checksum offload for tcp/udp */
unsigned int rsv:2;
};
struct dpmaif_drb_skb {
struct sk_buff *skb;
dma_addr_t phy_addr; /* physical address for DMA */
unsigned short data_len;
/* just for debug */
unsigned short drb_idx:13;
unsigned short is_msg:1;
unsigned short is_frag:1;
unsigned short is_last_one:1;
};
struct dpmaif_tx_queue {
unsigned char index;
bool que_started;
atomic_t tx_budget;
void *drb_base;
dma_addr_t drb_phy_addr; /* physical address for DMA */
unsigned int drb_size_cnt;
unsigned short drb_wr_idx;
unsigned short drb_rd_idx;
unsigned short drb_rel_rd_idx;
unsigned short last_ch_id;
void *drb_skb_base;
wait_queue_head_t req_wq;
struct workqueue_struct *worker;
#ifdef USING_TX_DONE_KERNEL_THREAD
/* For Tx done Kernel thread */
struct hrtimer tx_done_timer;
atomic_t txq_done;
wait_queue_head_t tx_done_wait;
void *tx_done_thread;
#else
struct delayed_work dpmaif_tx_work;
#endif
spinlock_t tx_lock;
atomic_t tx_processing;
#if DPMAIF_TRAFFIC_MONITOR_INTERVAL
unsigned int busy_count;
#endif
atomic_t tx_resume_tx;
atomic_t tx_resume_done;
};
enum hifdpmaif_state {
HIFDPMAIF_STATE_MIN = 0,
HIFDPMAIF_STATE_PWROFF,
HIFDPMAIF_STATE_PWRON,
HIFDPMAIF_STATE_EXCEPTION,
HIFDPMAIF_STATE_MAX,
};
struct ccci_hif_dpmaif_val {
struct regmap *infra_ao_base;
unsigned int md_gen;
unsigned long offset_epof_md1;
void __iomem *md_plat_info;
};
struct hif_dpmaif_ctrl {
enum hifdpmaif_state dpmaif_state;
struct dpmaif_tx_queue txq[DPMAIF_TXQ_NUM];
struct dpmaif_rx_queue rxq[DPMAIF_RXQ_NUM];
struct dma_pool *tx_drb_dmapool;
struct dma_pool *rx_pit_dmapool;
struct dma_pool *rx_bat_dmapool;
unsigned char md_id;
unsigned char hif_id;
struct ccci_hif_traffic traffic_info;
atomic_t wakeup_src;
void __iomem *dpmaif_ao_ul_base;
void __iomem *dpmaif_ao_dl_base;
void __iomem *dpmaif_pd_ul_base;
void __iomem *dpmaif_pd_dl_base;
void __iomem *dpmaif_pd_misc_base;
void __iomem *dpmaif_pd_md_misc_base;
void __iomem *dpmaif_pd_sram_base;
void __iomem *dpmaif_pd_rdma_base;
void __iomem *dpmaif_pd_wdma_base;
void __iomem *dpmaif_ao_md_dl_base;
unsigned int dpmaif_irq_id;
unsigned long dpmaif_irq_flags;
atomic_t dpmaif_irq_enabled;
struct ccci_hif_ops *ops;
#if DPMAIF_TRAFFIC_MONITOR_INTERVAL
unsigned int tx_traffic_monitor[DPMAIF_TXQ_NUM];
unsigned int rx_traffic_monitor[DPMAIF_RXQ_NUM];
unsigned int tx_pre_traffic_monitor[DPMAIF_TXQ_NUM];
unsigned long long tx_done_last_start_time[DPMAIF_TXQ_NUM];
unsigned int tx_done_last_count[DPMAIF_TXQ_NUM];
struct timer_list traffic_monitor;
char traffic_started;
#endif
struct clk *clk_ref0;
struct clk *clk_ref1;
struct platform_device *plat_dev; /* maybe: no need. */
struct ccci_hif_dpmaif_val plat_val;
atomic_t suspend_flag;
};
#ifndef CCCI_KMODULE_ENABLE
static inline int ccci_dpma_hif_send_skb(unsigned char hif_id, int tx_qno,
struct sk_buff *skb, int from_pool, int blocking)
{
struct hif_dpmaif_ctrl *hif_ctrl =
(struct hif_dpmaif_ctrl *)ccci_hif_get_by_id(hif_id);
if (hif_ctrl)
return hif_ctrl->ops->send_skb(hif_id, tx_qno, skb, from_pool,
blocking);
else
return -1;
}
static inline int ccci_dpma_hif_write_room(unsigned char hif_id,
unsigned char qno)
{
struct hif_dpmaif_ctrl *hif_ctrl =
(struct hif_dpmaif_ctrl *)ccci_hif_get_by_id(hif_id);
if (hif_ctrl)
return hif_ctrl->ops->write_room(hif_id, qno);
else
return -1;
}
static inline int ccci_dpma_hif_give_more(unsigned char hif_id, int rx_qno)
{
struct hif_dpmaif_ctrl *hif_ctrl =
(struct hif_dpmaif_ctrl *)ccci_hif_get_by_id(hif_id);
if (hif_ctrl)
return hif_ctrl->ops->give_more(hif_id, rx_qno);
else
return -1;
}
static inline int ccci_dpmaif_hif_dump_status(unsigned char hif_id,
enum MODEM_DUMP_FLAG dump_flag, void *buff, int length)
{
struct hif_dpmaif_ctrl *hif_ctrl =
(struct hif_dpmaif_ctrl *)ccci_hif_get_by_id(hif_id);
if (hif_ctrl)
return hif_ctrl->ops->dump_status(hif_id, dump_flag,
buff, length);
else
return -1;
}
static inline int ccci_dpmaif_hif_set_wakeup_src(unsigned char hif_id,
int value)
{
struct hif_dpmaif_ctrl *hif_ctrl =
(struct hif_dpmaif_ctrl *)ccci_hif_get_by_id(hif_id);
if (hif_ctrl)
return atomic_set(&hif_ctrl->wakeup_src, value);
else
return -1;
}
#else
#define ccci_write32(b, a, v) \
do { \
writel(v, (b) + (a)); \
mb(); /* make sure register access in order */ \
} while (0)
#define ccci_write16(b, a, v) \
do { \
writew(v, (b) + (a)); \
mb(); /* make sure register access in order */ \
} while (0)
#define ccci_write8(b, a, v) \
do { \
writeb(v, (b) + (a)); \
mb(); /* make sure register access in order */ \
} while (0)
#define ccci_read32(b, a) ioread32((void __iomem *)((b)+(a)))
#define ccci_read16(b, a) ioread16((void __iomem *)((b)+(a)))
#define ccci_read8(b, a) ioread8((void __iomem *)((b)+(a)))
#endif
int ccci_dpmaif_hif_init(struct device *dev);
int dpmaif_late_init(unsigned char hif_id);
int dpmaif_start(unsigned char hif_id);
int dpmaif_stop_rx(unsigned char hif_id);
int dpmaif_stop_tx(unsigned char hif_id);
int dpmaif_stop(unsigned char hif_id);
void dpmaif_stop_hw(void);
extern struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
const char *property);
extern int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
extern int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
extern void mt_irq_dump_status(int irq);
extern int dpmaif_suspend_noirq(struct device *dev);
extern int dpmaif_resume_noirq(struct device *dev);
#endif /* __MODEM_DPMA_H__ */