| From e1e2b3504e6b1f083d855dba3c8ff848a80fd93a Mon Sep 17 00:00:00 2001 |
| From: Zhenfang Wang <zhenfang.wang@unisoc.com> |
| Date: Thu, 12 Sep 2019 13:47:18 +0800 |
| Subject: [PATCH] dmaengine: sprd: Fix the link-list pointer register |
| configuration issue |
| |
| commit 8b6bc5fd71e677864d1a3b896b3069a6e0c5e214 upstream. |
| |
| We will set the link-list pointer register point to next link-list |
| configuration's physical address, which can load DMA configuration |
| from the link-list node automatically. |
| |
| But the link-list node's physical address can be larger than 32bits, |
| and now Spreadtrum DMA driver only supports 32bits physical address, |
| which may cause loading a incorrect DMA configuration when starting |
| the link-list transfer mode. According to the DMA datasheet, we can |
| use SRC_BLK_STEP register (bit28 - bit31) to save the high bits of the |
| link-list node's physical address to fix this issue. |
| |
| Fixes: 4ac695464763 ("dmaengine: sprd: Support DMA link-list mode") |
| Signed-off-by: Zhenfang Wang <zhenfang.wang@unisoc.com> |
| Signed-off-by: Baolin Wang <baolin.wang@linaro.org> |
| Link: https://lore.kernel.org/r/eadfe9295499efa003e1c344e67e2890f9d1d780.1568267061.git.baolin.wang@linaro.org |
| Signed-off-by: Vinod Koul <vkoul@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c |
| index 525dc7338fe3..a4a91f233121 100644 |
| --- a/drivers/dma/sprd-dma.c |
| +++ b/drivers/dma/sprd-dma.c |
| @@ -134,6 +134,10 @@ |
| #define SPRD_DMA_SRC_TRSF_STEP_OFFSET 0 |
| #define SPRD_DMA_TRSF_STEP_MASK GENMASK(15, 0) |
| |
| +/* SPRD DMA_SRC_BLK_STEP register definition */ |
| +#define SPRD_DMA_LLIST_HIGH_MASK GENMASK(31, 28) |
| +#define SPRD_DMA_LLIST_HIGH_SHIFT 28 |
| + |
| /* define DMA channel mode & trigger mode mask */ |
| #define SPRD_DMA_CHN_MODE_MASK GENMASK(7, 0) |
| #define SPRD_DMA_TRG_MODE_MASK GENMASK(7, 0) |
| @@ -717,6 +721,7 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, |
| u32 int_mode = flags & SPRD_DMA_INT_MASK; |
| int src_datawidth, dst_datawidth, src_step, dst_step; |
| u32 temp, fix_mode = 0, fix_en = 0; |
| + phys_addr_t llist_ptr; |
| |
| if (dir == DMA_MEM_TO_DEV) { |
| src_step = sprd_dma_get_step(slave_cfg->src_addr_width); |
| @@ -814,13 +819,16 @@ static int sprd_dma_fill_desc(struct dma_chan *chan, |
| * Set the link-list pointer point to next link-list |
| * configuration's physical address. |
| */ |
| - hw->llist_ptr = schan->linklist.phy_addr + temp; |
| + llist_ptr = schan->linklist.phy_addr + temp; |
| + hw->llist_ptr = lower_32_bits(llist_ptr); |
| + hw->src_blk_step = (upper_32_bits(llist_ptr) << SPRD_DMA_LLIST_HIGH_SHIFT) & |
| + SPRD_DMA_LLIST_HIGH_MASK; |
| } else { |
| hw->llist_ptr = 0; |
| + hw->src_blk_step = 0; |
| } |
| |
| hw->frg_step = 0; |
| - hw->src_blk_step = 0; |
| hw->des_blk_step = 0; |
| return 0; |
| } |
| -- |
| 2.7.4 |
| |