638 lines
19 KiB
Diff
638 lines
19 KiB
Diff
From 1971e8465456a4775d89de75f54cd646a319adb3 Mon Sep 17 00:00:00 2001
|
|
From: Xiang Xu <xuxiang@eswincomputing.com>
|
|
Date: Tue, 30 Jul 2024 04:54:27 +0000
|
|
Subject: [PATCH 011/128] drivers: dw-axi-dmac: DMA driver changes for EIC7700
|
|
|
|
- Removed cfgr clock as aon dma has separate cfg clk register bit
|
|
while dma0 havn't. Since dma cfg clk is default on we do not
|
|
need to control it
|
|
- Add arst and prst reset control
|
|
- Power on tbu and configure sid from hw init
|
|
|
|
Signed-off-by: Xiang Xu <xuxiang@eswincomputing.com>
|
|
Signed-off-by: Darshan Prajapati <darshan.prajapati@einfochips.com>
|
|
Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela@einfochips.com>
|
|
---
|
|
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 292 +++++++++++++++++-
|
|
drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 28 +-
|
|
2 files changed, 312 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
|
|
index 72fb40de58b3..c0c8763ca453 100644
|
|
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
|
|
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
|
|
@@ -32,6 +32,13 @@
|
|
#include "dw-axi-dmac.h"
|
|
#include "../dmaengine.h"
|
|
#include "../virt-dma.h"
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+#include <linux/iommu.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/bitfield.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/eic7700-sid-cfg.h>
|
|
+#endif
|
|
|
|
/*
|
|
* The set of bus widths supported by the DMA controller. DW AXI DMAC supports
|
|
@@ -51,6 +58,15 @@
|
|
#define AXI_DMA_FLAG_HAS_RESETS BIT(1)
|
|
#define AXI_DMA_FLAG_USE_CFG2 BIT(2)
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+#define AWSMMUSID GENMASK(31, 24) // The sid of write operation
|
|
+#define AWSMMUSSID GENMASK(23, 16) // The ssid of write operation
|
|
+#define ARSMMUSID GENMASK(15, 8) // The sid of read operation
|
|
+#define ARSMMUSSID GENMASK(7, 0) // The ssid of read operation
|
|
+
|
|
+static int eswin_dma_sid_cfg(struct device *dev);
|
|
+#endif
|
|
+
|
|
static inline void
|
|
axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val)
|
|
{
|
|
@@ -98,14 +114,26 @@ static inline void axi_chan_config_write(struct axi_dma_chan *chan,
|
|
config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
|
|
config->src_per << CH_CFG_H_SRC_PER_POS |
|
|
config->dst_per << CH_CFG_H_DST_PER_POS |
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ config->prior << CH_CFG_H_PRIORITY_POS |
|
|
+ 0xF <<CH_CFG_H_SRC_OSR_LMT_POS |
|
|
+ 0xF <<CH_CFG_H_DST_OSR_LMT_POS;
|
|
+#else
|
|
config->prior << CH_CFG_H_PRIORITY_POS;
|
|
+#endif
|
|
} else {
|
|
cfg_lo |= config->src_per << CH_CFG2_L_SRC_PER_POS |
|
|
config->dst_per << CH_CFG2_L_DST_PER_POS;
|
|
cfg_hi = config->tt_fc << CH_CFG2_H_TT_FC_POS |
|
|
config->hs_sel_src << CH_CFG2_H_HS_SEL_SRC_POS |
|
|
config->hs_sel_dst << CH_CFG2_H_HS_SEL_DST_POS |
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ config->prior << CH_CFG2_H_PRIORITY_POS |
|
|
+ 0xF <<CH_CFG2_H_SRC_OSR_LMT_POS |
|
|
+ 0xF <<CH_CFG2_H_DST_OSR_LMT_POS;
|
|
+#else
|
|
config->prior << CH_CFG2_H_PRIORITY_POS;
|
|
+#endif
|
|
}
|
|
axi_chan_iowrite32(chan, CH_CFG_L, cfg_lo);
|
|
axi_chan_iowrite32(chan, CH_CFG_H, cfg_hi);
|
|
@@ -228,6 +256,20 @@ static void axi_dma_hw_init(struct axi_dma_chip *chip)
|
|
ret = dma_set_mask_and_coherent(chip->dev, DMA_BIT_MASK(64));
|
|
if (ret)
|
|
dev_warn(chip->dev, "Unable to set coherent mask\n");
|
|
+
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ if (of_node_name_prefix(chip->dev->of_node, "dma-controller-hsp"))
|
|
+ {
|
|
+ eswin_dma_sid_cfg(chip->dev);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ eic7700_aon_sid_cfg(chip->dev);
|
|
+ }
|
|
+
|
|
+ /* TBU power up */
|
|
+ eic7700_tbu_power(chip->dev, true);
|
|
+#endif
|
|
}
|
|
|
|
static u32 axi_chan_get_xfer_width(struct axi_dma_chan *chan, dma_addr_t src,
|
|
@@ -333,7 +375,12 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
|
|
completed_length = completed_blocks * len;
|
|
bytes = length - completed_length;
|
|
}
|
|
-
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ else
|
|
+ {
|
|
+ bytes = vd_to_axi_desc(vdesc)->length;
|
|
+ }
|
|
+#endif
|
|
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
|
dma_set_residue(txstate, bytes);
|
|
|
|
@@ -455,6 +502,9 @@ static void dma_chan_issue_pending(struct dma_chan *dchan)
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&chan->vc.lock, flags);
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ chan->trigger = true;
|
|
+#endif
|
|
if (vchan_issue_pending(&chan->vc))
|
|
axi_chan_start_first_queued(chan);
|
|
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
|
@@ -575,25 +625,60 @@ static void write_desc_dar(struct axi_dma_hw_desc *desc, dma_addr_t adr)
|
|
desc->lli->dar = cpu_to_le64(adr);
|
|
}
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+static void set_desc_src_master(struct axi_dma_hw_desc *desc, struct axi_dma_chan *chan)
|
|
+#else
|
|
static void set_desc_src_master(struct axi_dma_hw_desc *desc)
|
|
+#endif
|
|
{
|
|
u32 val;
|
|
|
|
/* Select AXI0 for source master */
|
|
val = le32_to_cpu(desc->lli->ctl_lo);
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ if (chan->chip->dw->hdata->nr_masters > 1)
|
|
+ {
|
|
+ if(DMA_DEV_TO_MEM == chan->direction || DMA_DEV_TO_DEV == chan->direction) {
|
|
+ val |= CH_CTL_L_SRC_MAST;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ val &= ~CH_CTL_L_SRC_MAST;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ val &= ~CH_CTL_L_SRC_MAST;
|
|
+#else
|
|
val &= ~CH_CTL_L_SRC_MAST;
|
|
+#endif
|
|
desc->lli->ctl_lo = cpu_to_le32(val);
|
|
}
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+static void set_desc_dest_master(struct axi_dma_hw_desc *hw_desc,
|
|
+ struct axi_dma_chan *chan)
|
|
+#else
|
|
static void set_desc_dest_master(struct axi_dma_hw_desc *hw_desc,
|
|
struct axi_dma_desc *desc)
|
|
+#endif
|
|
{
|
|
u32 val;
|
|
|
|
/* Select AXI1 for source master if available */
|
|
val = le32_to_cpu(hw_desc->lli->ctl_lo);
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ if (chan->chip->dw->hdata->nr_masters > 1)
|
|
+ {
|
|
+ if(DMA_MEM_TO_DEV == chan->direction || DMA_DEV_TO_DEV == chan->direction) {
|
|
+ val |= CH_CTL_L_DST_MAST;
|
|
+ }
|
|
+ else
|
|
+ val &= ~CH_CTL_L_DST_MAST;
|
|
+ }
|
|
+#else
|
|
if (desc->chan->chip->dw->hdata->nr_masters > 1)
|
|
val |= CH_CTL_L_DST_MAST;
|
|
+#endif
|
|
else
|
|
val &= ~CH_CTL_L_DST_MAST;
|
|
|
|
@@ -612,6 +697,10 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|
size_t block_ts;
|
|
u32 ctllo, ctlhi;
|
|
u32 burst_len;
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ u32 src_maxburst;
|
|
+ u32 dst_maxburst;
|
|
+#endif
|
|
|
|
axi_block_ts = chan->chip->dw->hdata->block_size[chan->id];
|
|
|
|
@@ -624,6 +713,11 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|
return -EINVAL;
|
|
}
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ src_maxburst = chan->chip->dw->hdata->max_msize;
|
|
+ dst_maxburst = chan->chip->dw->hdata->max_msize;
|
|
+#endif
|
|
+
|
|
switch (chan->direction) {
|
|
case DMA_MEM_TO_DEV:
|
|
reg_width = __ffs(chan->config.dst_addr_width);
|
|
@@ -632,6 +726,9 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|
mem_width << CH_CTL_L_SRC_WIDTH_POS |
|
|
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS |
|
|
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS;
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ dst_maxburst = chan->config.dst_maxburst;
|
|
+#endif
|
|
block_ts = len >> mem_width;
|
|
break;
|
|
case DMA_DEV_TO_MEM:
|
|
@@ -641,6 +738,9 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|
mem_width << CH_CTL_L_DST_WIDTH_POS |
|
|
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
|
|
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ src_maxburst = chan->config.src_maxburst;
|
|
+#endif
|
|
block_ts = len >> reg_width;
|
|
break;
|
|
default:
|
|
@@ -674,12 +774,27 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan,
|
|
}
|
|
|
|
hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
|
|
-
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ if(is_power_of_2(dst_maxburst) && is_power_of_2(src_maxburst))
|
|
+ {
|
|
+ dst_maxburst = order_base_2(dst_maxburst)? order_base_2(dst_maxburst) - 1 : 0;
|
|
+ src_maxburst = order_base_2(src_maxburst)? order_base_2(src_maxburst) - 1 : 0;
|
|
+ }else
|
|
+ dev_err(chan->chip->dev, "dst_burst or src_burst error!\n");
|
|
+ ctllo |= dst_maxburst << CH_CTL_L_DST_MSIZE_POS |
|
|
+ src_maxburst << CH_CTL_L_SRC_MSIZE_POS;
|
|
+#else
|
|
ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
|
|
- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
|
|
+ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
|
|
+#endif
|
|
hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ set_desc_src_master(hw_desc, chan);
|
|
+ set_desc_dest_master(hw_desc, chan);
|
|
+#else
|
|
set_desc_src_master(hw_desc);
|
|
+#endif
|
|
|
|
hw_desc->len = len;
|
|
return 0;
|
|
@@ -880,6 +995,9 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
|
|
struct axi_dma_hw_desc *hw_desc = NULL;
|
|
struct axi_dma_desc *desc = NULL;
|
|
u32 xfer_width, reg, num;
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ u32 max_burst_len;
|
|
+#endif
|
|
u64 llp = 0;
|
|
u8 lms = 0; /* Select AXI0 master for LLI fetching */
|
|
|
|
@@ -887,6 +1005,12 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
|
|
axi_chan_name(chan), &src_adr, &dst_adr, len, flags);
|
|
|
|
max_block_ts = chan->chip->dw->hdata->block_size[chan->id];
|
|
+
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ max_burst_len = chan->chip->dw->hdata->max_msize;
|
|
+ max_burst_len = order_base_2(max_burst_len)? order_base_2(max_burst_len) - 1 : 0;
|
|
+#endif
|
|
+
|
|
xfer_width = axi_chan_get_xfer_width(chan, src_adr, dst_adr, len);
|
|
num = DIV_ROUND_UP(len, max_block_ts << xfer_width);
|
|
desc = axi_desc_alloc(num);
|
|
@@ -937,17 +1061,26 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
|
|
}
|
|
hw_desc->lli->ctl_hi = cpu_to_le32(reg);
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ reg = (max_burst_len << CH_CTL_L_DST_MSIZE_POS |
|
|
+ max_burst_len << CH_CTL_L_SRC_MSIZE_POS |
|
|
+#else
|
|
reg = (DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
|
|
DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS |
|
|
+#endif
|
|
xfer_width << CH_CTL_L_DST_WIDTH_POS |
|
|
xfer_width << CH_CTL_L_SRC_WIDTH_POS |
|
|
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
|
|
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS);
|
|
hw_desc->lli->ctl_lo = cpu_to_le32(reg);
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ set_desc_src_master(hw_desc, chan);
|
|
+ set_desc_dest_master(hw_desc, chan);
|
|
+#else
|
|
set_desc_src_master(hw_desc);
|
|
set_desc_dest_master(hw_desc, desc);
|
|
-
|
|
+#endif
|
|
hw_desc->len = xfer_len;
|
|
desc->length += hw_desc->len;
|
|
/* update the length and addresses for the next loop cycle */
|
|
@@ -1157,7 +1290,9 @@ static int dma_chan_terminate_all(struct dma_chan *dchan)
|
|
spin_lock_irqsave(&chan->vc.lock, flags);
|
|
|
|
vchan_get_all_descriptors(&chan->vc, &head);
|
|
-
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ chan->trigger = false;
|
|
+#endif
|
|
chan->cyclic = false;
|
|
spin_unlock_irqrestore(&chan->vc.lock, flags);
|
|
|
|
@@ -1246,8 +1381,9 @@ static int axi_dma_suspend(struct axi_dma_chip *chip)
|
|
axi_dma_disable(chip);
|
|
|
|
clk_disable_unprepare(chip->core_clk);
|
|
+#ifndef CONFIG_SOC_SIFIVE_EIC7700
|
|
clk_disable_unprepare(chip->cfgr_clk);
|
|
-
|
|
+#endif
|
|
return 0;
|
|
}
|
|
|
|
@@ -1255,9 +1391,11 @@ static int axi_dma_resume(struct axi_dma_chip *chip)
|
|
{
|
|
int ret;
|
|
|
|
+#ifndef CONFIG_SOC_SIFIVE_EIC7700
|
|
ret = clk_prepare_enable(chip->cfgr_clk);
|
|
if (ret < 0)
|
|
return ret;
|
|
+#endif
|
|
|
|
ret = clk_prepare_enable(chip->core_clk);
|
|
if (ret < 0)
|
|
@@ -1283,6 +1421,43 @@ static int __maybe_unused axi_dma_runtime_resume(struct device *dev)
|
|
return axi_dma_resume(chip);
|
|
}
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+int eic7700_dma_sel_cfg(struct axi_dma_chan *chan, u32 val)
|
|
+{
|
|
+ struct axi_dma_chip *chip = chan->chip;
|
|
+ struct device *dev = chan->chip->dev;
|
|
+ int ret = 0;
|
|
+ struct regmap *regmap;
|
|
+ int dma_sel_reg;
|
|
+ u32 dma_sel = 0;
|
|
+
|
|
+ regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "eswin,syscfg");
|
|
+ if (IS_ERR(regmap)) {
|
|
+ dev_err(dev, "No eswin,syscfg phandle specified\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ ret = of_property_read_u32_index(dev->of_node, "eswin,syscfg", 2,
|
|
+ &dma_sel_reg);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "can't get sid cfg reg offset in sys_con(errno:%d)\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ regmap_read(regmap, dma_sel_reg, &dma_sel);
|
|
+
|
|
+ if (of_node_name_prefix(chip->dev->of_node, "dma-controller-hsp")) {
|
|
+ if (val < 32)
|
|
+ dma_sel &= ~(1 << val);
|
|
+ }
|
|
+ else {
|
|
+ if (val < 32)
|
|
+ dma_sel |= (1 << val);
|
|
+ }
|
|
+ regmap_write(regmap, dma_sel_reg, dma_sel);
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
static struct dma_chan *dw_axi_dma_of_xlate(struct of_phandle_args *dma_spec,
|
|
struct of_dma *ofdma)
|
|
{
|
|
@@ -1296,6 +1471,10 @@ static struct dma_chan *dw_axi_dma_of_xlate(struct of_phandle_args *dma_spec,
|
|
|
|
chan = dchan_to_axi_dma_chan(dchan);
|
|
chan->hw_handshake_num = dma_spec->args[0];
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ if (dma_spec->args_count > 1)
|
|
+ eic7700_dma_sel_cfg(chan, dma_spec->args[1]);
|
|
+#endif
|
|
return dchan;
|
|
}
|
|
|
|
@@ -1366,6 +1545,20 @@ static int parse_device_properties(struct axi_dma_chip *chip)
|
|
chip->dw->hdata->axi_rw_burst_len = tmp;
|
|
}
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ /* max-size is optional property */
|
|
+ ret = device_property_read_u32(dev, "snps,max-msize", &tmp);
|
|
+ if (!ret) {
|
|
+ if (tmp > 1024)
|
|
+ return -EINVAL;
|
|
+ if (tmp < 1)
|
|
+ return -EINVAL;
|
|
+
|
|
+ chip->dw->hdata->max_msize = tmp;
|
|
+ }else
|
|
+ chip->dw->hdata->max_msize = 4;
|
|
+#endif
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1426,10 +1619,31 @@ static int dw_probe(struct platform_device *pdev)
|
|
if (IS_ERR(chip->core_clk))
|
|
return PTR_ERR(chip->core_clk);
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ chip->arst = devm_reset_control_get_optional(&pdev->dev, "arst");
|
|
+ if (IS_ERR_OR_NULL(chip->arst)) {
|
|
+ dev_err(chip->dev, "Failed to get axi reset handle\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ reset_control_deassert(chip->arst);
|
|
+
|
|
+ chip->prst = devm_reset_control_get_optional(&pdev->dev, "prst");
|
|
+ if (IS_ERR_OR_NULL(chip->prst)) {
|
|
+ dev_err(chip->dev, "Failed to get ahb reset handle\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ reset_control_deassert(chip->prst);
|
|
+#endif
|
|
+
|
|
+ /*
|
|
+ For EIC7700 SoC, aon dma has separate cfg clk register bit while dma0 havn't.
|
|
+ Since dma cfg clk is default on, so we don't control it
|
|
+ */
|
|
+#ifndef CONFIG_SOC_SIFIVE_EIC7700
|
|
chip->cfgr_clk = devm_clk_get(chip->dev, "cfgr-clk");
|
|
if (IS_ERR(chip->cfgr_clk))
|
|
return PTR_ERR(chip->cfgr_clk);
|
|
-
|
|
+#endif
|
|
ret = parse_device_properties(chip);
|
|
if (ret)
|
|
return ret;
|
|
@@ -1463,7 +1677,12 @@ static int dw_probe(struct platform_device *pdev)
|
|
dma_cap_set(DMA_CYCLIC, dw->dma.cap_mask);
|
|
|
|
/* DMA capabilities */
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ dw->dma.chancnt = hdata->nr_channels;
|
|
+ dw->dma.max_burst = hdata->max_msize;
|
|
+#else
|
|
dw->dma.max_burst = hdata->axi_rw_burst_len;
|
|
+#endif
|
|
dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS;
|
|
dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS;
|
|
dw->dma.directions = BIT(DMA_MEM_TO_MEM);
|
|
@@ -1533,6 +1752,53 @@ static int dw_probe(struct platform_device *pdev)
|
|
return ret;
|
|
}
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+static int eswin_dma_sid_cfg(struct device *dev)
|
|
+{
|
|
+ int ret;
|
|
+ struct regmap *regmap;
|
|
+ int hsp_mmu_dma_reg;
|
|
+ u32 rdwr_sid_ssid;
|
|
+ u32 sid;
|
|
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
|
|
+
|
|
+ /* not behind smmu, use the default reset value(0x0) of the reg as streamID*/
|
|
+ if (fwspec == NULL) {
|
|
+ dev_dbg(dev, "dev is not behind smmu, skip configuration of sid\n");
|
|
+ return 0;
|
|
+ }
|
|
+ sid = fwspec->ids[0];
|
|
+
|
|
+ regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "eswin,hsp_sp_csr");
|
|
+ if (IS_ERR(regmap)) {
|
|
+ dev_dbg(dev, "No hsp_sp_csr phandle specified\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ret = of_property_read_u32_index(dev->of_node, "eswin,hsp_sp_csr", 1,
|
|
+ &hsp_mmu_dma_reg);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "can't get dma sid cfg reg offset (%d)\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* make the reading sid the same as writing sid, ssid is fixed to zero */
|
|
+ rdwr_sid_ssid = FIELD_PREP(AWSMMUSID, sid);
|
|
+ rdwr_sid_ssid |= FIELD_PREP(ARSMMUSID, sid);
|
|
+ rdwr_sid_ssid |= FIELD_PREP(AWSMMUSSID, 0);
|
|
+ rdwr_sid_ssid |= FIELD_PREP(ARSMMUSSID, 0);
|
|
+ regmap_write(regmap, hsp_mmu_dma_reg, rdwr_sid_ssid);
|
|
+
|
|
+ ret = eic7700_dynm_sid_enable(dev_to_node(dev));
|
|
+ if (ret < 0)
|
|
+ dev_err(dev, "failed to config dma streamID(%d)!\n", sid);
|
|
+ else
|
|
+ dev_dbg(dev, "success to config dma streamID(%d)!\n", sid);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+#endif
|
|
+
|
|
static int dw_remove(struct platform_device *pdev)
|
|
{
|
|
struct axi_dma_chip *chip = platform_get_drvdata(pdev);
|
|
@@ -1541,7 +1807,9 @@ static int dw_remove(struct platform_device *pdev)
|
|
u32 i;
|
|
|
|
/* Enable clk before accessing to registers */
|
|
+#ifndef CONFIG_SOC_SIFIVE_EIC7700
|
|
clk_prepare_enable(chip->cfgr_clk);
|
|
+#endif
|
|
clk_prepare_enable(chip->core_clk);
|
|
axi_dma_irq_disable(chip);
|
|
for (i = 0; i < dw->hdata->nr_channels; i++) {
|
|
@@ -1559,10 +1827,20 @@ static int dw_remove(struct platform_device *pdev)
|
|
|
|
list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
|
|
vc.chan.device_node) {
|
|
+#ifndef CONFIG_SOC_SIFIVE_EIC7700
|
|
list_del(&chan->vc.chan.device_node);
|
|
+#endif
|
|
tasklet_kill(&chan->vc.task);
|
|
}
|
|
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ /* TBU power down before reset */
|
|
+ eic7700_tbu_power(chip->dev, false);
|
|
+
|
|
+ reset_control_assert(chip->arst);
|
|
+ reset_control_assert(chip->prst);
|
|
+#endif
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
|
|
index 8521530a34ec..96f8ea7731de 100644
|
|
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
|
|
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
|
|
@@ -15,7 +15,9 @@
|
|
#include <linux/device.h>
|
|
#include <linux/dmaengine.h>
|
|
#include <linux/types.h>
|
|
-
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+#include <linux/reset.h>
|
|
+#endif
|
|
#include "../virt-dma.h"
|
|
|
|
#define DMAC_MAX_CHANNELS 16
|
|
@@ -30,6 +32,9 @@ struct dw_axi_dma_hcfg {
|
|
u32 priority[DMAC_MAX_CHANNELS];
|
|
/* maximum supported axi burst length */
|
|
u32 axi_rw_burst_len;
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ u32 max_msize;
|
|
+#endif
|
|
/* Register map for DMAX_NUM_CHANNELS <= 8 */
|
|
bool reg_map_8_channels;
|
|
bool restrict_axi_burst_len;
|
|
@@ -52,6 +57,9 @@ struct axi_dma_chan {
|
|
bool cyclic;
|
|
/* these other elements are all protected by vc.lock */
|
|
bool is_paused;
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ bool trigger;
|
|
+#endif
|
|
};
|
|
|
|
struct dw_axi_dma {
|
|
@@ -71,6 +79,10 @@ struct axi_dma_chip {
|
|
struct clk *core_clk;
|
|
struct clk *cfgr_clk;
|
|
struct dw_axi_dma *dw;
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+ struct reset_control *arst;
|
|
+ struct reset_control *prst;
|
|
+#endif
|
|
};
|
|
|
|
/* LLI == Linked List Item */
|
|
@@ -203,7 +215,11 @@ static inline struct axi_dma_chan *dchan_to_axi_dma_chan(struct dma_chan *dchan)
|
|
#define UNUSED_CHANNEL 0x3F /* Set unused DMA channel to 0x3F */
|
|
#define DMA_APB_HS_SEL_BIT_SIZE 0x08 /* HW handshake bits per channel */
|
|
#define DMA_APB_HS_SEL_MASK 0xFF /* HW handshake select masks */
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+#define MAX_BLOCK_SIZE 0x80000 /* 1024 blocks * 512 bytes data width */
|
|
+#else
|
|
#define MAX_BLOCK_SIZE 0x1000 /* 1024 blocks * 4 bytes data width */
|
|
+#endif
|
|
#define DMA_REG_MAP_CH_REF 0x08 /* Channel count to choose register map */
|
|
|
|
/* DMAC_CFG */
|
|
@@ -283,6 +299,10 @@ enum {
|
|
#define CH_CTL_L_SRC_MAST BIT(0)
|
|
|
|
/* CH_CFG_H */
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+#define CH_CFG_H_DST_OSR_LMT_POS 27
|
|
+#define CH_CFG_H_SRC_OSR_LMT_POS 23
|
|
+#endif
|
|
#define CH_CFG_H_PRIORITY_POS 17
|
|
#define CH_CFG_H_DST_PER_POS 12
|
|
#define CH_CFG_H_SRC_PER_POS 7
|
|
@@ -322,7 +342,13 @@ enum {
|
|
#define CH_CFG2_H_TT_FC_POS 0
|
|
#define CH_CFG2_H_HS_SEL_SRC_POS 3
|
|
#define CH_CFG2_H_HS_SEL_DST_POS 4
|
|
+#ifdef CONFIG_SOC_SIFIVE_EIC7700
|
|
+#define CH_CFG2_H_PRIORITY_POS 15
|
|
+#define CH_CFG2_H_SRC_OSR_LMT_POS 23
|
|
+#define CH_CFG2_H_DST_OSR_LMT_POS 27
|
|
+#else
|
|
#define CH_CFG2_H_PRIORITY_POS 20
|
|
+#endif
|
|
|
|
/**
|
|
* DW AXI DMA channel interrupts
|
|
--
|
|
2.47.0
|
|
|