Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: DW DMAC: add multi-block property to device tree

Several versions of DW DMAC have multi block transfers hardware
support. Hardware support of multi block transfers is disabled
by default if we use DT to configure DMAC and software emulation
of multi block transfers used instead.
Add multi-block property, so it is possible to enable hardware
multi block transfers (if present) via DT.

Switch from per device is_nollp variable to multi_block array
to be able enable/disable multi block transfers separately per
channel.

Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by

Eugeniy Paltsev and committed by
Vinod Koul
bd2c6636 258f2277

+23 -6
+2
Documentation/devicetree/bindings/dma/snps-dma.txt
··· 27 27 that services interrupts for this device 28 28 - is_private: The device channels should be marked as private and not for by the 29 29 general purpose DMA channel allocator. False if not passed. 30 + - multi-block: Multi block transfers supported by hardware. Array property with 31 + one cell per channel. 0: not supported, 1 (default): supported. 30 32 31 33 Example: 32 34
+1
arch/arc/boot/dts/abilis_tb10x.dtsi
··· 129 129 data-width = <4>; 130 130 clocks = <&ahb_clk>; 131 131 clock-names = "hclk"; 132 + multi-block = <1 1 1 1 1 1>; 132 133 }; 133 134 134 135 i2c0: i2c@FF120000 {
+2
arch/arm/boot/dts/spear13xx.dtsi
··· 118 118 block_size = <0xfff>; 119 119 dma-masters = <2>; 120 120 data-width = <8 8>; 121 + multi-block = <1 1 1 1 1 1 1 1>; 121 122 }; 122 123 123 124 dma@eb000000 { ··· 135 134 chan_priority = <1>; 136 135 block_size = <0xfff>; 137 136 data-width = <8 8>; 137 + multi-block = <1 1 1 1 1 1 1 1>; 138 138 }; 139 139 140 140 fsmc: flash@b0000000 {
+1 -1
drivers/dma/dw/core.c
··· 1569 1569 (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0; 1570 1570 } else { 1571 1571 dwc->block_size = pdata->block_size; 1572 - dwc->nollp = pdata->is_nollp; 1572 + dwc->nollp = !pdata->multi_block[i]; 1573 1573 } 1574 1574 } 1575 1575
+11 -1
drivers/dma/dw/platform.c
··· 102 102 { 103 103 struct device_node *np = pdev->dev.of_node; 104 104 struct dw_dma_platform_data *pdata; 105 - u32 tmp, arr[DW_DMA_MAX_NR_MASTERS]; 105 + u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; 106 106 u32 nr_masters; 107 107 u32 nr_channels; 108 108 ··· 117 117 return NULL; 118 118 119 119 if (of_property_read_u32(np, "dma-channels", &nr_channels)) 120 + return NULL; 121 + if (nr_channels > DW_DMA_MAX_NR_CHANNELS) 120 122 return NULL; 121 123 122 124 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); ··· 152 150 } else if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { 153 151 for (tmp = 0; tmp < nr_masters; tmp++) 154 152 pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); 153 + } 154 + 155 + if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { 156 + for (tmp = 0; tmp < nr_channels; tmp++) 157 + pdata->multi_block[tmp] = mb[tmp]; 158 + } else { 159 + for (tmp = 0; tmp < nr_channels; tmp++) 160 + pdata->multi_block[tmp] = 1; 155 161 } 156 162 157 163 return pdata;
+2 -1
drivers/dma/dw/regs.h
··· 12 12 #include <linux/interrupt.h> 13 13 #include <linux/dmaengine.h> 14 14 15 - #define DW_DMA_MAX_NR_CHANNELS 8 15 + #include "internal.h" 16 + 16 17 #define DW_DMA_MAX_NR_REQUESTS 16 17 18 18 19 /* flow controller */
+1 -1
drivers/tty/serial/8250/8250_lpss.c
··· 157 157 static const struct dw_dma_platform_data qrk_serial_dma_pdata = { 158 158 .nr_channels = 2, 159 159 .is_private = true, 160 - .is_nollp = true, 161 160 .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, 162 161 .chan_priority = CHAN_PRIORITY_ASCENDING, 163 162 .block_size = 4095, 164 163 .nr_masters = 1, 165 164 .data_width = {4}, 165 + .multi_block = {0}, 166 166 }; 167 167 168 168 static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port)
+3 -2
include/linux/platform_data/dma-dw.h
··· 14 14 #include <linux/device.h> 15 15 16 16 #define DW_DMA_MAX_NR_MASTERS 4 17 + #define DW_DMA_MAX_NR_CHANNELS 8 17 18 18 19 /** 19 20 * struct dw_dma_slave - Controller-specific information about a slave ··· 41 40 * @is_private: The device channels should be marked as private and not for 42 41 * by the general purpose DMA channel allocator. 43 42 * @is_memcpy: The device channels do support memory-to-memory transfers. 44 - * @is_nollp: The device channels does not support multi block transfers. 45 43 * @chan_allocation_order: Allocate channels starting from 0 or 7 46 44 * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0. 47 45 * @block_size: Maximum block size supported by the controller 48 46 * @nr_masters: Number of AHB masters supported by the controller 49 47 * @data_width: Maximum data width supported by hardware per AHB master 50 48 * (in bytes, power of 2) 49 + * @multi_block: Multi block transfers supported by hardware per channel. 51 50 */ 52 51 struct dw_dma_platform_data { 53 52 unsigned int nr_channels; 54 53 bool is_private; 55 54 bool is_memcpy; 56 - bool is_nollp; 57 55 #define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */ 58 56 #define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */ 59 57 unsigned char chan_allocation_order; ··· 62 62 unsigned int block_size; 63 63 unsigned char nr_masters; 64 64 unsigned char data_width[DW_DMA_MAX_NR_MASTERS]; 65 + unsigned char multi_block[DW_DMA_MAX_NR_CHANNELS]; 65 66 }; 66 67 67 68 #endif /* _PLATFORM_DATA_DMA_DW_H */