Skip to content

Commit ec31c5c

Browse files
smaeulvinodkoul
authored andcommitted
dmaengine: sun6i: Add support for 34-bit physical addresses
Recent Allwinner SoCs support >4 GiB of DRAM, so those variants of the DMA engine support >32 bit physical addresses. This is accomplished by placing the high bits in the "para" word in the DMA descriptor. DMA descriptors themselves can be located at >32 bit addresses by putting the high bits in the LSBs of the descriptor address register, taking advantage of the required DMA descriptor alignment. However, support for this is not really necessary, so we can avoid the complication by allocating them from the DMA_32 zone. Signed-off-by: Samuel Holland <samuel@sholland.org> Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com> Link: https://lore.kernel.org/r/20220424172759.33383-4-samuel@sholland.org Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 9aa4880 commit ec31c5c

1 file changed

Lines changed: 38 additions & 15 deletions

File tree

drivers/dma/sun6i-dma.c

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@
9090

9191
#define DMA_CHAN_CUR_PARA 0x1c
9292

93+
/*
94+
* LLI address mangling
95+
*
96+
* The LLI link physical address is also mangled, but we avoid dealing
97+
* with that by allocating LLIs from the DMA32 zone.
98+
*/
99+
#define SRC_HIGH_ADDR(x) (((x) & 0x3U) << 16)
100+
#define DST_HIGH_ADDR(x) (((x) & 0x3U) << 18)
93101

94102
/*
95103
* Various hardware related defines
@@ -132,6 +140,7 @@ struct sun6i_dma_config {
132140
u32 dst_burst_lengths;
133141
u32 src_addr_widths;
134142
u32 dst_addr_widths;
143+
bool has_high_addr;
135144
bool has_mbus_clk;
136145
};
137146

@@ -623,6 +632,18 @@ static int set_config(struct sun6i_dma_dev *sdev,
623632
return 0;
624633
}
625634

635+
static inline void sun6i_dma_set_addr(struct sun6i_dma_dev *sdev,
636+
struct sun6i_dma_lli *v_lli,
637+
dma_addr_t src, dma_addr_t dst)
638+
{
639+
v_lli->src = lower_32_bits(src);
640+
v_lli->dst = lower_32_bits(dst);
641+
642+
if (sdev->cfg->has_high_addr)
643+
v_lli->para |= SRC_HIGH_ADDR(upper_32_bits(src)) |
644+
DST_HIGH_ADDR(upper_32_bits(dst));
645+
}
646+
626647
static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
627648
struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
628649
size_t len, unsigned long flags)
@@ -645,16 +666,15 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy(
645666
if (!txd)
646667
return NULL;
647668

648-
v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
669+
v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli);
649670
if (!v_lli) {
650671
dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
651672
goto err_txd_free;
652673
}
653674

654-
v_lli->src = src;
655-
v_lli->dst = dest;
656675
v_lli->len = len;
657676
v_lli->para = NORMAL_WAIT;
677+
sun6i_dma_set_addr(sdev, v_lli, src, dest);
658678

659679
burst = convert_burst(8);
660680
width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES);
@@ -705,16 +725,17 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
705725
return NULL;
706726

707727
for_each_sg(sgl, sg, sg_len, i) {
708-
v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
728+
v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli);
709729
if (!v_lli)
710730
goto err_lli_free;
711731

712732
v_lli->len = sg_dma_len(sg);
713733
v_lli->para = NORMAL_WAIT;
714734

715735
if (dir == DMA_MEM_TO_DEV) {
716-
v_lli->src = sg_dma_address(sg);
717-
v_lli->dst = sconfig->dst_addr;
736+
sun6i_dma_set_addr(sdev, v_lli,
737+
sg_dma_address(sg),
738+
sconfig->dst_addr);
718739
v_lli->cfg = lli_cfg;
719740
sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
720741
sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
@@ -726,8 +747,9 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg(
726747
sg_dma_len(sg), flags);
727748

728749
} else {
729-
v_lli->src = sconfig->src_addr;
730-
v_lli->dst = sg_dma_address(sg);
750+
sun6i_dma_set_addr(sdev, v_lli,
751+
sconfig->src_addr,
752+
sg_dma_address(sg));
731753
v_lli->cfg = lli_cfg;
732754
sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
733755
sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
@@ -786,7 +808,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
786808
return NULL;
787809

788810
for (i = 0; i < periods; i++) {
789-
v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
811+
v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli);
790812
if (!v_lli) {
791813
dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
792814
goto err_lli_free;
@@ -796,14 +818,16 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
796818
v_lli->para = NORMAL_WAIT;
797819

798820
if (dir == DMA_MEM_TO_DEV) {
799-
v_lli->src = buf_addr + period_len * i;
800-
v_lli->dst = sconfig->dst_addr;
821+
sun6i_dma_set_addr(sdev, v_lli,
822+
buf_addr + period_len * i,
823+
sconfig->dst_addr);
801824
v_lli->cfg = lli_cfg;
802825
sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port);
803826
sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE);
804827
} else {
805-
v_lli->src = sconfig->src_addr;
806-
v_lli->dst = buf_addr + period_len * i;
828+
sun6i_dma_set_addr(sdev, v_lli,
829+
sconfig->src_addr,
830+
buf_addr + period_len * i);
807831
v_lli->cfg = lli_cfg;
808832
sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM);
809833
sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE);
@@ -1174,8 +1198,6 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
11741198
};
11751199

11761200
/*
1177-
* TODO: Add support for more than 4g physical addressing.
1178-
*
11791201
* The A100 binding uses the number of dma channels from the
11801202
* device tree node.
11811203
*/
@@ -1194,6 +1216,7 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
11941216
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
11951217
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
11961218
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
1219+
.has_high_addr = true,
11971220
.has_mbus_clk = true,
11981221
};
11991222

0 commit comments

Comments
 (0)