mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
pcie-dma-trx: update to version 0x4
1.Optimize DMA hook to support multiple independent DMA channels 2.Add interrupt callback to support multiple independent DMA channels Change-Id: I42a638a4cb9fa61ebc1cd51d4e9f6d6942715fd1 Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
@@ -87,6 +87,8 @@ enum rk_pcie_device_mode {
|
||||
#define PCIE_DMA_RD_INT_MASK 0xa8
|
||||
#define PCIE_DMA_RD_INT_CLEAR 0xac
|
||||
|
||||
#define PCIE_DMA_CHANEL_MAX_NUM 2
|
||||
|
||||
/* Parameters for the waiting for iATU enabled routine */
|
||||
#define LINK_WAIT_IATU_MIN 9000
|
||||
#define LINK_WAIT_IATU_MAX 10000
|
||||
@@ -1330,10 +1332,9 @@ static int rk_pcie_reset_grant_ctrl(struct rk_pcie *rk_pcie,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, int ctr_off)
|
||||
static void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, struct dma_table *cur, int ctr_off)
|
||||
{
|
||||
struct rk_pcie *rk_pcie = dev_get_drvdata(obj->dev);
|
||||
struct dma_table *cur = obj->cur;
|
||||
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_ENB,
|
||||
cur->enb.asdword);
|
||||
@@ -1355,10 +1356,9 @@ static void rk_pcie_start_dma_rd(struct dma_trx_obj *obj, int ctr_off)
|
||||
cur->start.asdword);
|
||||
}
|
||||
|
||||
static void rk_pcie_start_dma_wr(struct dma_trx_obj *obj, int ctr_off)
|
||||
static void rk_pcie_start_dma_wr(struct dma_trx_obj *obj, struct dma_table *cur, int ctr_off)
|
||||
{
|
||||
struct rk_pcie *rk_pcie = dev_get_drvdata(obj->dev);
|
||||
struct dma_table *cur = obj->cur;
|
||||
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_ENB,
|
||||
cur->enb.asdword);
|
||||
@@ -1382,17 +1382,17 @@ static void rk_pcie_start_dma_wr(struct dma_trx_obj *obj, int ctr_off)
|
||||
cur->start.asdword);
|
||||
}
|
||||
|
||||
static void rk_pcie_start_dma_dwc(struct dma_trx_obj *obj)
|
||||
static void rk_pcie_start_dma_dwc(struct dma_trx_obj *obj, struct dma_table *table)
|
||||
{
|
||||
int dir = obj->cur->dir;
|
||||
int chn = obj->cur->chn;
|
||||
int dir = table->dir;
|
||||
int chn = table->chn;
|
||||
|
||||
int ctr_off = PCIE_DMA_OFFSET + chn * 0x200;
|
||||
|
||||
if (dir == DMA_FROM_BUS)
|
||||
rk_pcie_start_dma_rd(obj, ctr_off);
|
||||
rk_pcie_start_dma_rd(obj, table, ctr_off);
|
||||
else if (dir == DMA_TO_BUS)
|
||||
rk_pcie_start_dma_wr(obj, ctr_off);
|
||||
rk_pcie_start_dma_wr(obj, table, ctr_off);
|
||||
}
|
||||
|
||||
static void rk_pcie_config_dma_dwc(struct dma_table *table)
|
||||
@@ -1419,76 +1419,50 @@ static void rk_pcie_config_dma_dwc(struct dma_table *table)
|
||||
table->start.chnl = table->chn;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rk_pcie_handle_dma_interrupt(struct rk_pcie *rk_pcie)
|
||||
{
|
||||
struct dma_trx_obj *obj = rk_pcie->dma_obj;
|
||||
struct dma_table *cur;
|
||||
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
cur = obj->cur;
|
||||
if (!cur) {
|
||||
pr_err("no pcie dma table\n");
|
||||
return;
|
||||
}
|
||||
|
||||
obj->dma_free = true;
|
||||
obj->irq_num++;
|
||||
|
||||
if (cur->dir == DMA_TO_BUS) {
|
||||
if (list_empty(&obj->tbl_list)) {
|
||||
if (obj->dma_free &&
|
||||
obj->loop_count >= obj->loop_count_threshold)
|
||||
complete(&obj->done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t rk_pcie_sys_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct rk_pcie *rk_pcie = arg;
|
||||
u32 chn = 0;
|
||||
u32 chn;
|
||||
union int_status status;
|
||||
union int_clear clears;
|
||||
u32 reg, val;
|
||||
|
||||
status.asdword = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_STATUS);
|
||||
for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) {
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
if (rk_pcie->dma_obj && rk_pcie->dma_obj->cb)
|
||||
rk_pcie->dma_obj->cb(rk_pcie->dma_obj, chn, DMA_TO_BUS);
|
||||
}
|
||||
|
||||
if (rk_pcie->dma_obj && rk_pcie->dma_obj->cur)
|
||||
chn = rk_pcie->dma_obj->cur->chn;
|
||||
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
rk_pcie_handle_dma_interrupt(rk_pcie);
|
||||
}
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
|
||||
}
|
||||
}
|
||||
|
||||
status.asdword = dw_pcie_readl_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_STATUS);
|
||||
for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) {
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
if (rk_pcie->dma_obj && rk_pcie->dma_obj->cb)
|
||||
rk_pcie->dma_obj->cb(rk_pcie->dma_obj, chn, DMA_FROM_BUS);
|
||||
}
|
||||
|
||||
if (status.donesta & BIT(chn)) {
|
||||
clears.doneclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
rk_pcie_handle_dma_interrupt(rk_pcie);
|
||||
}
|
||||
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
if (status.abortsta & BIT(chn)) {
|
||||
dev_err(rk_pcie->pci->dev, "%s, abort\n", __func__);
|
||||
clears.abortclr = 0x1 << chn;
|
||||
dw_pcie_writel_dbi(rk_pcie->pci, PCIE_DMA_OFFSET +
|
||||
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
|
||||
}
|
||||
}
|
||||
|
||||
reg = rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_INTR_STATUS_MISC);
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
#include "pcie-rockchip.h"
|
||||
#include "rockchip-pcie-dma.h"
|
||||
|
||||
static void rk_pcie_start_dma_rk3399(struct dma_trx_obj *obj)
|
||||
static void rk_pcie_start_dma_rk3399(struct dma_trx_obj *obj, struct dma_table *cur)
|
||||
{
|
||||
struct rockchip_pcie *rockchip = dev_get_drvdata(obj->dev);
|
||||
struct dma_table *tbl = obj->cur;
|
||||
struct dma_table *tbl = cur;
|
||||
int chn = tbl->chn;
|
||||
|
||||
rockchip_pcie_write(rockchip, (u32)(tbl->phys_descs & 0xffffffff),
|
||||
|
||||
@@ -154,6 +154,30 @@ static unsigned int rk_pcie_check_sum(unsigned int *src, int size)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int rk_pcie_handle_dma_interrupt(struct dma_trx_obj *obj, u32 chn, enum dma_dir dir)
|
||||
{
|
||||
struct dma_table *cur;
|
||||
|
||||
cur = obj->cur;
|
||||
if (!cur) {
|
||||
pr_err("no pcie dma table\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
obj->dma_free = true;
|
||||
obj->irq_num++;
|
||||
|
||||
if (cur->dir == DMA_TO_BUS) {
|
||||
if (list_empty(&obj->tbl_list)) {
|
||||
if (obj->dma_free &&
|
||||
obj->loop_count >= obj->loop_count_threshold)
|
||||
complete(&obj->done);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk_pcie_prepare_dma(struct dma_trx_obj *obj,
|
||||
unsigned int idx, unsigned int bus_idx,
|
||||
unsigned int local_idx, size_t buf_size,
|
||||
@@ -295,7 +319,7 @@ static void rk_pcie_dma_trx_work(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
reinit_completion(&obj->done);
|
||||
obj->start_dma_func(obj);
|
||||
obj->start_dma_func(obj, table);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,7 +507,7 @@ static void rk_pcie_send_addr_to_remote(struct dma_trx_obj *obj)
|
||||
table->chn = PCIE_DMA_DEFAULT_CHN;
|
||||
obj->config_dma_func(table);
|
||||
obj->cur = table;
|
||||
obj->start_dma_func(obj);
|
||||
obj->start_dma_func(obj, table);
|
||||
}
|
||||
|
||||
static long rk_pcie_misc_ioctl(struct file *filp, unsigned int cmd,
|
||||
@@ -940,8 +964,9 @@ struct dma_trx_obj *rk_pcie_dma_obj_probe(struct device *dev)
|
||||
obj->irq_num = 0;
|
||||
obj->loop_count_threshold = 0;
|
||||
obj->ref_count = 0;
|
||||
obj->version = 0x3;
|
||||
obj->version = 0x4;
|
||||
init_completion(&obj->done);
|
||||
obj->cb = rk_pcie_handle_dma_interrupt;
|
||||
|
||||
mutex_init(&obj->count_mutex);
|
||||
rk_pcie_add_misc(obj);
|
||||
|
||||
@@ -188,8 +188,9 @@ struct dma_trx_obj {
|
||||
unsigned long irq_num;
|
||||
struct dentry *pcie_root;
|
||||
struct pcie_misc_dev *pcie_dev;
|
||||
void (*start_dma_func)(struct dma_trx_obj *obj);
|
||||
void (*start_dma_func)(struct dma_trx_obj *obj, struct dma_table *table);
|
||||
void (*config_dma_func)(struct dma_table *table);
|
||||
int (*cb)(struct dma_trx_obj *obj, u32 chn, enum dma_dir dir);
|
||||
ktime_t begin;
|
||||
ktime_t end;
|
||||
u64 cache_time_total;
|
||||
|
||||
Reference in New Issue
Block a user