Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

#include <dt-bindings/power/raspberrypi-power.h>

#define DMA_SEL_WANTHEAVY (1 << 8)
#define DMA_SEL_ONLYHEAVY (1 << 9)
#define DMA_FLAG_HEAVY (1 << 8)

&soc {
firmware: firmware {
Expand Down Expand Up @@ -95,20 +94,18 @@
};

&rp1_dma {
snps,sel-require = <DMA_SEL_WANTHEAVY DMA_SEL_WANTHEAVY 0 0 0 0 0 0>;
snps,sel-preclude = <0 0 DMA_SEL_ONLYHEAVY DMA_SEL_ONLYHEAVY DMA_SEL_ONLYHEAVY
DMA_SEL_ONLYHEAVY DMA_SEL_ONLYHEAVY DMA_SEL_ONLYHEAVY>;
snps,chan-flags = <DMA_FLAG_HEAVY DMA_FLAG_HEAVY 0 0 0 0 0 0>;
};

pio: &rp1_pio {
dmas = <&rp1_dma (RP1_DMA_PIO_CH0_TX | DMA_SEL_WANTHEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH0_RX | DMA_SEL_WANTHEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH1_TX | DMA_SEL_WANTHEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH1_RX | DMA_SEL_WANTHEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH2_TX | DMA_SEL_WANTHEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH2_RX | DMA_SEL_WANTHEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH3_TX | DMA_SEL_WANTHEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH3_RX | DMA_SEL_WANTHEAVY)>;
dmas = <&rp1_dma (RP1_DMA_PIO_CH0_TX | DMA_FLAG_HEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH0_RX | DMA_FLAG_HEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH1_TX | DMA_FLAG_HEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH1_RX | DMA_FLAG_HEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH2_TX | DMA_FLAG_HEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH2_RX | DMA_FLAG_HEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH3_TX | DMA_FLAG_HEAVY)>,
<&rp1_dma (RP1_DMA_PIO_CH3_RX | DMA_FLAG_HEAVY)>;
status = "okay";
};

Expand Down
80 changes: 53 additions & 27 deletions drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -1499,33 +1499,62 @@ static struct dma_chan *dw_axi_dma_of_xlate(struct of_phandle_args *dma_spec,
{
struct dw_axi_dma *dw = ofdma->of_dma_data;
struct axi_dma_chan *chan;
uint32_t chan_flags_all;
uint32_t busy_channels;
struct dma_chan *dchan;
uint32_t chan_mask = 0;
uint32_t chan_sel;
dma_cap_mask_t mask;
uint32_t chan_mask;
uint32_t chan_sel;
int max_score;
int score;
int i;

/*
* Walk through all channels looking for the best match.
* Starting from 0, choose the first available slave channel which isn't precluded.
*/
chan_sel = dma_spec->args[0];

for (i = 0; i < dw->hdata->nr_channels; i++) {
if (((dw->sel_precluded[i] & chan_sel) == 0) &&
((dw->sel_required[i] & chan_sel) == dw->sel_required[i]))
chan_mask |= (1 << i);
}
for (i = 0; i < dw->hdata->nr_channels; i++)
chan_flags_all |= dw->chan_flags[i];

dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);

dchan = __dma_request_channel(&mask, dw_axi_dma_filter_fn, &chan_mask, ofdma->of_node);
if (!dchan)
return NULL;
chan_sel = dma_spec->args[0];
busy_channels = 0;
dchan = NULL;

while (1) {
max_score = 0;
chan_mask = 0;

for (i = 0; i < dw->hdata->nr_channels; i++) {
if (busy_channels & (1 << i))
continue;
/*
* Positive matches (wanted flags that match) score twice that of
* negetive matches (not wanted flags that are not present).
*/
score = 2 * hweight32(chan_sel & dw->chan_flags[i]) +
1 * hweight32(~chan_sel & ~dw->chan_flags[i] & chan_flags_all);
if (score > max_score) {
max_score = score;
chan_mask = (1 << i);
} else if (score == max_score) {
chan_mask |= (1 << i);
}
}

if (!chan_mask)
return NULL;

dchan = __dma_request_channel(&mask, dw_axi_dma_filter_fn,
&chan_mask, ofdma->of_node);
if (dchan)
break;

/* Repeat, after first marking this group of channels as busy */
busy_channels |= chan_mask;
}

chan = dchan_to_axi_dma_chan(dchan);
chan->hw_handshake_num = (u8)chan_sel;

return dchan;
}

Expand Down Expand Up @@ -1607,17 +1636,14 @@ static int parse_device_properties(struct axi_dma_chip *chip)
}
}

/* sel-require is optional */
memset(chip->dw->sel_required, 0, sizeof(chip->dw->sel_required));
device_property_read_u32_array(dev, "snps,sel-require",
chip->dw->sel_required,
chip->dw->hdata->nr_channels);

/* sel-preclude is optional */
memset(chip->dw->sel_precluded, 0, sizeof(chip->dw->sel_precluded));
device_property_read_u32_array(dev, "snps,sel-preclude",
chip->dw->sel_precluded,
chip->dw->hdata->nr_channels);
/* snps,chan-flags is optional */
memset(chip->dw->chan_flags, 0, sizeof(chip->dw->chan_flags));
if (device_property_read_u32_array(dev, "snps,chan-flags",
chip->dw->chan_flags,
chip->dw->hdata->nr_channels) < 0)
device_property_read_u32_array(dev, "snps,sel-require",
chip->dw->chan_flags,
chip->dw->hdata->nr_channels);

return 0;
}
Expand Down
3 changes: 1 addition & 2 deletions drivers/dma/dw-axi-dmac/dw-axi-dmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ struct dw_axi_dma {
struct dma_device dma;
struct dw_axi_dma_hcfg *hdata;
struct device_dma_parameters dma_parms;
u32 sel_required[DMAC_MAX_CHANNELS];
u32 sel_precluded[DMAC_MAX_CHANNELS];
u32 chan_flags[DMAC_MAX_CHANNELS];

/* channels */
struct axi_dma_chan *chan;
Expand Down
7 changes: 5 additions & 2 deletions drivers/misc/rp1-pio.c
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ static int rp1_pio_sm_config_xfer_internal(struct rp1_pio_client *client, uint s
struct platform_device *pdev = pio->pdev;
struct device *dev = &pdev->dev;
struct dma_slave_config config = {};
struct dma_slave_caps dma_caps;
phys_addr_t fifo_addr;
struct dma_info *dma;
uint32_t dma_mask;
Expand Down Expand Up @@ -676,10 +677,12 @@ static int rp1_pio_sm_config_xfer_internal(struct rp1_pio_client *client, uint s
config.src_addr = fifo_addr;
config.dst_addr = fifo_addr;
config.direction = (dir == RP1_PIO_DIR_TO_SM) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
dma_caps.max_burst = 4;
dma_get_slave_caps(dma->chan, &dma_caps);
if (dir == RP1_PIO_DIR_TO_SM)
config.dst_maxburst = 8;
config.dst_maxburst = dma_caps.max_burst;
else
config.src_maxburst = 8;
config.src_maxburst = dma_caps.max_burst;

ret = dmaengine_slave_config(dma->chan, &config);
if (ret)
Expand Down