From: Amelie Delaunay <amelie.delaunay@foss.st.com>
To: Vinod Koul <vkoul@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Maxime Coquelin <mcoquelin.stm32@gmail.com>,
Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: <dmaengine@vger.kernel.org>,
<linux-stm32@st-md-mailman.stormreply.com>,
<devicetree@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>,
Amelie Delaunay <amelie.delaunay@foss.st.com>
Subject: [PATCH 07/11] dmaengine: stm32-dma3: clamp AXI burst using st,axi-max-burst-len
Date: Thu, 10 Oct 2024 16:27:57 +0200 [thread overview]
Message-ID: <20241010-dma3-mp25-updates-v1-7-adf0633981ea@foss.st.com> (raw)
In-Reply-To: <20241010-dma3-mp25-updates-v1-0-adf0633981ea@foss.st.com>
STM32 DMA3 can be interconnected with AXI3 or AXI4 busses. In case it is
interconnected with AXI3, the maximum burst length supported by AXI3
protocol is 16 beats, which is lower than the maximum burst length
supported by STM32 DMA3. So the programmed burst has to be shortened when
AXI port is used.
Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
---
drivers/dma/stm32/stm32-dma3.c | 47 +++++++++++++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 12 deletions(-)
diff --git a/drivers/dma/stm32/stm32-dma3.c b/drivers/dma/stm32/stm32-dma3.c
index 1467308dd27c4674b13d2740c05087b1338fd91a..e10689038d8269d23c3f38af9b19cad0b6761fe3 100644
--- a/drivers/dma/stm32/stm32-dma3.c
+++ b/drivers/dma/stm32/stm32-dma3.c
@@ -230,6 +230,8 @@ enum stm32_dma3_port_data_width {
#define STM32_DMA3_CFG_SET_BOTH (STM32_DMA3_CFG_SET_DT | STM32_DMA3_CFG_SET_DMA)
#define STM32_DMA3_MAX_BLOCK_SIZE ALIGN_DOWN(CBR1_BNDT, 64)
+#define STM32_DMA3_MAX_BURST_LEN (1 + min_t(u32, FIELD_GET(CTR1_SBL_1, CTR1_SBL_1), \
+ FIELD_GET(CTR1_DBL_1, CTR1_DBL_1)))
#define port_is_ahb(maxdw) ({ typeof(maxdw) (_maxdw) = (maxdw); \
((_maxdw) != DW_INVALID) && ((_maxdw) == DW_32); })
#define port_is_axi(maxdw) ({ typeof(maxdw) (_maxdw) = (maxdw); \
@@ -303,6 +305,7 @@ struct stm32_dma3_ddata {
u32 dma_channels;
u32 dma_requests;
enum stm32_dma3_port_data_width ports_max_dw[2];
+ u32 axi_max_burst_len;
};
static inline struct stm32_dma3_ddata *to_stm32_dma3_ddata(struct stm32_dma3_chan *chan)
@@ -535,7 +538,8 @@ static enum dma_slave_buswidth stm32_dma3_get_max_dw(u32 chan_max_burst,
return 1 << __ffs(len | addr | max_dw);
}
-static u32 stm32_dma3_get_max_burst(u32 len, enum dma_slave_buswidth dw, u32 chan_max_burst)
+static u32 stm32_dma3_get_max_burst(u32 len, enum dma_slave_buswidth dw,
+ u32 chan_max_burst, u32 bus_max_burst)
{
u32 max_burst = chan_max_burst ? chan_max_burst / dw : 1;
@@ -546,8 +550,9 @@ static u32 stm32_dma3_get_max_burst(u32 len, enum dma_slave_buswidth dw, u32 cha
/*
* HW doesn't modify the burst if burst size <= half of the fifo size.
* If len is not a multiple of burst size, last burst is shortened by HW.
+ * Take care of maximum burst supported on interconnect bus.
*/
- return max_burst;
+ return min_t(u32, max_burst, bus_max_burst);
}
static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transfer_direction dir,
@@ -556,6 +561,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
{
struct stm32_dma3_ddata *ddata = to_stm32_dma3_ddata(chan);
struct dma_device dma_device = ddata->dma_dev;
+ u32 src_max_burst = STM32_DMA3_MAX_BURST_LEN, dst_max_burst = STM32_DMA3_MAX_BURST_LEN;
u32 sdw, ddw, sbl_max, dbl_max, tcem, init_dw, init_bl_max;
u32 _ctr1 = 0, _ctr2 = 0;
u32 ch_conf = chan->dt_config.ch_conf;
@@ -596,10 +602,14 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
_ctr1 |= CTR1_SINC;
if (sap)
_ctr1 |= CTR1_SAP;
+ if (port_is_axi(sap_max_dw)) /* AXI - apply axi maximum burst limitation */
+ src_max_burst = ddata->axi_max_burst_len;
if (FIELD_GET(STM32_DMA3_DT_DINC, tr_conf))
_ctr1 |= CTR1_DINC;
if (dap)
_ctr1 |= CTR1_DAP;
+ if (port_is_axi(dap_max_dw)) /* AXI - apply axi maximum burst limitation */
+ dst_max_burst = ddata->axi_max_burst_len;
_ctr2 |= FIELD_PREP(CTR2_REQSEL, chan->dt_config.req_line) & ~CTR2_SWREQ;
if (FIELD_GET(STM32_DMA3_DT_BREQ, tr_conf))
@@ -619,11 +629,12 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
/* Set destination (device) data width and burst */
ddw = min_t(u32, ddw, stm32_dma3_get_max_dw(chan->max_burst, dap_max_dw,
len, dst_addr));
- dbl_max = min_t(u32, dbl_max, stm32_dma3_get_max_burst(len, ddw, chan->max_burst));
+ dbl_max = min_t(u32, dbl_max, stm32_dma3_get_max_burst(len, ddw, chan->max_burst,
+ dst_max_burst));
/* Set source (memory) data width and burst */
sdw = stm32_dma3_get_max_dw(chan->max_burst, sap_max_dw, len, src_addr);
- sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst);
+ sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst, src_max_burst);
if (!!FIELD_GET(STM32_DMA3_DT_NOPACK, tr_conf)) {
sdw = ddw;
sbl_max = dbl_max;
@@ -653,11 +664,12 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
/* Set source (device) data width and burst */
sdw = min_t(u32, sdw, stm32_dma3_get_max_dw(chan->max_burst, sap_max_dw,
len, src_addr));
- sbl_max = min_t(u32, sbl_max, stm32_dma3_get_max_burst(len, sdw, chan->max_burst));
+ sbl_max = min_t(u32, sbl_max, stm32_dma3_get_max_burst(len, sdw, chan->max_burst,
+ src_max_burst));
/* Set destination (memory) data width and burst */
ddw = stm32_dma3_get_max_dw(chan->max_burst, dap_max_dw, len, dst_addr);
- dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst);
+ dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst, dst_max_burst);
if (!!FIELD_GET(STM32_DMA3_DT_NOPACK, tr_conf) ||
((_ctr2 & CTR2_PFREQ) && ddw > sdw)) { /* Packing to wider ddw not supported */
ddw = sdw;
@@ -689,22 +701,24 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf
init_dw = sdw;
init_bl_max = sbl_max;
sdw = stm32_dma3_get_max_dw(chan->max_burst, sap_max_dw, len, src_addr);
- sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst);
+ sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst, src_max_burst);
if (chan->config_set & STM32_DMA3_CFG_SET_DMA) {
sdw = min_t(u32, init_dw, sdw);
- sbl_max = min_t(u32, init_bl_max,
- stm32_dma3_get_max_burst(len, sdw, chan->max_burst));
+ sbl_max = min_t(u32, init_bl_max, stm32_dma3_get_max_burst(len, sdw,
+ chan->max_burst,
+ src_max_burst));
}
/* Set destination (memory) data width and burst */
init_dw = ddw;
init_bl_max = dbl_max;
ddw = stm32_dma3_get_max_dw(chan->max_burst, dap_max_dw, len, dst_addr);
- dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst);
+ dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst, dst_max_burst);
if (chan->config_set & STM32_DMA3_CFG_SET_DMA) {
ddw = min_t(u32, init_dw, ddw);
- dbl_max = min_t(u32, init_bl_max,
- stm32_dma3_get_max_burst(len, ddw, chan->max_burst));
+ dbl_max = min_t(u32, init_bl_max, stm32_dma3_get_max_burst(len, ddw,
+ chan->max_burst,
+ dst_max_burst));
}
_ctr1 |= FIELD_PREP(CTR1_SDW_LOG2, ilog2(sdw));
@@ -1750,6 +1764,15 @@ static int stm32_dma3_probe(struct platform_device *pdev)
else /* Dual master ports */
ddata->ports_max_dw[1] = FIELD_GET(G_M1_DATA_WIDTH_ENC, hwcfgr);
+ /* st,axi-max-burst-len is optional, if not defined, use STM32_DMA3_MAX_BURST_LEN */
+ if (of_property_read_u32(np, "st,axi-max-burst-len", &ddata->axi_max_burst_len))
+ ddata->axi_max_burst_len = STM32_DMA3_MAX_BURST_LEN;
+ else
+ ddata->axi_max_burst_len = min_t(u32, ddata->axi_max_burst_len,
+ STM32_DMA3_MAX_BURST_LEN);
+ dev_dbg(&pdev->dev, "Burst is limited to %u beats through AXI port\n",
+ ddata->axi_max_burst_len);
+
ddata->chans = devm_kcalloc(&pdev->dev, ddata->dma_channels, sizeof(*ddata->chans),
GFP_KERNEL);
if (!ddata->chans) {
--
2.25.1
next prev parent reply other threads:[~2024-10-10 14:31 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-10 14:27 [PATCH 00/11] STM32 DMA3 updates for STM32MP25 Amelie Delaunay
2024-10-10 14:27 ` [PATCH 01/11] dt-bindings: dma: stm32-dma3: prevent packing/unpacking mode Amelie Delaunay
2024-10-10 18:11 ` Rob Herring (Arm)
2024-10-10 14:27 ` [PATCH 02/11] dmaengine: stm32-dma3: prevent pack/unpack thanks to DT configuration Amelie Delaunay
2024-10-10 14:27 ` [PATCH 03/11] dmaengine: stm32-dma3: refactor HW linked-list to optimize memory accesses Amelie Delaunay
2024-10-10 14:27 ` [PATCH 04/11] dt-bindings: dma: stm32-dma3: prevent linked-list refactoring Amelie Delaunay
2024-10-10 18:14 ` Rob Herring
2024-10-11 9:01 ` Amelie Delaunay
2024-10-10 14:27 ` [PATCH 05/11] dmaengine: stm32-dma3: prevent LL refactoring thanks to DT configuration Amelie Delaunay
2024-10-10 14:27 ` [PATCH 06/11] dt-bindings: dma: stm32-dma3: introduce st,axi-max-burst-len property Amelie Delaunay
2024-10-10 18:16 ` Rob Herring
2024-10-11 9:12 ` Amelie Delaunay
2024-10-10 14:27 ` Amelie Delaunay [this message]
2024-10-10 14:27 ` [PATCH 08/11] arm64: dts: st: limit axi burst length in dma nodes of stm32mp25 Amelie Delaunay
2024-10-10 14:27 ` [PATCH 09/11] arm64: dts: st: add DMA support on U(S)ART instances " Amelie Delaunay
2024-10-10 14:28 ` [PATCH 10/11] arm64: dts: st: add DMA support on I2C " Amelie Delaunay
2024-10-10 14:28 ` [PATCH 11/11] arm64: dts: st: add DMA support on SPI " Amelie Delaunay
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241010-dma3-mp25-updates-v1-7-adf0633981ea@foss.st.com \
--to=amelie.delaunay@foss.st.com \
--cc=alexandre.torgue@foss.st.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dmaengine@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-stm32@st-md-mailman.stormreply.com \
--cc=mcoquelin.stm32@gmail.com \
--cc=robh@kernel.org \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).