kernel/0020-feat-Add-dma-driver.patch

462 lines
16 KiB
Diff

From 08e9577184e3eaa06d7e276047c23bde568988c1 Mon Sep 17 00:00:00 2001
From: xuxiang <xuxiang@eswincomputing.com>
Date: Thu, 23 May 2024 10:01:46 +0800
Subject: [PATCH 020/219] feat:Add dma driver.
Changelogs:
1.Add dma driver for linux-6.6.
---
.../dts/eswin/eswin-win2030-die0-soc.dtsi | 20 ++-
.../dts/eswin/eswin-win2030-die1-soc.dtsi | 10 +-
drivers/clk/eswin/clk-win2030.c | 4 +
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 169 ++++++++++++++++--
drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 5 +-
include/dt-bindings/clock/win2030-clock.h | 2 +
6 files changed, 182 insertions(+), 28 deletions(-)
diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi
index 1e813abf0819..a9f269bd9325 100644
--- a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi
+++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi
@@ -375,13 +375,14 @@ d0_pmu_dsp3: win2030-pmu-controller-port@240 {
};
d0_dmac0: dma-controller-hsp@0x50430000 {
- compatible = "snps,axi-dma-1.01a";
+ compatible = "eswin,eic770x-axi-dma";
reg = <0x0 0x50430000 0x0 0x10000>;
interrupt-parent = <&plic0>;
interrupts = <57>;
#dma-cells = <2>; // change dma-cells value <1> to <2>, to support peripheral selection dma-controller,See the parameter dmas for details;
- clocks = <&d0_clock WIN2030_CLK_HSP_DMA0_CLK>;
- clock-names = "core-clk";
+ clocks = <&d0_clock WIN2030_CLK_HSP_DMA0_CLK>,
+ <&d0_clock WIN2030_CLK_HSP_DMA0_CLK_TEST>;
+ clock-names = "core-clk", "cfgr-clk";
resets = <&d0_reset HSPDMA_RST_CTRL SW_HSP_DMA0_RSTN>,
<&d0_reset HSPDMA_RST_CTRL SW_HSP_DMA_PRSTN>;
reset-names = "arst", "prst";
@@ -401,13 +402,14 @@ d0_dmac0: dma-controller-hsp@0x50430000 {
};
d0_aon_dmac: dma-controller-aon@0x518c0000 {
- compatible = "snps,axi-dma-1.01a";
+ compatible = "eswin,eic770x-axi-dma";
reg = <0x0 0x518c0000 0x0 0x10000>;
interrupt-parent = <&plic0>;
interrupts = <289>;
#dma-cells = <2>; // change dma-cells value <1> to <2>, to support peripheral selection dma-controller,See the parameter dmas for details;
- clocks = <&d0_clock WIN2030_CLK_AONDMA_ACLK>;
- clock-names = "core-clk";
+ clocks = <&d0_clock WIN2030_CLK_AONDMA_ACLK>,
+ <&d0_clock WIN2030_CLK_AONDMA_CFG>;
+ clock-names = "core-clk", "cfgr-clk";
resets = <&d0_reset DMA1_RST_CTRL SW_DMA1_ARSTN>,
<&d0_reset DMA1_RST_CTRL SW_DMA1_HRSTN>;
reset-names = "arst", "prst";
@@ -417,7 +419,7 @@ d0_aon_dmac: dma-controller-aon@0x518c0000 {
snps,data-width = <3>;
snps,block-size = <0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000>;
snps,axi-max-burst-len = <32>;
- snps,max-msize = <64>;
+ // snps,max-msize = <64>;
#size-cells = <2>;
#address-cells = <2>;
dma-ranges = <0x0 0x80000000 0x0 0x80000000 0x100 0x0>;
@@ -806,7 +808,7 @@ msi_ctrl_int : 220
};
ssi0: spi@50810000 {
- compatible = "snps,win2030-spi";
+ compatible = "snps,eic770x-spi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x50810000 0x0 0x4000>;
@@ -826,7 +828,7 @@ ssi0: spi@50810000 {
};
ssi1: spi@50814000 {
- compatible = "snps,win2030-spi";
+ compatible = "snps,eic770x-spi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x50814000 0x0 0x4000>;
diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi
index 5a55de6c7b2a..9e12379cc7d3 100644
--- a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi
+++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi
@@ -323,7 +323,8 @@ d1_dmac0: dma-controller-hsp@0x70430000 {
interrupts = <57>;
#dma-cells = <2>; // change dma-cells value <1> to <2>, to support peripheral selection dma-controller,See the parameter dmas for details;
clocks = <&d1_clock WIN2030_CLK_HSP_DMA0_CLK>;
- clock-names = "core-clk";
+ <&d1_clock WIN2030_CLK_HSP_DMA0_CLK_TEST>;
+ clock-names = "core-clk", "cfgr-clk";
resets = <&d1_reset HSPDMA_RST_CTRL SW_HSP_DMA0_RSTN>,
<&d1_reset HSPDMA_RST_CTRL SW_HSP_DMA_PRSTN>;
reset-names = "arst", "prst";
@@ -348,8 +349,9 @@ d1_aon_dmac: dma-controller-aon@0x718c0000 {
interrupt-parent = <&plic1>;
interrupts = <289>;
#dma-cells = <2>; // change dma-cells value <1> to <2>, to support peripheral selection dma-controller,See the parameter dmas for details;
- clocks = <&d1_clock WIN2030_CLK_AONDMA_ACLK>;
- clock-names = "core-clk";
+ clocks = <&d1_clock WIN2030_CLK_AONDMA_ACLK>,
+ <&d1_clock WIN2030_CLK_AONDMA_CFG>;
+ clock-names = "core-clk", "cfgr-clk";
resets = <&d1_reset DMA1_RST_CTRL SW_DMA1_ARSTN>,
<&d1_reset DMA1_RST_CTRL SW_DMA1_HRSTN>;
reset-names = "arst", "prst";
@@ -1620,7 +1622,7 @@ d1_sdio1: mmc@0x70470000{
};
d1_ssi0: spi1@70810000 {
- compatible = "snps,win2030-spi";
+ compatible = "snps,eic770x-spi";
#address-cells = <2>;
#size-cells = <2>;
reg = <0x0 0x70810000 0x0 0x5000>;
diff --git a/drivers/clk/eswin/clk-win2030.c b/drivers/clk/eswin/clk-win2030.c
index 2ff82f4feba1..64bf0476b4bc 100755
--- a/drivers/clk/eswin/clk-win2030.c
+++ b/drivers/clk/eswin/clk-win2030.c
@@ -906,6 +906,9 @@ static struct eswin_gate_clock win2030_gate_clks[] = {
{ WIN2030_GATE_HSP_SATA_OOB_CLK ,"gate_hsp_sata_oob_clk", "mux_u_sata_phy_2mux1", CLK_SET_RATE_PARENT,
WIN2030_REG_OFFSET_SATA_OOB_CTRL, 31, 0, },
+ { WIN2030_GATE_HSP_DMA0_CLK_TEST ,"gate_hsp_dma0_clk_test", "gate_clk_hsp_aclk", CLK_SET_RATE_PARENT,
+ WIN2030_REG_OFFSET_HSP_ACLK_CTRL, 1, 0, },
+
{ WIN2030_GATE_HSP_DMA0_CLK ,"gate_hsp_dma0_clk", "gate_clk_hsp_aclk", CLK_SET_RATE_PARENT,
WIN2030_REG_OFFSET_HSP_ACLK_CTRL, 0, 0, },
@@ -1110,6 +1113,7 @@ static struct eswin_clock win2030_clks[] = {
{ WIN2030_CLK_VC_MON_PCLK ,"clk_vc_mon_pclk", "gate_vc_mon_pclk", CLK_SET_RATE_PARENT,},
{ WIN2030_CLK_HSP_DMA0_CLK ,"clk_hsp_dma0_clk", "gate_hsp_dma0_clk", CLK_SET_RATE_PARENT,},
+ { WIN2030_CLK_HSP_DMA0_CLK_TEST ,"clk_hsp_dma0_clk_TEST", "gate_hsp_dma0_clk", CLK_SET_RATE_PARENT,},
{ WIN2030_CLK_HSP_RMII_REF_0 ,"clk_hsp_rmii_ref_0", "gate_hsp_rmii_ref_0", CLK_SET_RATE_PARENT,},
{ WIN2030_CLK_HSP_RMII_REF_1 ,"clk_hsp_rmii_ref_1", "gate_hsp_rmii_ref_1", CLK_SET_RATE_PARENT,},
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..dd98cce3dad8 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -28,10 +28,15 @@
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/iommu.h>
#include "dw-axi-dmac.h"
#include "../dmaengine.h"
#include "../virt-dma.h"
+#include <linux/mfd/syscon.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/eswin-win2030-sid-cfg.h>
/*
* The set of bus widths supported by the DMA controller. DW AXI DMAC supports
@@ -50,6 +55,14 @@
#define AXI_DMA_FLAG_HAS_APB_REGS BIT(0)
#define AXI_DMA_FLAG_HAS_RESETS BIT(1)
#define AXI_DMA_FLAG_USE_CFG2 BIT(2)
+#define AXI_DMA_FLAG_HAS_2RESETS BIT(3)
+
+#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);
static inline void
axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val)
@@ -228,6 +241,16 @@ 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");
+
+ if (of_node_name_prefix(chip->dev->of_node, "dma-controller-hsp")) {
+ eswin_dma_sid_cfg(chip->dev);
+ }
+ else {
+ win2030_aon_sid_cfg(chip->dev);
+ }
+
+ /* TBU power up */
+ win2030_tbu_power(chip->dev, true);
}
static u32 axi_chan_get_xfer_width(struct axi_dma_chan *chan, dma_addr_t src,
@@ -575,25 +598,43 @@ static void write_desc_dar(struct axi_dma_hw_desc *desc, dma_addr_t adr)
desc->lli->dar = cpu_to_le64(adr);
}
-static void set_desc_src_master(struct axi_dma_hw_desc *desc)
+static void set_desc_src_master(struct axi_dma_hw_desc *hw_desc,
+ struct axi_dma_chan *chan)
{
u32 val;
/* Select AXI0 for source master */
- val = le32_to_cpu(desc->lli->ctl_lo);
- val &= ~CH_CTL_L_SRC_MAST;
- desc->lli->ctl_lo = cpu_to_le32(val);
+ val = le32_to_cpu(hw_desc->lli->ctl_lo);
+ 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;
+ hw_desc->lli->ctl_lo = cpu_to_le32(val);
}
static void set_desc_dest_master(struct axi_dma_hw_desc *hw_desc,
- struct axi_dma_desc *desc)
+ struct axi_dma_chan *chan)
{
u32 val;
/* Select AXI1 for source master if available */
val = le32_to_cpu(hw_desc->lli->ctl_lo);
- if (desc->chan->chip->dw->hdata->nr_masters > 1)
- val |= CH_CTL_L_DST_MAST;
+ 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
val &= ~CH_CTL_L_DST_MAST;
@@ -676,11 +717,11 @@ 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);
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;
hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
- set_desc_src_master(hw_desc);
-
+ set_desc_src_master(hw_desc, chan);
+ set_desc_dest_master(hw_desc, chan);
hw_desc->len = len;
return 0;
}
@@ -945,8 +986,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan *dchan, dma_addr_t dst_adr,
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS);
hw_desc->lli->ctl_lo = cpu_to_le32(reg);
- set_desc_src_master(hw_desc);
- set_desc_dest_master(hw_desc, desc);
+ set_desc_src_master(hw_desc, chan);
+ set_desc_dest_master(hw_desc, chan);
hw_desc->len = xfer_len;
desc->length += hw_desc->len;
@@ -1283,6 +1324,41 @@ static int __maybe_unused axi_dma_runtime_resume(struct device *dev)
return axi_dma_resume(chip);
}
+int win2030_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;
+}
+
static struct dma_chan *dw_axi_dma_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
@@ -1296,6 +1372,8 @@ 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];
+ if (dma_spec->args_count > 1)
+ win2030_dma_sel_cfg(chan, dma_spec->args[1]);
return dchan;
}
@@ -1419,6 +1497,23 @@ static int dw_probe(struct platform_device *pdev)
if (ret)
return ret;
}
+ if (flags & AXI_DMA_FLAG_HAS_2RESETS) {
+ resets = devm_reset_control_get_optional(&pdev->dev, "arst");
+ if (IS_ERR(resets))
+ return PTR_ERR(resets);
+
+ ret = reset_control_deassert(resets);
+ if (ret)
+ return ret;
+
+ resets = devm_reset_control_get_optional(&pdev->dev, "prst");
+ if (IS_ERR(resets))
+ return PTR_ERR(resets);
+
+ ret = reset_control_deassert(resets);
+ if (ret)
+ return ret;
+ }
chip->dw->hdata->use_cfg2 = !!(flags & AXI_DMA_FLAG_USE_CFG2);
@@ -1533,6 +1628,51 @@ static int dw_probe(struct platform_device *pdev)
return ret;
}
+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 = win2030_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;
+}
+
static int dw_remove(struct platform_device *pdev)
{
struct axi_dma_chip *chip = platform_get_drvdata(pdev);
@@ -1562,6 +1702,8 @@ static int dw_remove(struct platform_device *pdev)
list_del(&chan->vc.chan.device_node);
tasklet_kill(&chan->vc.task);
}
+ /* TBU power down before reset */
+ win2030_tbu_power(chip->dev, false);
return 0;
}
@@ -1579,6 +1721,9 @@ static const struct of_device_id dw_dma_of_id_table[] = {
}, {
.compatible = "starfive,jh7110-axi-dma",
.data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2),
+ }, {
+ .compatible = "eswin,eic770x-axi-dma",
+ .data = (void *)(AXI_DMA_FLAG_HAS_2RESETS | AXI_DMA_FLAG_USE_CFG2),
},
{}
};
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
index 8521530a34ec..cc09abf15aad 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
@@ -203,7 +203,7 @@ 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 */
-#define MAX_BLOCK_SIZE 0x1000 /* 1024 blocks * 4 bytes data width */
+#define MAX_BLOCK_SIZE 0x1000 /* 1024 blocks * 512 bytes data width */
#define DMA_REG_MAP_CH_REF 0x08 /* Channel count to choose register map */
/* DMAC_CFG */
@@ -322,8 +322,7 @@ 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
-#define CH_CFG2_H_PRIORITY_POS 20
-
+#define CH_CFG2_H_PRIORITY_POS 15
/**
* DW AXI DMA channel interrupts
*
diff --git a/include/dt-bindings/clock/win2030-clock.h b/include/dt-bindings/clock/win2030-clock.h
index 6c85b4b980f2..7793f3925932 100755
--- a/include/dt-bindings/clock/win2030-clock.h
+++ b/include/dt-bindings/clock/win2030-clock.h
@@ -378,6 +378,7 @@
#define WIN2030_GATE_VC_VD_PCLK 411
#define WIN2030_GATE_VC_MON_PCLK 412
#define WIN2030_GATE_HSP_DMA0_CLK 413
+#define WIN2030_GATE_HSP_DMA0_CLK_TEST 414
/*fixed factor clocks*/
#define WIN2030_FIXED_FACTOR_U_CPU_DIV2 450
@@ -596,6 +597,7 @@
#define WIN2030_CLK_VC_MON_PCLK 689
#define WIN2030_CLK_HSP_DMA0_CLK 690
+#define WIN2030_CLK_HSP_DMA0_CLK_TEST 691
#define WIN2030_NR_CLKS 700
--
2.47.0