diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi index 2f6e4a569b3e59..52452d0bec59ec 100644 --- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi @@ -2,8 +2,7 @@ #include -#define DMA_SEL_WANTHEAVY (1 << 8) -#define DMA_SEL_ONLYHEAVY (1 << 9) +#define DMA_FLAG_HEAVY (1 << 8) &soc { firmware: firmware { @@ -95,20 +94,18 @@ }; &rp1_dma { - snps,sel-require = ; - 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 = ; }; 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"; }; 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 2e86ee44469081..a82f5ce5e39ff7 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -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; } @@ -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; } diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index 5bf8bc890e6cb8..ab868c16d6b5a5 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -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; diff --git a/drivers/misc/rp1-pio.c b/drivers/misc/rp1-pio.c index 206539fa5f4e06..5758647fc7971c 100644 --- a/drivers/misc/rp1-pio.c +++ b/drivers/misc/rp1-pio.c @@ -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; @@ -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)