From 4f080c77ec53ec619304c0bbee5f6762fe3207a0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 May 2023 14:55:31 +0200 Subject: [PATCH 01/28] dt-bindings: dma: dma40: Prefer to pass sram through phandle Extend the DMA40 bindings so that we can pass two SRAM segments as phandles instead of directly referring to the memory address in the second reg cell. This enables more granular control over the SRAM, and adds the optiona LCLA SRAM segment as well. Deprecate the old way of passing LCPA as a second reg cell, make sram compulsory. Reviewed-by: Rob Herring Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230417-ux500-dma40-cleanup-v3-1-60bfa6785968@linaro.org Signed-off-by: Vinod Koul --- .../bindings/dma/stericsson,dma40.yaml | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/stericsson,dma40.yaml b/Documentation/devicetree/bindings/dma/stericsson,dma40.yaml index 64845347f44d..1e5752b19a49 100644 --- a/Documentation/devicetree/bindings/dma/stericsson,dma40.yaml +++ b/Documentation/devicetree/bindings/dma/stericsson,dma40.yaml @@ -112,14 +112,23 @@ properties: - const: stericsson,dma40 reg: - items: - - description: DMA40 memory base - - description: LCPA memory base + oneOf: + - items: + - description: DMA40 memory base + - items: + - description: DMA40 memory base + - description: LCPA memory base, deprecated, use eSRAM pool instead + deprecated: true + reg-names: - items: - - const: base - - const: lcpa + oneOf: + - items: + - const: base + - items: + - const: base + - const: lcpa + deprecated: true interrupts: maxItems: 1 @@ -127,6 +136,15 @@ properties: clocks: maxItems: 1 + sram: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: A phandle array with inner size 1 (no arg cells). + First phandle is the LCPA (Logical Channel Parameter Address) memory. + Second phandle is the LCLA (Logical Channel Link base Address) memory. + maxItems: 2 + items: + maxItems: 1 + memcpy-channels: $ref: /schemas/types.yaml#/definitions/uint32-array description: Array of u32 elements indicating which channels on the DMA @@ -138,6 +156,7 @@ required: - reg - interrupts - clocks + - sram - memcpy-channels additionalProperties: false @@ -149,8 +168,9 @@ examples: #include dma-controller@801c0000 { compatible = "stericsson,db8500-dma40", "stericsson,dma40"; - reg = <0x801c0000 0x1000>, <0x40010000 0x800>; - reg-names = "base", "lcpa"; + reg = <0x801c0000 0x1000>; + reg-names = "base"; + sram = <&lcpa>, <&lcla>; interrupts = ; #dma-cells = <3>; memcpy-channels = <56 57 58 59 60>; From 5a1a3b9c19ddeddc6b0c2ea1da7fbe6624c04c7e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 May 2023 14:55:32 +0200 Subject: [PATCH 02/28] dmaengine: ste_dma40: Get LCPA SRAM from SRAM node Instead of passing the reserved SRAM as a "reg" field look for a phandle to the LCPA SRAM memory so we can use the proper SRAM device tree bindings for the SRAM. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230417-ux500-dma40-cleanup-v3-2-60bfa6785968@linaro.org Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 1 + drivers/dma/ste_dma40.c | 47 +++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index f5f422f9b850..644c188d6a11 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -553,6 +553,7 @@ config STE_DMA40 bool "ST-Ericsson DMA40 support" depends on ARCH_U8500 select DMA_ENGINE + select SRAM help Support for ST-Ericsson DMA40 controller diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index f093e08c23b1..7890ccae61f9 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -3506,9 +3507,11 @@ static int __init d40_probe(struct platform_device *pdev) { struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev); struct device_node *np = pdev->dev.of_node; + struct device_node *np_lcpa; int ret = -ENOENT; struct d40_base *base; struct resource *res; + struct resource res_lcpa; int num_reserved_chans; u32 val; @@ -3535,37 +3538,37 @@ static int __init d40_probe(struct platform_device *pdev) spin_lock_init(&base->interrupt_lock); spin_lock_init(&base->execmd_lock); - /* Get IO for logical channel parameter address */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcpa"); - if (!res) { - ret = -ENOENT; - d40_err(&pdev->dev, "No \"lcpa\" memory resource\n"); - goto destroy_cache; + /* Get IO for logical channel parameter address (LCPA) */ + np_lcpa = of_parse_phandle(np, "sram", 0); + if (!np_lcpa) { + dev_err(&pdev->dev, "no LCPA SRAM node\n"); + goto report_failure; } - base->lcpa_size = resource_size(res); - base->phy_lcpa = res->start; - - if (request_mem_region(res->start, resource_size(res), - D40_NAME " I/O lcpa") == NULL) { - ret = -EBUSY; - d40_err(&pdev->dev, "Failed to request LCPA region %pR\n", res); - goto destroy_cache; + /* This is no device so read the address directly from the node */ + ret = of_address_to_resource(np_lcpa, 0, &res_lcpa); + if (ret) { + dev_err(&pdev->dev, "no LCPA SRAM resource\n"); + goto report_failure; } + base->lcpa_size = resource_size(&res_lcpa); + base->phy_lcpa = res_lcpa.start; + dev_info(&pdev->dev, "found LCPA SRAM at 0x%08x, size 0x%08x\n", + (u32)base->phy_lcpa, base->lcpa_size); /* We make use of ESRAM memory for this. */ val = readl(base->virtbase + D40_DREG_LCPA); - if (res->start != val && val != 0) { + if (base->phy_lcpa != val && val != 0) { dev_warn(&pdev->dev, - "[%s] Mismatch LCPA dma 0x%x, def %pa\n", - __func__, val, &res->start); + "[%s] Mismatch LCPA dma 0x%x, def %08x\n", + __func__, val, (u32)base->phy_lcpa); } else - writel(res->start, base->virtbase + D40_DREG_LCPA); + writel(base->phy_lcpa, base->virtbase + D40_DREG_LCPA); - base->lcpa_base = ioremap(res->start, resource_size(res)); + base->lcpa_base = ioremap(base->phy_lcpa, base->lcpa_size); if (!base->lcpa_base) { ret = -ENOMEM; d40_err(&pdev->dev, "Failed to ioremap LCPA region\n"); - goto destroy_cache; + goto release_base; } /* If lcla has to be located in ESRAM we don't need to allocate */ if (base->plat_data->use_esram_lcla) { @@ -3678,9 +3681,7 @@ static int __init d40_probe(struct platform_device *pdev) if (base->lcpa_base) iounmap(base->lcpa_base); - if (base->phy_lcpa) - release_mem_region(base->phy_lcpa, - base->lcpa_size); +release_base: if (base->phy_start) release_mem_region(base->phy_start, base->phy_size); From fb85a8c51784f46b4ddd8bdad3c6bcacd0e5ad2b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 May 2023 14:55:33 +0200 Subject: [PATCH 03/28] dmaengine: ste_dma40: Add dev helper variable The &pdev->dev device pointer is used so many times in the probe() and d40_hw_detect_init() functions that a local *dev variable makes the code way easier to read. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230417-ux500-dma40-cleanup-v3-3-60bfa6785968@linaro.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 50 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 7890ccae61f9..813de4efced5 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -3104,6 +3104,7 @@ static int __init d40_phy_res_init(struct d40_base *base) static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) { struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev); + struct device *dev = &pdev->dev; struct clk *clk; void __iomem *virtbase; struct resource *res; @@ -3117,15 +3118,15 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) u32 cid; u8 rev; - clk = clk_get(&pdev->dev, NULL); + clk = clk_get(dev, NULL); if (IS_ERR(clk)) { - d40_err(&pdev->dev, "No matching clock found\n"); + d40_err(dev, "No matching clock found\n"); goto check_prepare_enabled; } clk_ret = clk_prepare_enable(clk); if (clk_ret) { - d40_err(&pdev->dev, "Failed to prepare/enable clock\n"); + d40_err(dev, "Failed to prepare/enable clock\n"); goto disable_unprepare; } @@ -3151,11 +3152,11 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) & 255) << (i * 8); if (cid != AMBA_CID) { - d40_err(&pdev->dev, "Unknown hardware! No PrimeCell ID\n"); + d40_err(dev, "Unknown hardware! No PrimeCell ID\n"); goto unmap_io; } if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) { - d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n", + d40_err(dev, "Unknown designer! Got %x wanted %x\n", AMBA_MANF_BITS(pid), AMBA_VENDOR_ST); goto unmap_io; @@ -3171,7 +3172,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) */ rev = AMBA_REV_BITS(pid); if (rev < 2) { - d40_err(&pdev->dev, "hardware revision: %d is not supported", rev); + d40_err(dev, "hardware revision: %d is not supported", rev); goto unmap_io; } @@ -3189,7 +3190,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) num_log_chans = num_phy_chans * D40_MAX_LOG_CHAN_PER_PHY; - dev_info(&pdev->dev, + dev_info(dev, "hardware rev: %d @ %pa with %d physical and %d logical channels\n", rev, &res->start, num_phy_chans, num_log_chans); @@ -3209,7 +3210,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) base->phy_size = resource_size(res); base->virtbase = virtbase; base->plat_data = plat_data; - base->dev = &pdev->dev; + base->dev = dev; base->phy_chans = ((void *)base) + ALIGN(sizeof(struct d40_base), 4); base->log_chans = &base->phy_chans[num_phy_chans]; @@ -3505,7 +3506,8 @@ static int __init d40_of_probe(struct platform_device *pdev, static int __init d40_probe(struct platform_device *pdev) { - struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev); + struct device *dev = &pdev->dev; + struct stedma40_platform_data *plat_data = dev_get_platdata(dev); struct device_node *np = pdev->dev.of_node; struct device_node *np_lcpa; int ret = -ENOENT; @@ -3522,7 +3524,7 @@ static int __init d40_probe(struct platform_device *pdev) goto report_failure; } } else { - d40_err(&pdev->dev, "No pdata or Device Tree provided\n"); + d40_err(dev, "No pdata or Device Tree provided\n"); goto report_failure; } } @@ -3541,24 +3543,24 @@ static int __init d40_probe(struct platform_device *pdev) /* Get IO for logical channel parameter address (LCPA) */ np_lcpa = of_parse_phandle(np, "sram", 0); if (!np_lcpa) { - dev_err(&pdev->dev, "no LCPA SRAM node\n"); + dev_err(dev, "no LCPA SRAM node\n"); goto report_failure; } /* This is no device so read the address directly from the node */ ret = of_address_to_resource(np_lcpa, 0, &res_lcpa); if (ret) { - dev_err(&pdev->dev, "no LCPA SRAM resource\n"); + dev_err(dev, "no LCPA SRAM resource\n"); goto report_failure; } base->lcpa_size = resource_size(&res_lcpa); base->phy_lcpa = res_lcpa.start; - dev_info(&pdev->dev, "found LCPA SRAM at 0x%08x, size 0x%08x\n", + dev_info(dev, "found LCPA SRAM at 0x%08x, size 0x%08x\n", (u32)base->phy_lcpa, base->lcpa_size); /* We make use of ESRAM memory for this. */ val = readl(base->virtbase + D40_DREG_LCPA); if (base->phy_lcpa != val && val != 0) { - dev_warn(&pdev->dev, + dev_warn(dev, "[%s] Mismatch LCPA dma 0x%x, def %08x\n", __func__, val, (u32)base->phy_lcpa); } else @@ -3567,7 +3569,7 @@ static int __init d40_probe(struct platform_device *pdev) base->lcpa_base = ioremap(base->phy_lcpa, base->lcpa_size); if (!base->lcpa_base) { ret = -ENOMEM; - d40_err(&pdev->dev, "Failed to ioremap LCPA region\n"); + d40_err(dev, "Failed to ioremap LCPA region\n"); goto release_base; } /* If lcla has to be located in ESRAM we don't need to allocate */ @@ -3576,7 +3578,7 @@ static int __init d40_probe(struct platform_device *pdev) "lcla_esram"); if (!res) { ret = -ENOENT; - d40_err(&pdev->dev, + d40_err(dev, "No \"lcla_esram\" memory resource\n"); goto destroy_cache; } @@ -3584,7 +3586,7 @@ static int __init d40_probe(struct platform_device *pdev) resource_size(res)); if (!base->lcla_pool.base) { ret = -ENOMEM; - d40_err(&pdev->dev, "Failed to ioremap LCLA region\n"); + d40_err(dev, "Failed to ioremap LCLA region\n"); goto destroy_cache; } writel(res->start, base->virtbase + D40_DREG_LCLA); @@ -3592,7 +3594,7 @@ static int __init d40_probe(struct platform_device *pdev) } else { ret = d40_lcla_allocate(base); if (ret) { - d40_err(&pdev->dev, "Failed to allocate LCLA area\n"); + d40_err(dev, "Failed to allocate LCLA area\n"); goto destroy_cache; } } @@ -3603,7 +3605,7 @@ static int __init d40_probe(struct platform_device *pdev) ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base); if (ret) { - d40_err(&pdev->dev, "No IRQ defined\n"); + d40_err(dev, "No IRQ defined\n"); goto destroy_cache; } @@ -3611,7 +3613,7 @@ static int __init d40_probe(struct platform_device *pdev) base->lcpa_regulator = regulator_get(base->dev, "lcla_esram"); if (IS_ERR(base->lcpa_regulator)) { - d40_err(&pdev->dev, "Failed to get lcpa_regulator\n"); + d40_err(dev, "Failed to get lcpa_regulator\n"); ret = PTR_ERR(base->lcpa_regulator); base->lcpa_regulator = NULL; goto destroy_cache; @@ -3619,7 +3621,7 @@ static int __init d40_probe(struct platform_device *pdev) ret = regulator_enable(base->lcpa_regulator); if (ret) { - d40_err(&pdev->dev, + d40_err(dev, "Failed to enable lcpa_regulator\n"); regulator_put(base->lcpa_regulator); base->lcpa_regulator = NULL; @@ -3642,7 +3644,7 @@ static int __init d40_probe(struct platform_device *pdev) ret = dma_set_max_seg_size(base->dev, STEDMA40_MAX_SEG_SIZE); if (ret) { - d40_err(&pdev->dev, "Failed to set dma max seg size\n"); + d40_err(dev, "Failed to set dma max seg size\n"); goto destroy_cache; } @@ -3651,7 +3653,7 @@ static int __init d40_probe(struct platform_device *pdev) if (np) { ret = of_dma_controller_register(np, d40_xlate, NULL); if (ret) - dev_err(&pdev->dev, + dev_err(dev, "could not register of_dma_controller\n"); } @@ -3701,7 +3703,7 @@ release_base: kfree(base->phy_res); kfree(base); report_failure: - d40_err(&pdev->dev, "probe failed\n"); + d40_err(dev, "probe failed\n"); return ret; } From 42ae6f1695beed57958e7a2554e6d52dddc56e43 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 May 2023 14:55:34 +0200 Subject: [PATCH 04/28] dmaengine: ste_dma40: Remove platform data The Ux500 is device tree-only since ages. Delete the platform data header and push it into or next to the driver instead. Drop the non-DT probe path since this will not happen. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230417-ux500-dma40-cleanup-v3-4-60bfa6785968@linaro.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 56 ++++++---- .../dma/ste_dma40.h | 101 +----------------- drivers/dma/ste_dma40_ll.c | 3 +- 3 files changed, 41 insertions(+), 119 deletions(-) rename include/linux/platform_data/dma-ste-dma40.h => drivers/dma/ste_dma40.h (51%) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 813de4efced5..48c9606cfd46 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -23,11 +23,39 @@ #include #include #include -#include #include "dmaengine.h" +#include "ste_dma40.h" #include "ste_dma40_ll.h" +/** + * struct stedma40_platform_data - Configuration struct for the dma device. + * + * @dev_tx: mapping between destination event line and io address + * @dev_rx: mapping between source event line and io address + * @disabled_channels: A vector, ending with -1, that marks physical channels + * that are for different reasons not available for the driver. + * @soft_lli_chans: A vector, that marks physical channels will use LLI by SW + * which avoids HW bug that exists in some versions of the controller. + * SoftLLI introduces relink overhead that could impact performace for + * certain use cases. + * @num_of_soft_lli_chans: The number of channels that needs to be configured + * to use SoftLLI. + * @use_esram_lcla: flag for mapping the lcla into esram region + * @num_of_memcpy_chans: The number of channels reserved for memcpy. + * @num_of_phy_chans: The number of physical channels implemented in HW. + * 0 means reading the number of channels from DMA HW but this is only valid + * for 'multiple of 4' channels, like 8. + */ +struct stedma40_platform_data { + int disabled_channels[STEDMA40_MAX_PHYS]; + int *soft_lli_chans; + int num_of_soft_lli_chans; + bool use_esram_lcla; + int num_of_memcpy_chans; + int num_of_phy_chans; +}; + #define D40_NAME "dma40" #define D40_PHY_CHAN -1 @@ -2269,7 +2297,7 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, return NULL; } -bool stedma40_filter(struct dma_chan *chan, void *data) +static bool stedma40_filter(struct dma_chan *chan, void *data) { struct stedma40_chan_cfg *info = data; struct d40_chan *d40c = @@ -2288,7 +2316,6 @@ bool stedma40_filter(struct dma_chan *chan, void *data) return err == 0; } -EXPORT_SYMBOL(stedma40_filter); static void __d40_set_prio_rt(struct d40_chan *d40c, int dev_type, bool src) { @@ -3517,16 +3544,9 @@ static int __init d40_probe(struct platform_device *pdev) int num_reserved_chans; u32 val; - if (!plat_data) { - if (np) { - if (d40_of_probe(pdev, np)) { - ret = -ENOMEM; - goto report_failure; - } - } else { - d40_err(dev, "No pdata or Device Tree provided\n"); - goto report_failure; - } + if (d40_of_probe(pdev, np)) { + ret = -ENOMEM; + goto report_failure; } base = d40_hw_detect_init(pdev); @@ -3650,11 +3670,11 @@ static int __init d40_probe(struct platform_device *pdev) d40_hw_init(base); - if (np) { - ret = of_dma_controller_register(np, d40_xlate, NULL); - if (ret) - dev_err(dev, - "could not register of_dma_controller\n"); + ret = of_dma_controller_register(np, d40_xlate, NULL); + if (ret) { + dev_err(dev, + "could not register of_dma_controller\n"); + goto destroy_cache; } dev_info(base->dev, "initialized\n"); diff --git a/include/linux/platform_data/dma-ste-dma40.h b/drivers/dma/ste_dma40.h similarity index 51% rename from include/linux/platform_data/dma-ste-dma40.h rename to drivers/dma/ste_dma40.h index 10641633facc..c697bfe16a01 100644 --- a/include/linux/platform_data/dma-ste-dma40.h +++ b/drivers/dma/ste_dma40.h @@ -1,19 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) ST-Ericsson SA 2007-2010 - * Author: Per Forlin for ST-Ericsson - * Author: Jonas Aaberg for ST-Ericsson - */ - #ifndef STE_DMA40_H #define STE_DMA40_H -#include -#include -#include -#include - /* * Maxium size for a single dma descriptor * Size is limited to 16 bits. @@ -118,92 +107,4 @@ struct stedma40_chan_cfg { int phy_channel; }; -/** - * struct stedma40_platform_data - Configuration struct for the dma device. - * - * @dev_tx: mapping between destination event line and io address - * @dev_rx: mapping between source event line and io address - * @disabled_channels: A vector, ending with -1, that marks physical channels - * that are for different reasons not available for the driver. - * @soft_lli_chans: A vector, that marks physical channels will use LLI by SW - * which avoids HW bug that exists in some versions of the controller. - * SoftLLI introduces relink overhead that could impact performace for - * certain use cases. - * @num_of_soft_lli_chans: The number of channels that needs to be configured - * to use SoftLLI. - * @use_esram_lcla: flag for mapping the lcla into esram region - * @num_of_memcpy_chans: The number of channels reserved for memcpy. - * @num_of_phy_chans: The number of physical channels implemented in HW. - * 0 means reading the number of channels from DMA HW but this is only valid - * for 'multiple of 4' channels, like 8. - */ -struct stedma40_platform_data { - int disabled_channels[STEDMA40_MAX_PHYS]; - int *soft_lli_chans; - int num_of_soft_lli_chans; - bool use_esram_lcla; - int num_of_memcpy_chans; - int num_of_phy_chans; -}; - -#ifdef CONFIG_STE_DMA40 - -/** - * stedma40_filter() - Provides stedma40_chan_cfg to the - * ste_dma40 dma driver via the dmaengine framework. - * does some checking of what's provided. - * - * Never directly called by client. It used by dmaengine. - * @chan: dmaengine handle. - * @data: Must be of type: struct stedma40_chan_cfg and is - * the configuration of the framework. - * - * - */ - -bool stedma40_filter(struct dma_chan *chan, void *data); - -/** - * stedma40_slave_mem() - Transfers a raw data buffer to or from a slave - * (=device) - * - * @chan: dmaengine handle - * @addr: source or destination physicall address. - * @size: bytes to transfer - * @direction: direction of transfer - * @flags: is actually enum dma_ctrl_flags. See dmaengine.h - */ - -static inline struct -dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan, - dma_addr_t addr, - unsigned int size, - enum dma_transfer_direction direction, - unsigned long flags) -{ - struct scatterlist sg; - sg_init_table(&sg, 1); - sg.dma_address = addr; - sg.length = size; - - return dmaengine_prep_slave_sg(chan, &sg, 1, direction, flags); -} - -#else -static inline bool stedma40_filter(struct dma_chan *chan, void *data) -{ - return false; -} - -static inline struct -dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan, - dma_addr_t addr, - unsigned int size, - enum dma_transfer_direction direction, - unsigned long flags) -{ - return NULL; -} -#endif - -#endif +#endif /* STE_DMA40_H */ diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index b5287c661eb7..4c489b126cb2 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -6,8 +6,9 @@ */ #include -#include +#include +#include "ste_dma40.h" #include "ste_dma40_ll.h" static u8 d40_width_to_bits(enum dma_slave_buswidth width) From e59d81e9173ae4b5037a81a08b1c5a6915b333e3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 May 2023 14:55:35 +0200 Subject: [PATCH 05/28] dmaengine: ste_dma40: Pass dev to OF function The OF platform data population function only wants to use struct device *dev, so pass that instead. This change makes the compiler realize that the local platform data variable is unused, so drop that too. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230417-ux500-dma40-cleanup-v3-5-60bfa6785968@linaro.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 48c9606cfd46..87f57457e4d9 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -3480,14 +3480,14 @@ static int __init d40_lcla_allocate(struct d40_base *base) return ret; } -static int __init d40_of_probe(struct platform_device *pdev, +static int __init d40_of_probe(struct device *dev, struct device_node *np) { struct stedma40_platform_data *pdata; int num_phy = 0, num_memcpy = 0, num_disabled = 0; const __be32 *list; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; @@ -3500,7 +3500,7 @@ static int __init d40_of_probe(struct platform_device *pdev, num_memcpy /= sizeof(*list); if (num_memcpy > D40_MEMCPY_MAX_CHANS || num_memcpy <= 0) { - d40_err(&pdev->dev, + d40_err(dev, "Invalid number of memcpy channels specified (%d)\n", num_memcpy); return -EINVAL; @@ -3515,7 +3515,7 @@ static int __init d40_of_probe(struct platform_device *pdev, num_disabled /= sizeof(*list); if (num_disabled >= STEDMA40_MAX_PHYS || num_disabled < 0) { - d40_err(&pdev->dev, + d40_err(dev, "Invalid number of disabled channels specified (%d)\n", num_disabled); return -EINVAL; @@ -3526,7 +3526,7 @@ static int __init d40_of_probe(struct platform_device *pdev, num_disabled); pdata->disabled_channels[num_disabled] = -1; - pdev->dev.platform_data = pdata; + dev->platform_data = pdata; return 0; } @@ -3534,7 +3534,6 @@ static int __init d40_of_probe(struct platform_device *pdev, static int __init d40_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct stedma40_platform_data *plat_data = dev_get_platdata(dev); struct device_node *np = pdev->dev.of_node; struct device_node *np_lcpa; int ret = -ENOENT; @@ -3544,7 +3543,7 @@ static int __init d40_probe(struct platform_device *pdev) int num_reserved_chans; u32 val; - if (d40_of_probe(pdev, np)) { + if (d40_of_probe(dev, np)) { ret = -ENOMEM; goto report_failure; } From 339f5041089a22646372d3ebdeec94c25e8d4e29 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 May 2023 14:55:36 +0200 Subject: [PATCH 06/28] dmaengine: ste_dma40: Use managed resources This switches the DMA40 driver to use a bunch of managed resources and strip down the errorpath. The result is pretty neat and makes the driver way more readable. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230417-ux500-dma40-cleanup-v3-6-60bfa6785968@linaro.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 180 ++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 119 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 87f57457e4d9..313baf316f13 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -554,8 +554,6 @@ struct d40_gen_dmac { * @virtbase: The virtual base address of the DMA's register. * @rev: silicon revision detected. * @clk: Pointer to the DMA clock structure. - * @phy_start: Physical memory start of the DMA registers. - * @phy_size: Size of the DMA register map. * @irq: The IRQ number. * @num_memcpy_chans: The number of channels used for memcpy (mem-to-mem * transfers). @@ -599,8 +597,6 @@ struct d40_base { void __iomem *virtbase; u8 rev:4; struct clk *clk; - phys_addr_t phy_start; - resource_size_t phy_size; int irq; int num_memcpy_chans; int num_phy_chans; @@ -3128,65 +3124,58 @@ static int __init d40_phy_res_init(struct d40_base *base) return num_phy_chans_avail; } +/* Called from the registered devm action */ +static void d40_drop_kmem_cache_action(void *d) +{ + struct kmem_cache *desc_slab = d; + + kmem_cache_destroy(desc_slab); +} + static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) { struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct clk *clk; void __iomem *virtbase; - struct resource *res; struct d40_base *base; int num_log_chans; int num_phy_chans; int num_memcpy_chans; - int clk_ret = -EINVAL; int i; u32 pid; u32 cid; u8 rev; + int ret; - clk = clk_get(dev, NULL); - if (IS_ERR(clk)) { - d40_err(dev, "No matching clock found\n"); - goto check_prepare_enabled; - } - - clk_ret = clk_prepare_enable(clk); - if (clk_ret) { - d40_err(dev, "Failed to prepare/enable clock\n"); - goto disable_unprepare; - } + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return NULL; /* Get IO for DMAC base address */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base"); - if (!res) - goto disable_unprepare; - - if (request_mem_region(res->start, resource_size(res), - D40_NAME " I/O base") == NULL) - goto release_region; - - virtbase = ioremap(res->start, resource_size(res)); - if (!virtbase) - goto release_region; + virtbase = devm_platform_ioremap_resource_byname(pdev, "base"); + if (IS_ERR(virtbase)) { + dev_err(dev, "No IO base defined\n"); + return NULL; + } /* This is just a regular AMBA PrimeCell ID actually */ for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(virtbase + resource_size(res) - 0x20 + 4 * i) + pid |= (readl(virtbase + SZ_4K - 0x20 + 4 * i) & 255) << (i * 8); for (cid = 0, i = 0; i < 4; i++) - cid |= (readl(virtbase + resource_size(res) - 0x10 + 4 * i) + cid |= (readl(virtbase + SZ_4K - 0x10 + 4 * i) & 255) << (i * 8); if (cid != AMBA_CID) { d40_err(dev, "Unknown hardware! No PrimeCell ID\n"); - goto unmap_io; + return NULL; } if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) { d40_err(dev, "Unknown designer! Got %x wanted %x\n", AMBA_MANF_BITS(pid), AMBA_VENDOR_ST); - goto unmap_io; + return NULL; } /* * HW revision: @@ -3200,7 +3189,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) rev = AMBA_REV_BITS(pid); if (rev < 2) { d40_err(dev, "hardware revision: %d is not supported", rev); - goto unmap_io; + return NULL; } /* The number of physical channels on this HW */ @@ -3218,23 +3207,22 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) num_log_chans = num_phy_chans * D40_MAX_LOG_CHAN_PER_PHY; dev_info(dev, - "hardware rev: %d @ %pa with %d physical and %d logical channels\n", - rev, &res->start, num_phy_chans, num_log_chans); + "hardware rev: %d with %d physical and %d logical channels\n", + rev, num_phy_chans, num_log_chans); - base = kzalloc(ALIGN(sizeof(struct d40_base), 4) + - (num_phy_chans + num_log_chans + num_memcpy_chans) * - sizeof(struct d40_chan), GFP_KERNEL); + base = devm_kzalloc(dev, + ALIGN(sizeof(struct d40_base), 4) + + (num_phy_chans + num_log_chans + num_memcpy_chans) * + sizeof(struct d40_chan), GFP_KERNEL); - if (base == NULL) - goto unmap_io; + if (!base) + return NULL; base->rev = rev; base->clk = clk; base->num_memcpy_chans = num_memcpy_chans; base->num_phy_chans = num_phy_chans; base->num_log_chans = num_log_chans; - base->phy_start = res->start; - base->phy_size = resource_size(res); base->virtbase = virtbase; base->plat_data = plat_data; base->dev = dev; @@ -3271,76 +3259,55 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) base->gen_dmac.init_reg_size = ARRAY_SIZE(dma_init_reg_v4a); } - base->phy_res = kcalloc(num_phy_chans, - sizeof(*base->phy_res), - GFP_KERNEL); + base->phy_res = devm_kcalloc(dev, num_phy_chans, + sizeof(*base->phy_res), + GFP_KERNEL); if (!base->phy_res) - goto free_base; + return NULL; - base->lookup_phy_chans = kcalloc(num_phy_chans, - sizeof(*base->lookup_phy_chans), - GFP_KERNEL); + base->lookup_phy_chans = devm_kcalloc(dev, num_phy_chans, + sizeof(*base->lookup_phy_chans), + GFP_KERNEL); if (!base->lookup_phy_chans) - goto free_phy_res; + return NULL; - base->lookup_log_chans = kcalloc(num_log_chans, - sizeof(*base->lookup_log_chans), - GFP_KERNEL); + base->lookup_log_chans = devm_kcalloc(dev, num_log_chans, + sizeof(*base->lookup_log_chans), + GFP_KERNEL); if (!base->lookup_log_chans) - goto free_phy_chans; + return NULL; - base->reg_val_backup_chan = kmalloc_array(base->num_phy_chans, + base->reg_val_backup_chan = devm_kmalloc_array(dev, base->num_phy_chans, sizeof(d40_backup_regs_chan), GFP_KERNEL); if (!base->reg_val_backup_chan) - goto free_log_chans; + return NULL; - base->lcla_pool.alloc_map = kcalloc(num_phy_chans + base->lcla_pool.alloc_map = devm_kcalloc(dev, num_phy_chans * D40_LCLA_LINK_PER_EVENT_GRP, sizeof(*base->lcla_pool.alloc_map), GFP_KERNEL); if (!base->lcla_pool.alloc_map) - goto free_backup_chan; + return NULL; - base->regs_interrupt = kmalloc_array(base->gen_dmac.il_size, + base->regs_interrupt = devm_kmalloc_array(dev, base->gen_dmac.il_size, sizeof(*base->regs_interrupt), GFP_KERNEL); if (!base->regs_interrupt) - goto free_map; + return NULL; base->desc_slab = kmem_cache_create(D40_NAME, sizeof(struct d40_desc), 0, SLAB_HWCACHE_ALIGN, NULL); - if (base->desc_slab == NULL) - goto free_regs; + if (!base->desc_slab) + return NULL; + ret = devm_add_action_or_reset(dev, d40_drop_kmem_cache_action, + base->desc_slab); + if (ret) + return NULL; return base; - free_regs: - kfree(base->regs_interrupt); - free_map: - kfree(base->lcla_pool.alloc_map); - free_backup_chan: - kfree(base->reg_val_backup_chan); - free_log_chans: - kfree(base->lookup_log_chans); - free_phy_chans: - kfree(base->lookup_phy_chans); - free_phy_res: - kfree(base->phy_res); - free_base: - kfree(base); - unmap_io: - iounmap(virtbase); - release_region: - release_mem_region(res->start, resource_size(res)); - check_prepare_enabled: - if (!clk_ret) - disable_unprepare: - clk_disable_unprepare(clk); - if (!IS_ERR(clk)) - clk_put(clk); - return NULL; } static void __init d40_hw_init(struct d40_base *base) @@ -3585,11 +3552,11 @@ static int __init d40_probe(struct platform_device *pdev) } else writel(base->phy_lcpa, base->virtbase + D40_DREG_LCPA); - base->lcpa_base = ioremap(base->phy_lcpa, base->lcpa_size); + base->lcpa_base = devm_ioremap(dev, base->phy_lcpa, base->lcpa_size); if (!base->lcpa_base) { ret = -ENOMEM; d40_err(dev, "Failed to ioremap LCPA region\n"); - goto release_base; + goto report_failure; } /* If lcla has to be located in ESRAM we don't need to allocate */ if (base->plat_data->use_esram_lcla) { @@ -3599,14 +3566,14 @@ static int __init d40_probe(struct platform_device *pdev) ret = -ENOENT; d40_err(dev, "No \"lcla_esram\" memory resource\n"); - goto destroy_cache; + goto report_failure; } - base->lcla_pool.base = ioremap(res->start, - resource_size(res)); + base->lcla_pool.base = devm_ioremap(dev, res->start, + resource_size(res)); if (!base->lcla_pool.base) { ret = -ENOMEM; d40_err(dev, "Failed to ioremap LCLA region\n"); - goto destroy_cache; + goto report_failure; } writel(res->start, base->virtbase + D40_DREG_LCLA); @@ -3678,16 +3645,8 @@ static int __init d40_probe(struct platform_device *pdev) dev_info(base->dev, "initialized\n"); return 0; + destroy_cache: - kmem_cache_destroy(base->desc_slab); - if (base->virtbase) - iounmap(base->virtbase); - - if (base->lcla_pool.base && base->plat_data->use_esram_lcla) { - iounmap(base->lcla_pool.base); - base->lcla_pool.base = NULL; - } - if (base->lcla_pool.dma_addr) dma_unmap_single(base->dev, base->lcla_pool.dma_addr, SZ_1K * base->num_phy_chans, @@ -3699,28 +3658,11 @@ static int __init d40_probe(struct platform_device *pdev) kfree(base->lcla_pool.base_unaligned); - if (base->lcpa_base) - iounmap(base->lcpa_base); - -release_base: - if (base->phy_start) - release_mem_region(base->phy_start, - base->phy_size); - if (base->clk) { - clk_disable_unprepare(base->clk); - clk_put(base->clk); - } - if (base->lcpa_regulator) { regulator_disable(base->lcpa_regulator); regulator_put(base->lcpa_regulator); } - kfree(base->lcla_pool.alloc_map); - kfree(base->lookup_log_chans); - kfree(base->lookup_phy_chans); - kfree(base->phy_res); - kfree(base); report_failure: d40_err(dev, "probe failed\n"); return ret; From 2893f6bc9d4076c48f8dd717b71baa29fe6adcae Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 16 May 2023 14:55:37 +0200 Subject: [PATCH 07/28] dmaengine: ste_dma40: Return error codes properly This makes the probe() and its subfunction d40_hw_detect_init() return proper error codes. One effect of this is that deferred probe, e.g from the clock, will start to work, would it happen. Also it is better design. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20230417-ux500-dma40-cleanup-v3-7-60bfa6785968@linaro.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 46 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 313baf316f13..c30d00a78eed 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -3132,7 +3132,8 @@ static void d40_drop_kmem_cache_action(void *d) kmem_cache_destroy(desc_slab); } -static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) +static int __init d40_hw_detect_init(struct platform_device *pdev, + struct d40_base **retbase) { struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; @@ -3150,14 +3151,12 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(clk)) - return NULL; + return PTR_ERR(clk); /* Get IO for DMAC base address */ virtbase = devm_platform_ioremap_resource_byname(pdev, "base"); - if (IS_ERR(virtbase)) { - dev_err(dev, "No IO base defined\n"); - return NULL; - } + if (IS_ERR(virtbase)) + return PTR_ERR(virtbase); /* This is just a regular AMBA PrimeCell ID actually */ for (pid = 0, i = 0; i < 4; i++) @@ -3169,13 +3168,13 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) if (cid != AMBA_CID) { d40_err(dev, "Unknown hardware! No PrimeCell ID\n"); - return NULL; + return -EINVAL; } if (AMBA_MANF_BITS(pid) != AMBA_VENDOR_ST) { d40_err(dev, "Unknown designer! Got %x wanted %x\n", AMBA_MANF_BITS(pid), AMBA_VENDOR_ST); - return NULL; + return -EINVAL; } /* * HW revision: @@ -3189,7 +3188,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) rev = AMBA_REV_BITS(pid); if (rev < 2) { d40_err(dev, "hardware revision: %d is not supported", rev); - return NULL; + return -EINVAL; } /* The number of physical channels on this HW */ @@ -3216,7 +3215,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) sizeof(struct d40_chan), GFP_KERNEL); if (!base) - return NULL; + return -ENOMEM; base->rev = rev; base->clk = clk; @@ -3263,51 +3262,53 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) sizeof(*base->phy_res), GFP_KERNEL); if (!base->phy_res) - return NULL; + return -ENOMEM; base->lookup_phy_chans = devm_kcalloc(dev, num_phy_chans, sizeof(*base->lookup_phy_chans), GFP_KERNEL); if (!base->lookup_phy_chans) - return NULL; + return -ENOMEM; base->lookup_log_chans = devm_kcalloc(dev, num_log_chans, sizeof(*base->lookup_log_chans), GFP_KERNEL); if (!base->lookup_log_chans) - return NULL; + return -ENOMEM; base->reg_val_backup_chan = devm_kmalloc_array(dev, base->num_phy_chans, sizeof(d40_backup_regs_chan), GFP_KERNEL); if (!base->reg_val_backup_chan) - return NULL; + return -ENOMEM; base->lcla_pool.alloc_map = devm_kcalloc(dev, num_phy_chans * D40_LCLA_LINK_PER_EVENT_GRP, sizeof(*base->lcla_pool.alloc_map), GFP_KERNEL); if (!base->lcla_pool.alloc_map) - return NULL; + return -ENOMEM; base->regs_interrupt = devm_kmalloc_array(dev, base->gen_dmac.il_size, sizeof(*base->regs_interrupt), GFP_KERNEL); if (!base->regs_interrupt) - return NULL; + return -ENOMEM; base->desc_slab = kmem_cache_create(D40_NAME, sizeof(struct d40_desc), 0, SLAB_HWCACHE_ALIGN, NULL); if (!base->desc_slab) - return NULL; + return -ENOMEM; ret = devm_add_action_or_reset(dev, d40_drop_kmem_cache_action, base->desc_slab); if (ret) - return NULL; + return ret; - return base; + *retbase = base; + + return 0; } static void __init d40_hw_init(struct d40_base *base) @@ -3503,20 +3504,20 @@ static int __init d40_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; struct device_node *np_lcpa; - int ret = -ENOENT; struct d40_base *base; struct resource *res; struct resource res_lcpa; int num_reserved_chans; u32 val; + int ret; if (d40_of_probe(dev, np)) { ret = -ENOMEM; goto report_failure; } - base = d40_hw_detect_init(pdev); - if (!base) + ret = d40_hw_detect_init(pdev, &base); + if (ret) goto report_failure; num_reserved_chans = d40_phy_res_init(base); @@ -3530,6 +3531,7 @@ static int __init d40_probe(struct platform_device *pdev) np_lcpa = of_parse_phandle(np, "sram", 0); if (!np_lcpa) { dev_err(dev, "no LCPA SRAM node\n"); + ret = -EINVAL; goto report_failure; } /* This is no device so read the address directly from the node */ From 64273b51a5156cae177394b3d9f036e0e61ca703 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 12 May 2023 13:40:33 +0200 Subject: [PATCH 08/28] dt-bindings: dma: xilinx: Add power-domains to xlnx,zynqmp-dpdma DP DMA has own power domain that's why describe required power-domain property. Signed-off-by: Michal Simek Acked-by: Conor Dooley Reviewed-by: Laurent Pinchart Link: https://lore.kernel.org/r/8f5651634df338743f95a7253a741f9ddc92487d.1683891609.git.michal.simek@amd.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml index d6cbd95ec26d..2128f4645c98 100644 --- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml +++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml @@ -41,6 +41,9 @@ properties: clock-names: const: axi_clk + power-domains: + maxItems: 1 + required: - "#dma-cells" - compatible @@ -48,12 +51,14 @@ required: - interrupts - clocks - clock-names + - power-domains additionalProperties: false examples: - | #include + #include dma: dma-controller@fd4c0000 { compatible = "xlnx,zynqmp-dpdma"; @@ -63,6 +68,7 @@ examples: clocks = <&dpdma_clk>; clock-names = "axi_clk"; #dma-cells = <1>; + power-domains = <&zynqmp_firmware PD_DP>; }; ... From b8e27cb0e4ed0e8c4bb858989ecb361d537bd9f0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 11 May 2023 09:17:04 +0530 Subject: [PATCH 09/28] dmaengine: ti: k3-psil-j721s2: Add PSI-L thread map for main CPSW2G Add PSI-L thread map for main CPSW2G. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Siddharth Vadapalli Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20230511034704.656155-1-s-vadapalli@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/k3-psil-j721s2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/dma/ti/k3-psil-j721s2.c b/drivers/dma/ti/k3-psil-j721s2.c index a488c2250623..1d5430fc5724 100644 --- a/drivers/dma/ti/k3-psil-j721s2.c +++ b/drivers/dma/ti/k3-psil-j721s2.c @@ -99,6 +99,8 @@ static struct psil_ep j721s2_src_ep_map[] = { PSIL_PDMA_XY_PKT(0x461d), PSIL_PDMA_XY_PKT(0x461e), PSIL_PDMA_XY_PKT(0x461f), + /* MAIN_CPSW2G */ + PSIL_ETHERNET(0x4640), /* PDMA_USART_G0 - UART0-1 */ PSIL_PDMA_XY_PKT(0x4700), PSIL_PDMA_XY_PKT(0x4701), @@ -161,6 +163,15 @@ static struct psil_ep j721s2_dst_ep_map[] = { PSIL_ETHERNET(0xf005), PSIL_ETHERNET(0xf006), PSIL_ETHERNET(0xf007), + /* MAIN_CPSW2G */ + PSIL_ETHERNET(0xc640), + PSIL_ETHERNET(0xc641), + PSIL_ETHERNET(0xc642), + PSIL_ETHERNET(0xc643), + PSIL_ETHERNET(0xc644), + PSIL_ETHERNET(0xc645), + PSIL_ETHERNET(0xc646), + PSIL_ETHERNET(0xc647), /* SA2UL */ PSIL_SA2UL(0xf500, 1), PSIL_SA2UL(0xf501, 1), From 6de80a0cc7d24292ed83d1696f61ebfee2b854f1 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Fri, 5 May 2023 20:09:28 +0530 Subject: [PATCH 10/28] dt-bindings: dma: ti: Add J721S2 BCDMA Add bindings for J721S2 BCDMA instance dedicated for Camera Serial Interface. Unlike AM62A CSI BCDMA, this instance has RX and TX channels but lacks block copy channels. Signed-off-by: Vaishnav Achath Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230505143929.28131-2-vaishnav.a@ti.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/ti/k3-bcdma.yaml | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml index beecfe7a1732..4ca300a42a99 100644 --- a/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml +++ b/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml @@ -33,6 +33,7 @@ properties: enum: - ti,am62a-dmss-bcdma-csirx - ti,am64-dmss-bcdma + - ti,j721s2-dmss-bcdma-csi reg: minItems: 3 @@ -151,7 +152,12 @@ allOf: required: - power-domains - else: + - if: + properties: + compatible: + contains: + const: ti,am64-dmss-bcdma + then: properties: reg: minItems: 5 @@ -168,6 +174,28 @@ allOf: - ti,sci-rm-range-bchan - ti,sci-rm-range-tchan + - if: + properties: + compatible: + contains: + const: ti,j721s2-dmss-bcdma-csi + then: + properties: + ti,sci-rm-range-bchan: false + + reg: + maxItems: 4 + + reg-names: + items: + - const: gcfg + - const: rchanrt + - const: tchanrt + - const: ringrt + + required: + - ti,sci-rm-range-tchan + unevaluatedProperties: false examples: From ceb434d56826b39ff9d5700804c4b22cb091c1a2 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Fri, 5 May 2023 20:09:29 +0530 Subject: [PATCH 11/28] dmaengine: ti: k3-udma: Add support for J721S2 CSI BCDMA instance J721S2 has dedicated BCDMA instance for Camera Serial Interface RX and TX. The BCDMA instance supports RX and TX channels but block copy channels are not present, add support for the same. Signed-off-by: Vaishnav Achath Link: https://lore.kernel.org/r/20230505143929.28131-3-vaishnav.a@ti.com Signed-off-by: Vinod Koul --- drivers/dma/ti/k3-udma.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index fc3a2a05ab7b..16c5c333808b 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -4308,6 +4308,15 @@ static struct udma_soc_data am62a_dmss_csi_soc_data = { }, }; +static struct udma_soc_data j721s2_bcdma_csi_soc_data = { + .oes = { + .bcdma_tchan_data = 0x800, + .bcdma_tchan_ring = 0xa00, + .bcdma_rchan_data = 0xe00, + .bcdma_rchan_ring = 0x1000, + }, +}; + static struct udma_match_data am62a_bcdma_csirx_data = { .type = DMA_TYPE_BCDMA, .psil_base = 0x3100, @@ -4346,6 +4355,18 @@ static struct udma_match_data am64_pktdma_data = { }, }; +static struct udma_match_data j721s2_bcdma_csi_data = { + .type = DMA_TYPE_BCDMA, + .psil_base = 0x2000, + .enable_memcpy_support = false, + .burst_size = { + TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ + 0, /* No H Channels */ + 0, /* No UH Channels */ + }, + .soc_data = &j721s2_bcdma_csi_soc_data, +}; + static const struct of_device_id udma_of_match[] = { { .compatible = "ti,am654-navss-main-udmap", @@ -4373,6 +4394,10 @@ static const struct of_device_id udma_of_match[] = { .compatible = "ti,am62a-dmss-bcdma-csirx", .data = &am62a_bcdma_csirx_data, }, + { + .compatible = "ti,j721s2-dmss-bcdma-csi", + .data = &j721s2_bcdma_csi_data, + }, { /* Sentinel */ }, }; From 9d71a11b6b07b01e21127184cdd47b40fbcbe5d4 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 11 May 2023 22:09:00 +0300 Subject: [PATCH 12/28] MAINTAINERS: Demote Gustavo Pimentel to DW EDMA driver reviewer No maintaining actions from Gustavo have been noticed for over a year. Demote him to being the DW eDMA driver reviewer for now. Signed-off-by: Serge Semin Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20230511190902.28896-13-Sergey.Semin@baikalelectronics.ru Signed-off-by: Vinod Koul --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7e0b87d5aa2e..84ec0281ff9b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5885,7 +5885,7 @@ S: Orphan F: drivers/mtd/nand/raw/denali* DESIGNWARE EDMA CORE IP DRIVER -M: Gustavo Pimentel +R: Gustavo Pimentel L: dmaengine@vger.kernel.org S: Maintained F: drivers/dma/dw-edma/ From 1c677f238f92ba0a329b7c13220f38b396872806 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 11 May 2023 22:09:01 +0300 Subject: [PATCH 13/28] MAINTAINERS: Add Manivannan to DW eDMA driver maintainers list Manivannan has been very active in reviewing the bits coming to the DW eDMA driver. Let's add him to the driver maintainers list. Signed-off-by: Serge Semin Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20230511190902.28896-14-Sergey.Semin@baikalelectronics.ru Signed-off-by: Vinod Koul --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 84ec0281ff9b..bdbdc285575b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5885,6 +5885,7 @@ S: Orphan F: drivers/mtd/nand/raw/denali* DESIGNWARE EDMA CORE IP DRIVER +M: Manivannan Sadhasivam R: Gustavo Pimentel L: dmaengine@vger.kernel.org S: Maintained From 8d81d3a0e97d54d6f6b58fb8ea011b1fa0991f6f Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 11 May 2023 22:09:02 +0300 Subject: [PATCH 14/28] MAINTAINERS: Add myself as the DW eDMA driver reviewer The driver original maintainer has been inactive for almost two years now. It doesn't positively affect the new patches tests and reviews process. Since the DW eDMA engine has been embedded into the PCIe controllers in several our SoCs we will be interested in helping with the updates review. Signed-off-by: Serge Semin Acked-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20230511190902.28896-15-Sergey.Semin@baikalelectronics.ru Signed-off-by: Vinod Koul --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index bdbdc285575b..ea14e0f57e19 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5887,6 +5887,7 @@ F: drivers/mtd/nand/raw/denali* DESIGNWARE EDMA CORE IP DRIVER M: Manivannan Sadhasivam R: Gustavo Pimentel +R: Serge Semin L: dmaengine@vger.kernel.org S: Maintained F: drivers/dma/dw-edma/ From ef1e1c41a11d37069029bc0563c2fa6915d9880b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 17 May 2023 12:14:33 +0530 Subject: [PATCH 15/28] dmaengine: ste_dma40: use correct print specfier for resource_size_t We should use %pR for printing resource_size_t, so update that fixing the warning: drivers/dma/ste_dma40.c:3556:25: warning: format specifies type 'unsigned int' but the argument has type 'resource_size_t' (aka 'unsigned long long') [-Wformat] Reported-by: kernel test robot Fixes: 5a1a3b9c19dd ("dmaengine: ste_dma40: Get LCPA SRAM from SRAM node") Reviewed-by: Linus Walleij Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20230517064434.141091-1-vkoul@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index c30d00a78eed..56c839241a53 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -3542,8 +3542,8 @@ static int __init d40_probe(struct platform_device *pdev) } base->lcpa_size = resource_size(&res_lcpa); base->phy_lcpa = res_lcpa.start; - dev_info(dev, "found LCPA SRAM at 0x%08x, size 0x%08x\n", - (u32)base->phy_lcpa, base->lcpa_size); + dev_info(dev, "found LCPA SRAM at 0x%08x, size %pR\n", + (u32)base->phy_lcpa, &base->lcpa_size); /* We make use of ESRAM memory for this. */ val = readl(base->virtbase + D40_DREG_LCPA); From 401f022cc5a2f0c521767d82c352d83aed944834 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 17 May 2023 12:14:34 +0530 Subject: [PATCH 16/28] dmaengine: ste_dma40: fix typo in enum documentation s/40_command/d40_command to fix the below warning reported: drivers/dma/ste_dma40.c:151: warning: expecting prototype for enum 40_command. Prototype was for enum d40_command instead Reviewed-by: Linus Walleij Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20230517064434.141091-2-vkoul@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 56c839241a53..2246a604256e 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -136,7 +136,7 @@ static const struct stedma40_chan_cfg dma40_memcpy_conf_log = { }; /** - * enum 40_command - The different commands and/or statuses. + * enum d40_command - The different commands and/or statuses. * * @D40_DMA_STOP: DMA channel command STOP or status STOPPED, * @D40_DMA_RUN: The DMA channel is RUNNING of the command RUN. From 2437d5ea2191f3059246a1a7ac6fc4c8cc004dec Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Sat, 6 May 2023 19:16:28 +0800 Subject: [PATCH 17/28] dmaengine: make QCOM_HIDMA depend on HAS_IOMEM On s390 systems (aka mainframes), it has classic channel devices for networking and permanent storage that are currently even more common than PCI devices. Hence it could have a fully functional s390 kernel with CONFIG_PCI=n, then the relevant iomem mapping functions [including ioremap(), devm_ioremap(), etc.] are not available. Here let QCOM_HIDMA depend on HAS_IOMEM so that it won't be built to cause below compiling error if PCI is unset. -------------------------------------------------------- ld: drivers/dma/qcom/hidma.o: in function `hidma_probe': hidma.c:(.text+0x4b46): undefined reference to `devm_ioremap_resource' ld: hidma.c:(.text+0x4b9e): undefined reference to `devm_ioremap_resource' make[1]: *** [scripts/Makefile.vmlinux:35: vmlinux] Error 1 make: *** [Makefile:1264: vmlinux] Error 2 Signed-off-by: Baoquan He Reviewed-by: Niklas Schnelle Cc: Andy Gross Cc: Bjorn Andersson Cc: Konrad Dybcio Cc: Vinod Koul Cc: linux-arm-msm@vger.kernel.org Cc: dmaengine@vger.kernel.org Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230506111628.712316-3-bhe@redhat.com Signed-off-by: Vinod Koul --- drivers/dma/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig index 3f926a653bd8..ace75d7b835a 100644 --- a/drivers/dma/qcom/Kconfig +++ b/drivers/dma/qcom/Kconfig @@ -45,6 +45,7 @@ config QCOM_HIDMA_MGMT config QCOM_HIDMA tristate "Qualcomm Technologies HIDMA Channel support" + depends on HAS_IOMEM select DMA_ENGINE help Enable support for the Qualcomm Technologies HIDMA controller. From 41be14c71bae05c8daa3de5ae7fd7c2a7bc0d057 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 19 May 2023 11:34:38 +0200 Subject: [PATCH 18/28] dmaengine: ste_dma40: use proper format string for resource_size_t A fixup for a printk format string warning causes an out-of-bounds variable access as the %pR string expects a struct resource instead of a plain resource_size_t. Change both to the special %pap and %pap helpers for these types. Fixes: 5a1a3b9c19dd ("dmaengine: ste_dma40: Get LCPA SRAM from SRAM node") Fixes: ef1e1c41a11d ("dmaengine: ste_dma40: use correct print specfier for resource_size_t") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230519093447.4097040-1-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 2246a604256e..825001bde42c 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -3542,8 +3542,8 @@ static int __init d40_probe(struct platform_device *pdev) } base->lcpa_size = resource_size(&res_lcpa); base->phy_lcpa = res_lcpa.start; - dev_info(dev, "found LCPA SRAM at 0x%08x, size %pR\n", - (u32)base->phy_lcpa, &base->lcpa_size); + dev_info(dev, "found LCPA SRAM at %pad, size %pa\n", + &base->phy_lcpa, &base->lcpa_size); /* We make use of ESRAM memory for this. */ val = readl(base->virtbase + D40_DREG_LCPA); From 487517557f97809c38ff99f726ec991ab6aa8a73 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Sat, 20 May 2023 13:08:49 +0800 Subject: [PATCH 19/28] dmaengine: dw-edma: Rename dw_edma_core_ops structure to dw_edma_plat_ops The dw_edma_core_ops structure contains a set of the operations: device IRQ numbers getter, CPU/PCI address translation. Based on the functions semantics the structure name "dw_edma_plat_ops" looks more descriptive since indeed the operations are platform-specific. The "dw_edma_core_ops" name shall be used for a structure with the IP-core specific set of callbacks in order to abstract out DW eDMA and DW HDMA setups. Such structure will be added in one of the next commit in the framework of the set of changes adding the DW HDMA device support. Anyway the renaming was necessary to distinguish two types of the implementation callbacks: 1. DW eDMA/hDMA IP-core specific operations: device-specific CSR setups in one or another aspect of the DMA-engine initialization. 2. DW eDMA/hDMA platform specific operations: the DMA device environment configs like IRQs, address translation, etc. Signed-off-by: Cai Huoqing Reviewed-by: Serge Semin Reviewed-by: Manivannan Sadhasivam Tested-by: Serge Semin Link: https://lore.kernel.org/r/20230520050854.73160-2-cai.huoqing@linux.dev Signed-off-by: Vinod Koul --- drivers/dma/dw-edma/dw-edma-pcie.c | 4 ++-- drivers/pci/controller/dwc/pcie-designware.c | 2 +- include/linux/dma/edma.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c index 2b40f2b44f5e..1c6043751dc9 100644 --- a/drivers/dma/dw-edma/dw-edma-pcie.c +++ b/drivers/dma/dw-edma/dw-edma-pcie.c @@ -109,7 +109,7 @@ static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr) return region.start; } -static const struct dw_edma_core_ops dw_edma_pcie_core_ops = { +static const struct dw_edma_plat_ops dw_edma_pcie_plat_ops = { .irq_vector = dw_edma_pcie_irq_vector, .pci_address = dw_edma_pcie_address, }; @@ -225,7 +225,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev, chip->mf = vsec_data.mf; chip->nr_irqs = nr_irqs; - chip->ops = &dw_edma_pcie_core_ops; + chip->ops = &dw_edma_pcie_plat_ops; chip->ll_wr_cnt = vsec_data.wr_ch_cnt; chip->ll_rd_cnt = vsec_data.rd_ch_cnt; diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 8e33e6e59e68..1f2ee71da4da 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -828,7 +828,7 @@ static int dw_pcie_edma_irq_vector(struct device *dev, unsigned int nr) return platform_get_irq_byname_optional(pdev, name); } -static struct dw_edma_core_ops dw_pcie_edma_ops = { +static struct dw_edma_plat_ops dw_pcie_edma_ops = { .irq_vector = dw_pcie_edma_irq_vector, }; diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h index d2638d9259dc..ed401c965a87 100644 --- a/include/linux/dma/edma.h +++ b/include/linux/dma/edma.h @@ -40,7 +40,7 @@ struct dw_edma_region { * iATU windows. That will be done by the controller * automatically. */ -struct dw_edma_core_ops { +struct dw_edma_plat_ops { int (*irq_vector)(struct device *dev, unsigned int nr); u64 (*pci_address)(struct device *dev, phys_addr_t cpu_addr); }; @@ -80,7 +80,7 @@ enum dw_edma_chip_flags { struct dw_edma_chip { struct device *dev; int nr_irqs; - const struct dw_edma_core_ops *ops; + const struct dw_edma_plat_ops *ops; u32 flags; void __iomem *reg_base; From f9c3403f1fabf6b21dad67a2a0641ea18a48de21 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Sat, 20 May 2023 13:08:50 +0800 Subject: [PATCH 20/28] dmaengine: dw-edma: Create a new dw_edma_core_ops structure to abstract controller operation The structure dw_edma_core_ops has a set of the pointers abstracting out the DW eDMA vX and DW HDMA Native controllers. And use dw_edma_v0_core_register to set up operation. Signed-off-by: Cai Huoqing Reviewed-by: Serge Semin Reviewed-by: Manivannan Sadhasivam Tested-by: Serge Semin Link: https://lore.kernel.org/r/20230520050854.73160-3-cai.huoqing@linux.dev Signed-off-by: Vinod Koul --- drivers/dma/dw-edma/dw-edma-core.c | 84 ++++++++------------------ drivers/dma/dw-edma/dw-edma-core.h | 58 ++++++++++++++++++ drivers/dma/dw-edma/dw-edma-v0-core.c | 85 +++++++++++++++++++++++---- drivers/dma/dw-edma/dw-edma-v0-core.h | 14 +---- 4 files changed, 158 insertions(+), 83 deletions(-) diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index 7d2b73ef0872..f17207c66c19 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -183,6 +183,7 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc) static int dw_edma_start_transfer(struct dw_edma_chan *chan) { + struct dw_edma *dw = chan->dw; struct dw_edma_chunk *child; struct dw_edma_desc *desc; struct virt_dma_desc *vd; @@ -200,7 +201,7 @@ static int dw_edma_start_transfer(struct dw_edma_chan *chan) if (!child) return 0; - dw_edma_v0_core_start(child, !desc->xfer_sz); + dw_edma_core_start(dw, child, !desc->xfer_sz); desc->xfer_sz += child->ll_region.sz; dw_edma_free_burst(child); list_del(&child->list); @@ -287,7 +288,7 @@ static int dw_edma_device_terminate_all(struct dma_chan *dchan) chan->configured = false; } else if (chan->status == EDMA_ST_IDLE) { chan->configured = false; - } else if (dw_edma_v0_core_ch_status(chan) == DMA_COMPLETE) { + } else if (dw_edma_core_ch_status(chan) == DMA_COMPLETE) { /* * The channel is in a false BUSY state, probably didn't * receive or lost an interrupt @@ -599,8 +600,6 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan) struct virt_dma_desc *vd; unsigned long flags; - dw_edma_v0_core_clear_done_int(chan); - spin_lock_irqsave(&chan->vc.lock, flags); vd = vchan_next_desc(&chan->vc); if (vd) { @@ -641,8 +640,6 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan) struct virt_dma_desc *vd; unsigned long flags; - dw_edma_v0_core_clear_abort_int(chan); - spin_lock_irqsave(&chan->vc.lock, flags); vd = vchan_next_desc(&chan->vc); if (vd) { @@ -654,63 +651,32 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan) chan->status = EDMA_ST_IDLE; } -static irqreturn_t dw_edma_interrupt(int irq, void *data, bool write) -{ - struct dw_edma_irq *dw_irq = data; - struct dw_edma *dw = dw_irq->dw; - unsigned long total, pos, val; - unsigned long off; - u32 mask; - - if (write) { - total = dw->wr_ch_cnt; - off = 0; - mask = dw_irq->wr_mask; - } else { - total = dw->rd_ch_cnt; - off = dw->wr_ch_cnt; - mask = dw_irq->rd_mask; - } - - val = dw_edma_v0_core_status_done_int(dw, write ? - EDMA_DIR_WRITE : - EDMA_DIR_READ); - val &= mask; - for_each_set_bit(pos, &val, total) { - struct dw_edma_chan *chan = &dw->chan[pos + off]; - - dw_edma_done_interrupt(chan); - } - - val = dw_edma_v0_core_status_abort_int(dw, write ? - EDMA_DIR_WRITE : - EDMA_DIR_READ); - val &= mask; - for_each_set_bit(pos, &val, total) { - struct dw_edma_chan *chan = &dw->chan[pos + off]; - - dw_edma_abort_interrupt(chan); - } - - return IRQ_HANDLED; -} - static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data) { - return dw_edma_interrupt(irq, data, true); + struct dw_edma_irq *dw_irq = data; + + return dw_edma_core_handle_int(dw_irq, EDMA_DIR_WRITE, + dw_edma_done_interrupt, + dw_edma_abort_interrupt); } static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data) { - return dw_edma_interrupt(irq, data, false); + struct dw_edma_irq *dw_irq = data; + + return dw_edma_core_handle_int(dw_irq, EDMA_DIR_READ, + dw_edma_done_interrupt, + dw_edma_abort_interrupt); } static irqreturn_t dw_edma_interrupt_common(int irq, void *data) { - dw_edma_interrupt(irq, data, true); - dw_edma_interrupt(irq, data, false); + irqreturn_t ret = IRQ_NONE; - return IRQ_HANDLED; + ret |= dw_edma_interrupt_write(irq, data); + ret |= dw_edma_interrupt_read(irq, data); + + return ret; } static int dw_edma_alloc_chan_resources(struct dma_chan *dchan) @@ -811,7 +777,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc) vchan_init(&chan->vc, dma); - dw_edma_v0_core_device_config(chan); + dw_edma_core_ch_config(chan); } /* Set DMA channel capabilities */ @@ -956,14 +922,16 @@ int dw_edma_probe(struct dw_edma_chip *chip) dw->chip = chip; + dw_edma_v0_core_register(dw); + raw_spin_lock_init(&dw->lock); dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt, - dw_edma_v0_core_ch_count(dw, EDMA_DIR_WRITE)); + dw_edma_core_ch_count(dw, EDMA_DIR_WRITE)); dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH); dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt, - dw_edma_v0_core_ch_count(dw, EDMA_DIR_READ)); + dw_edma_core_ch_count(dw, EDMA_DIR_READ)); dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH); if (!dw->wr_ch_cnt && !dw->rd_ch_cnt) @@ -982,7 +950,7 @@ int dw_edma_probe(struct dw_edma_chip *chip) dev_name(chip->dev)); /* Disable eDMA, only to establish the ideal initial conditions */ - dw_edma_v0_core_off(dw); + dw_edma_core_off(dw); /* Request IRQs */ err = dw_edma_irq_request(dw, &wr_alloc, &rd_alloc); @@ -995,7 +963,7 @@ int dw_edma_probe(struct dw_edma_chip *chip) goto err_irq_free; /* Turn debugfs on */ - dw_edma_v0_core_debugfs_on(dw); + dw_edma_core_debugfs_on(dw); chip->dw = dw; @@ -1021,7 +989,7 @@ int dw_edma_remove(struct dw_edma_chip *chip) return -ENODEV; /* Disable eDMA */ - dw_edma_v0_core_off(dw); + dw_edma_core_off(dw); /* Free irqs */ for (i = (dw->nr_irqs - 1); i >= 0; i--) diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h index 0ab2b6dba880..71894b9e0b15 100644 --- a/drivers/dma/dw-edma/dw-edma-core.h +++ b/drivers/dma/dw-edma/dw-edma-core.h @@ -111,6 +111,21 @@ struct dw_edma { raw_spinlock_t lock; /* Only for legacy */ struct dw_edma_chip *chip; + + const struct dw_edma_core_ops *core; +}; + +typedef void (*dw_edma_handler_t)(struct dw_edma_chan *); + +struct dw_edma_core_ops { + void (*off)(struct dw_edma *dw); + u16 (*ch_count)(struct dw_edma *dw, enum dw_edma_dir dir); + enum dma_status (*ch_status)(struct dw_edma_chan *chan); + irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, + dw_edma_handler_t done, dw_edma_handler_t abort); + void (*start)(struct dw_edma_chunk *chunk, bool first); + void (*ch_config)(struct dw_edma_chan *chan); + void (*debugfs_on)(struct dw_edma *dw); }; struct dw_edma_sg { @@ -148,4 +163,47 @@ struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan) return vc2dw_edma_chan(to_virt_chan(dchan)); } +static inline +void dw_edma_core_off(struct dw_edma *dw) +{ + dw->core->off(dw); +} + +static inline +u16 dw_edma_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) +{ + return dw->core->ch_count(dw, dir); +} + +static inline +enum dma_status dw_edma_core_ch_status(struct dw_edma_chan *chan) +{ + return chan->dw->core->ch_status(chan); +} + +static inline irqreturn_t +dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, + dw_edma_handler_t done, dw_edma_handler_t abort) +{ + return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort); +} + +static inline +void dw_edma_core_start(struct dw_edma *dw, struct dw_edma_chunk *chunk, bool first) +{ + dw->core->start(chunk, first); +} + +static inline +void dw_edma_core_ch_config(struct dw_edma_chan *chan) +{ + chan->dw->core->ch_config(chan); +} + +static inline +void dw_edma_core_debugfs_on(struct dw_edma *dw) +{ + dw->core->debugfs_on(dw); +} + #endif /* _DW_EDMA_CORE_H */ diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c index 32f834a3848a..b38786f0ad79 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-core.c +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c @@ -7,7 +7,7 @@ */ #include - +#include #include #include "dw-edma-core.h" @@ -160,7 +160,7 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch, readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name)) /* eDMA management callbacks */ -void dw_edma_v0_core_off(struct dw_edma *dw) +static void dw_edma_v0_core_off(struct dw_edma *dw) { SET_BOTH_32(dw, int_mask, EDMA_V0_DONE_INT_MASK | EDMA_V0_ABORT_INT_MASK); @@ -169,7 +169,7 @@ void dw_edma_v0_core_off(struct dw_edma *dw) SET_BOTH_32(dw, engine_en, 0); } -u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) +static u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) { u32 num_ch; @@ -186,7 +186,7 @@ u16 dw_edma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) return (u16)num_ch; } -enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan) +static enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan) { struct dw_edma *dw = chan->dw; u32 tmp; @@ -202,7 +202,7 @@ enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan) return DMA_ERROR; } -void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan) +static void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan) { struct dw_edma *dw = chan->dw; @@ -210,7 +210,7 @@ void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan) FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id))); } -void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan) +static void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan) { struct dw_edma *dw = chan->dw; @@ -218,18 +218,64 @@ void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan) FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id))); } -u32 dw_edma_v0_core_status_done_int(struct dw_edma *dw, enum dw_edma_dir dir) +static u32 dw_edma_v0_core_status_done_int(struct dw_edma *dw, enum dw_edma_dir dir) { return FIELD_GET(EDMA_V0_DONE_INT_MASK, GET_RW_32(dw, dir, int_status)); } -u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir) +static u32 dw_edma_v0_core_status_abort_int(struct dw_edma *dw, enum dw_edma_dir dir) { return FIELD_GET(EDMA_V0_ABORT_INT_MASK, GET_RW_32(dw, dir, int_status)); } +static irqreturn_t +dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, + dw_edma_handler_t done, dw_edma_handler_t abort) +{ + struct dw_edma *dw = dw_irq->dw; + unsigned long total, pos, val; + irqreturn_t ret = IRQ_NONE; + struct dw_edma_chan *chan; + unsigned long off; + u32 mask; + + if (dir == EDMA_DIR_WRITE) { + total = dw->wr_ch_cnt; + off = 0; + mask = dw_irq->wr_mask; + } else { + total = dw->rd_ch_cnt; + off = dw->wr_ch_cnt; + mask = dw_irq->rd_mask; + } + + val = dw_edma_v0_core_status_done_int(dw, dir); + val &= mask; + for_each_set_bit(pos, &val, total) { + chan = &dw->chan[pos + off]; + + dw_edma_v0_core_clear_done_int(chan); + done(chan); + + ret = IRQ_HANDLED; + } + + val = dw_edma_v0_core_status_abort_int(dw, dir); + val &= mask; + for_each_set_bit(pos, &val, total) { + chan = &dw->chan[pos + off]; + + dw_edma_v0_core_clear_abort_int(chan); + abort(chan); + + ret = IRQ_HANDLED; + } + + return ret; +} + static void dw_edma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i, u32 control, u32 size, u64 sar, u64 dar) { @@ -300,7 +346,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk) dw_edma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr); } -void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first) +static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first) { struct dw_edma_chan *chan = chunk->chan; struct dw_edma *dw = chan->dw; @@ -371,7 +417,7 @@ void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first) FIELD_PREP(EDMA_V0_DOORBELL_CH_MASK, chan->id)); } -int dw_edma_v0_core_device_config(struct dw_edma_chan *chan) +static void dw_edma_v0_core_ch_config(struct dw_edma_chan *chan) { struct dw_edma *dw = chan->dw; u32 tmp = 0; @@ -438,12 +484,25 @@ int dw_edma_v0_core_device_config(struct dw_edma_chan *chan) SET_RW_32(dw, chan->dir, ch67_imwr_data, tmp); break; } - - return 0; } /* eDMA debugfs callbacks */ -void dw_edma_v0_core_debugfs_on(struct dw_edma *dw) +static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw) { dw_edma_v0_debugfs_on(dw); } + +static const struct dw_edma_core_ops dw_edma_v0_core = { + .off = dw_edma_v0_core_off, + .ch_count = dw_edma_v0_core_ch_count, + .ch_status = dw_edma_v0_core_ch_status, + .handle_int = dw_edma_v0_core_handle_int, + .start = dw_edma_v0_core_start, + .ch_config = dw_edma_v0_core_ch_config, + .debugfs_on = dw_edma_v0_core_debugfs_on, +}; + +void dw_edma_v0_core_register(struct dw_edma *dw) +{ + dw->core = &dw_edma_v0_core; +} diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.h b/drivers/dma/dw-edma/dw-edma-v0-core.h index ab96a1f48080..04a882222f99 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-core.h +++ b/drivers/dma/dw-edma/dw-edma-v0-core.h @@ -11,17 +11,7 @@ #include -/* eDMA management callbacks */ -void dw_edma_v0_core_off(struct dw_edma *chan); -u16 dw_edma_v0_core_ch_count(struct dw_edma *chan, enum dw_edma_dir dir); -enum dma_status dw_edma_v0_core_ch_status(struct dw_edma_chan *chan); -void dw_edma_v0_core_clear_done_int(struct dw_edma_chan *chan); -void dw_edma_v0_core_clear_abort_int(struct dw_edma_chan *chan); -u32 dw_edma_v0_core_status_done_int(struct dw_edma *chan, enum dw_edma_dir dir); -u32 dw_edma_v0_core_status_abort_int(struct dw_edma *chan, enum dw_edma_dir dir); -void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first); -int dw_edma_v0_core_device_config(struct dw_edma_chan *chan); -/* eDMA debug fs callbacks */ -void dw_edma_v0_core_debugfs_on(struct dw_edma *dw); +/* eDMA core register */ +void dw_edma_v0_core_register(struct dw_edma *dw); #endif /* _DW_EDMA_V0_CORE_H */ From e74c39573d35e9ac441090ff8183aa3dc2540649 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Sat, 20 May 2023 13:08:51 +0800 Subject: [PATCH 21/28] dmaengine: dw-edma: Add support for native HDMA Add support for HDMA NATIVE, as long the IP design has set the compatible register map parameter-HDMA_NATIVE, which allows compatibility for native HDMA register configuration. The HDMA Hyper-DMA IP is an enhancement of the eDMA embedded-DMA IP. And the native HDMA registers are different from eDMA, so this patch add support for HDMA NATIVE mode. HDMA write and read channels operate independently to maximize the performance of the HDMA read and write data transfer over the link When you configure the HDMA with multiple read channels, then it uses a round robin (RR) arbitration scheme to select the next read channel to be serviced.The same applies when you have multiple write channels. The native HDMA driver also supports a maximum of 16 independent channels (8 write + 8 read), which can run simultaneously. Both SAR (Source Address Register) and DAR (Destination Address Register) are aligned to byte. Signed-off-by: Cai Huoqing Reviewed-by: Serge Semin Reviewed-by: Manivannan Sadhasivam Tested-by: Serge Semin Link: https://lore.kernel.org/r/20230520050854.73160-4-cai.huoqing@linux.dev Signed-off-by: Vinod Koul --- drivers/dma/dw-edma/Makefile | 5 +- drivers/dma/dw-edma/dw-edma-core.c | 6 +- drivers/dma/dw-edma/dw-hdma-v0-core.c | 294 ++++++++++++++++++++++++++ drivers/dma/dw-edma/dw-hdma-v0-core.h | 17 ++ drivers/dma/dw-edma/dw-hdma-v0-regs.h | 129 +++++++++++ include/linux/dma/edma.h | 3 +- 6 files changed, 450 insertions(+), 4 deletions(-) create mode 100644 drivers/dma/dw-edma/dw-hdma-v0-core.c create mode 100644 drivers/dma/dw-edma/dw-hdma-v0-core.h create mode 100644 drivers/dma/dw-edma/dw-hdma-v0-regs.h diff --git a/drivers/dma/dw-edma/Makefile b/drivers/dma/dw-edma/Makefile index 8d45c0d5689d..b1c91ef2c63d 100644 --- a/drivers/dma/dw-edma/Makefile +++ b/drivers/dma/dw-edma/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_DW_EDMA) += dw-edma.o dw-edma-$(CONFIG_DEBUG_FS) := dw-edma-v0-debugfs.o -dw-edma-objs := dw-edma-core.o \ - dw-edma-v0-core.o $(dw-edma-y) +dw-edma-objs := dw-edma-core.o \ + dw-edma-v0-core.o \ + dw-hdma-v0-core.o $(dw-edma-y) obj-$(CONFIG_DW_EDMA_PCIE) += dw-edma-pcie.o diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index f17207c66c19..68236247059d 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -18,6 +18,7 @@ #include "dw-edma-core.h" #include "dw-edma-v0-core.h" +#include "dw-hdma-v0-core.h" #include "../dmaengine.h" #include "../virt-dma.h" @@ -922,7 +923,10 @@ int dw_edma_probe(struct dw_edma_chip *chip) dw->chip = chip; - dw_edma_v0_core_register(dw); + if (dw->chip->mf == EDMA_MF_HDMA_NATIVE) + dw_hdma_v0_core_register(dw); + else + dw_edma_v0_core_register(dw); raw_spin_lock_init(&dw->lock); diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c new file mode 100644 index 000000000000..22b7b0410deb --- /dev/null +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 Cai Huoqing + * Synopsys DesignWare HDMA v0 core + */ + +#include +#include +#include + +#include "dw-edma-core.h" +#include "dw-hdma-v0-core.h" +#include "dw-hdma-v0-regs.h" + +enum dw_hdma_control { + DW_HDMA_V0_CB = BIT(0), + DW_HDMA_V0_TCB = BIT(1), + DW_HDMA_V0_LLP = BIT(2), + DW_HDMA_V0_LIE = BIT(3), + DW_HDMA_V0_RIE = BIT(4), + DW_HDMA_V0_CCS = BIT(8), + DW_HDMA_V0_LLE = BIT(9), +}; + +static inline struct dw_hdma_v0_regs __iomem *__dw_regs(struct dw_edma *dw) +{ + return dw->chip->reg_base; +} + +static inline struct dw_hdma_v0_ch_regs __iomem * +__dw_ch_regs(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch) +{ + if (dir == EDMA_DIR_WRITE) + return &(__dw_regs(dw)->ch[ch].wr); + else + return &(__dw_regs(dw)->ch[ch].rd); +} + +#define SET_CH_32(dw, dir, ch, name, value) \ + writel(value, &(__dw_ch_regs(dw, dir, ch)->name)) + +#define GET_CH_32(dw, dir, ch, name) \ + readl(&(__dw_ch_regs(dw, dir, ch)->name)) + +#define SET_BOTH_CH_32(dw, ch, name, value) \ + do { \ + writel(value, &(__dw_ch_regs(dw, EDMA_DIR_WRITE, ch)->name)); \ + writel(value, &(__dw_ch_regs(dw, EDMA_DIR_READ, ch)->name)); \ + } while (0) + +/* HDMA management callbacks */ +static void dw_hdma_v0_core_off(struct dw_edma *dw) +{ + int id; + + for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) { + SET_BOTH_CH_32(dw, id, int_setup, + HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK); + SET_BOTH_CH_32(dw, id, int_clear, + HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK); + SET_BOTH_CH_32(dw, id, ch_en, 0); + } +} + +static u16 dw_hdma_v0_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) +{ + u32 num_ch = 0; + int id; + + for (id = 0; id < HDMA_V0_MAX_NR_CH; id++) { + if (GET_CH_32(dw, id, dir, ch_en) & BIT(0)) + num_ch++; + } + + if (num_ch > HDMA_V0_MAX_NR_CH) + num_ch = HDMA_V0_MAX_NR_CH; + + return (u16)num_ch; +} + +static enum dma_status dw_hdma_v0_core_ch_status(struct dw_edma_chan *chan) +{ + struct dw_edma *dw = chan->dw; + u32 tmp; + + tmp = FIELD_GET(HDMA_V0_CH_STATUS_MASK, + GET_CH_32(dw, chan->id, chan->dir, ch_stat)); + + if (tmp == 1) + return DMA_IN_PROGRESS; + else if (tmp == 3) + return DMA_COMPLETE; + else + return DMA_ERROR; +} + +static void dw_hdma_v0_core_clear_done_int(struct dw_edma_chan *chan) +{ + struct dw_edma *dw = chan->dw; + + SET_CH_32(dw, chan->dir, chan->id, int_clear, HDMA_V0_STOP_INT_MASK); +} + +static void dw_hdma_v0_core_clear_abort_int(struct dw_edma_chan *chan) +{ + struct dw_edma *dw = chan->dw; + + SET_CH_32(dw, chan->dir, chan->id, int_clear, HDMA_V0_ABORT_INT_MASK); +} + +static u32 dw_hdma_v0_core_status_int(struct dw_edma_chan *chan) +{ + struct dw_edma *dw = chan->dw; + + return GET_CH_32(dw, chan->dir, chan->id, int_stat); +} + +static irqreturn_t +dw_hdma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, + dw_edma_handler_t done, dw_edma_handler_t abort) +{ + struct dw_edma *dw = dw_irq->dw; + unsigned long total, pos, val; + irqreturn_t ret = IRQ_NONE; + struct dw_edma_chan *chan; + unsigned long off, mask; + + if (dir == EDMA_DIR_WRITE) { + total = dw->wr_ch_cnt; + off = 0; + mask = dw_irq->wr_mask; + } else { + total = dw->rd_ch_cnt; + off = dw->wr_ch_cnt; + mask = dw_irq->rd_mask; + } + + for_each_set_bit(pos, &mask, total) { + chan = &dw->chan[pos + off]; + + val = dw_hdma_v0_core_status_int(chan); + if (FIELD_GET(HDMA_V0_STOP_INT_MASK, val)) { + dw_hdma_v0_core_clear_done_int(chan); + done(chan); + + ret = IRQ_HANDLED; + } + + if (FIELD_GET(HDMA_V0_ABORT_INT_MASK, val)) { + dw_hdma_v0_core_clear_abort_int(chan); + abort(chan); + + ret = IRQ_HANDLED; + } + } + + return ret; +} + +static void dw_hdma_v0_write_ll_data(struct dw_edma_chunk *chunk, int i, + u32 control, u32 size, u64 sar, u64 dar) +{ + ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli); + + if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) { + struct dw_hdma_v0_lli *lli = chunk->ll_region.vaddr.mem + ofs; + + lli->control = control; + lli->transfer_size = size; + lli->sar.reg = sar; + lli->dar.reg = dar; + } else { + struct dw_hdma_v0_lli __iomem *lli = chunk->ll_region.vaddr.io + ofs; + + writel(control, &lli->control); + writel(size, &lli->transfer_size); + writeq(sar, &lli->sar.reg); + writeq(dar, &lli->dar.reg); + } +} + +static void dw_hdma_v0_write_ll_link(struct dw_edma_chunk *chunk, + int i, u32 control, u64 pointer) +{ + ptrdiff_t ofs = i * sizeof(struct dw_hdma_v0_lli); + + if (chunk->chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) { + struct dw_hdma_v0_llp *llp = chunk->ll_region.vaddr.mem + ofs; + + llp->control = control; + llp->llp.reg = pointer; + } else { + struct dw_hdma_v0_llp __iomem *llp = chunk->ll_region.vaddr.io + ofs; + + writel(control, &llp->control); + writeq(pointer, &llp->llp.reg); + } +} + +static void dw_hdma_v0_core_write_chunk(struct dw_edma_chunk *chunk) +{ + struct dw_edma_burst *child; + struct dw_edma_chan *chan = chunk->chan; + u32 control = 0, i = 0; + int j; + + if (chunk->cb) + control = DW_HDMA_V0_CB; + + j = chunk->bursts_alloc; + list_for_each_entry(child, &chunk->burst->list, list) { + j--; + if (!j) { + control |= DW_HDMA_V0_LIE; + if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL)) + control |= DW_HDMA_V0_RIE; + } + + dw_hdma_v0_write_ll_data(chunk, i++, control, child->sz, + child->sar, child->dar); + } + + control = DW_HDMA_V0_LLP | DW_HDMA_V0_TCB; + if (!chunk->cb) + control |= DW_HDMA_V0_CB; + + dw_hdma_v0_write_ll_link(chunk, i, control, chunk->ll_region.paddr); +} + +static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) +{ + struct dw_edma_chan *chan = chunk->chan; + struct dw_edma *dw = chan->dw; + u32 tmp; + + dw_hdma_v0_core_write_chunk(chunk); + + if (first) { + /* Enable engine */ + SET_CH_32(dw, chan->dir, chan->id, ch_en, BIT(0)); + /* Interrupt enable&unmask - done, abort */ + tmp = GET_CH_32(dw, chan->dir, chan->id, int_setup) | + HDMA_V0_STOP_INT_MASK | HDMA_V0_ABORT_INT_MASK | + HDMA_V0_LOCAL_STOP_INT_EN | HDMA_V0_LOCAL_STOP_INT_EN; + SET_CH_32(dw, chan->dir, chan->id, int_setup, tmp); + /* Channel control */ + SET_CH_32(dw, chan->dir, chan->id, control1, HDMA_V0_LINKLIST_EN); + /* Linked list */ + /* llp is not aligned on 64bit -> keep 32bit accesses */ + SET_CH_32(dw, chan->dir, chan->id, llp.lsb, + lower_32_bits(chunk->ll_region.paddr)); + SET_CH_32(dw, chan->dir, chan->id, llp.msb, + upper_32_bits(chunk->ll_region.paddr)); + } + /* Set consumer cycle */ + SET_CH_32(dw, chan->dir, chan->id, cycle_sync, + HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT); + /* Doorbell */ + SET_CH_32(dw, chan->dir, chan->id, doorbell, HDMA_V0_DOORBELL_START); +} + +static void dw_hdma_v0_core_ch_config(struct dw_edma_chan *chan) +{ + struct dw_edma *dw = chan->dw; + + /* MSI done addr - low, high */ + SET_CH_32(dw, chan->dir, chan->id, msi_stop.lsb, chan->msi.address_lo); + SET_CH_32(dw, chan->dir, chan->id, msi_stop.msb, chan->msi.address_hi); + /* MSI abort addr - low, high */ + SET_CH_32(dw, chan->dir, chan->id, msi_abort.lsb, chan->msi.address_lo); + SET_CH_32(dw, chan->dir, chan->id, msi_abort.msb, chan->msi.address_hi); + /* config MSI data */ + SET_CH_32(dw, chan->dir, chan->id, msi_msgdata, chan->msi.data); +} + +/* HDMA debugfs callbacks */ +static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw) +{ +} + +static const struct dw_edma_core_ops dw_hdma_v0_core = { + .off = dw_hdma_v0_core_off, + .ch_count = dw_hdma_v0_core_ch_count, + .ch_status = dw_hdma_v0_core_ch_status, + .handle_int = dw_hdma_v0_core_handle_int, + .start = dw_hdma_v0_core_start, + .ch_config = dw_hdma_v0_core_ch_config, + .debugfs_on = dw_hdma_v0_core_debugfs_on, +}; + +void dw_hdma_v0_core_register(struct dw_edma *dw) +{ + dw->core = &dw_hdma_v0_core; +} diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.h b/drivers/dma/dw-edma/dw-hdma-v0-core.h new file mode 100644 index 000000000000..c373b4f0bd8a --- /dev/null +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Cai Huoqing + * Synopsys DesignWare HDMA v0 core + * + * Author: Cai Huoqing + */ + +#ifndef _DW_HDMA_V0_CORE_H +#define _DW_HDMA_V0_CORE_H + +#include + +/* HDMA core register */ +void dw_hdma_v0_core_register(struct dw_edma *dw); + +#endif /* _DW_HDMA_V0_CORE_H */ diff --git a/drivers/dma/dw-edma/dw-hdma-v0-regs.h b/drivers/dma/dw-edma/dw-hdma-v0-regs.h new file mode 100644 index 000000000000..a974abdf8aaf --- /dev/null +++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Cai Huoqing + * Synopsys DesignWare HDMA v0 reg + * + * Author: Cai Huoqing + */ + +#ifndef _DW_HDMA_V0_REGS_H +#define _DW_HDMA_V0_REGS_H + +#include + +#define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6) +#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5) +#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4) +#define HDMA_V0_REMOTEL_STOP_INT_EN BIT(3) +#define HDMA_V0_ABORT_INT_MASK BIT(2) +#define HDMA_V0_STOP_INT_MASK BIT(0) +#define HDMA_V0_LINKLIST_EN BIT(0) +#define HDMA_V0_CONSUMER_CYCLE_STAT BIT(1) +#define HDMA_V0_CONSUMER_CYCLE_BIT BIT(0) +#define HDMA_V0_DOORBELL_START BIT(0) +#define HDMA_V0_CH_STATUS_MASK GENMASK(1, 0) + +struct dw_hdma_v0_ch_regs { + u32 ch_en; /* 0x0000 */ + u32 doorbell; /* 0x0004 */ + u32 prefetch; /* 0x0008 */ + u32 handshake; /* 0x000c */ + union { + u64 reg; /* 0x0010..0x0014 */ + struct { + u32 lsb; /* 0x0010 */ + u32 msb; /* 0x0014 */ + }; + } llp; + u32 cycle_sync; /* 0x0018 */ + u32 transfer_size; /* 0x001c */ + union { + u64 reg; /* 0x0020..0x0024 */ + struct { + u32 lsb; /* 0x0020 */ + u32 msb; /* 0x0024 */ + }; + } sar; + union { + u64 reg; /* 0x0028..0x002c */ + struct { + u32 lsb; /* 0x0028 */ + u32 msb; /* 0x002c */ + }; + } dar; + u32 watermark_en; /* 0x0030 */ + u32 control1; /* 0x0034 */ + u32 func_num; /* 0x0038 */ + u32 qos; /* 0x003c */ + u32 padding_1[16]; /* 0x0040..0x007c */ + u32 ch_stat; /* 0x0080 */ + u32 int_stat; /* 0x0084 */ + u32 int_setup; /* 0x0088 */ + u32 int_clear; /* 0x008c */ + union { + u64 reg; /* 0x0090..0x0094 */ + struct { + u32 lsb; /* 0x0090 */ + u32 msb; /* 0x0094 */ + }; + } msi_stop; + union { + u64 reg; /* 0x0098..0x009c */ + struct { + u32 lsb; /* 0x0098 */ + u32 msb; /* 0x009c */ + }; + } msi_watermark; + union { + u64 reg; /* 0x00a0..0x00a4 */ + struct { + u32 lsb; /* 0x00a0 */ + u32 msb; /* 0x00a4 */ + }; + } msi_abort; + u32 msi_msgdata; /* 0x00a8 */ + u32 padding_2[21]; /* 0x00ac..0x00fc */ +} __packed; + +struct dw_hdma_v0_ch { + struct dw_hdma_v0_ch_regs wr; /* 0x0000 */ + struct dw_hdma_v0_ch_regs rd; /* 0x0100 */ +} __packed; + +struct dw_hdma_v0_regs { + struct dw_hdma_v0_ch ch[HDMA_V0_MAX_NR_CH]; /* 0x0000..0x0fa8 */ +} __packed; + +struct dw_hdma_v0_lli { + u32 control; + u32 transfer_size; + union { + u64 reg; + struct { + u32 lsb; + u32 msb; + }; + } sar; + union { + u64 reg; + struct { + u32 lsb; + u32 msb; + }; + } dar; +} __packed; + +struct dw_hdma_v0_llp { + u32 control; + u32 reserved; + union { + u64 reg; + struct { + u32 lsb; + u32 msb; + }; + } llp; +} __packed; + +#endif /* _DW_HDMA_V0_REGS_H */ diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h index ed401c965a87..3080747689f6 100644 --- a/include/linux/dma/edma.h +++ b/include/linux/dma/edma.h @@ -48,7 +48,8 @@ struct dw_edma_plat_ops { enum dw_edma_map_format { EDMA_MF_EDMA_LEGACY = 0x0, EDMA_MF_EDMA_UNROLL = 0x1, - EDMA_MF_HDMA_COMPAT = 0x5 + EDMA_MF_HDMA_COMPAT = 0x5, + EDMA_MF_HDMA_NATIVE = 0x7, }; /** From 353d5c241e83c4de04ca5ec0d7922bfb0809aa25 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Sat, 20 May 2023 13:08:52 +0800 Subject: [PATCH 22/28] dmaengine: dw-edma: Add HDMA DebugFS support Add HDMA DebugFS support to show registers content Signed-off-by: Cai Huoqing Reviewed-by: Serge Semin Reviewed-by: Manivannan Sadhasivam Tested-by: Serge Semin Link: https://lore.kernel.org/r/20230520050854.73160-5-cai.huoqing@linux.dev Signed-off-by: Vinod Koul --- drivers/dma/dw-edma/Makefile | 3 +- drivers/dma/dw-edma/dw-hdma-v0-core.c | 2 + drivers/dma/dw-edma/dw-hdma-v0-debugfs.c | 170 +++++++++++++++++++++++ drivers/dma/dw-edma/dw-hdma-v0-debugfs.h | 22 +++ 4 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 drivers/dma/dw-edma/dw-hdma-v0-debugfs.c create mode 100644 drivers/dma/dw-edma/dw-hdma-v0-debugfs.h diff --git a/drivers/dma/dw-edma/Makefile b/drivers/dma/dw-edma/Makefile index b1c91ef2c63d..83ab58f87760 100644 --- a/drivers/dma/dw-edma/Makefile +++ b/drivers/dma/dw-edma/Makefile @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DW_EDMA) += dw-edma.o -dw-edma-$(CONFIG_DEBUG_FS) := dw-edma-v0-debugfs.o +dw-edma-$(CONFIG_DEBUG_FS) := dw-edma-v0-debugfs.o \ + dw-hdma-v0-debugfs.o dw-edma-objs := dw-edma-core.o \ dw-edma-v0-core.o \ dw-hdma-v0-core.o $(dw-edma-y) diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c index 22b7b0410deb..00b735a0202a 100644 --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c @@ -11,6 +11,7 @@ #include "dw-edma-core.h" #include "dw-hdma-v0-core.h" #include "dw-hdma-v0-regs.h" +#include "dw-hdma-v0-debugfs.h" enum dw_hdma_control { DW_HDMA_V0_CB = BIT(0), @@ -276,6 +277,7 @@ static void dw_hdma_v0_core_ch_config(struct dw_edma_chan *chan) /* HDMA debugfs callbacks */ static void dw_hdma_v0_core_debugfs_on(struct dw_edma *dw) { + dw_hdma_v0_debugfs_on(dw); } static const struct dw_edma_core_ops dw_hdma_v0_core = { diff --git a/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c new file mode 100644 index 000000000000..520c81978b08 --- /dev/null +++ b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 Cai Huoqing + * Synopsys DesignWare HDMA v0 debugfs + * + * Author: Cai Huoqing + */ + +#include +#include + +#include "dw-hdma-v0-debugfs.h" +#include "dw-hdma-v0-regs.h" +#include "dw-edma-core.h" + +#define REGS_ADDR(dw, name) \ + ({ \ + struct dw_hdma_v0_regs __iomem *__regs = (dw)->chip->reg_base; \ + \ + (void __iomem *)&__regs->name; \ + }) + +#define REGS_CH_ADDR(dw, name, _dir, _ch) \ + ({ \ + struct dw_hdma_v0_ch_regs __iomem *__ch_regs; \ + \ + if (_dir == EDMA_DIR_READ) \ + __ch_regs = REGS_ADDR(dw, ch[_ch].rd); \ + else \ + __ch_regs = REGS_ADDR(dw, ch[_ch].wr); \ + \ + (void __iomem *)&__ch_regs->name; \ + }) + +#define CTX_REGISTER(dw, name, dir, ch) \ + {#name, REGS_CH_ADDR(dw, name, dir, ch)} + +#define WRITE_STR "write" +#define READ_STR "read" +#define CHANNEL_STR "channel" +#define REGISTERS_STR "registers" + +struct dw_hdma_debugfs_entry { + const char *name; + void __iomem *reg; +}; + +static int dw_hdma_debugfs_u32_get(void *data, u64 *val) +{ + struct dw_hdma_debugfs_entry *entry = data; + void __iomem *reg = entry->reg; + + *val = readl(reg); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_hdma_debugfs_u32_get, NULL, "0x%08llx\n"); + +static void dw_hdma_debugfs_create_x32(struct dw_edma *dw, + const struct dw_hdma_debugfs_entry ini[], + int nr_entries, struct dentry *dent) +{ + struct dw_hdma_debugfs_entry *entries; + int i; + + entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries), + GFP_KERNEL); + if (!entries) + return; + + for (i = 0; i < nr_entries; i++) { + entries[i] = ini[i]; + + debugfs_create_file_unsafe(entries[i].name, 0444, dent, + &entries[i], &fops_x32); + } +} + +static void dw_hdma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir, + u16 ch, struct dentry *dent) +{ + const struct dw_hdma_debugfs_entry debugfs_regs[] = { + CTX_REGISTER(dw, ch_en, dir, ch), + CTX_REGISTER(dw, doorbell, dir, ch), + CTX_REGISTER(dw, prefetch, dir, ch), + CTX_REGISTER(dw, handshake, dir, ch), + CTX_REGISTER(dw, llp.lsb, dir, ch), + CTX_REGISTER(dw, llp.msb, dir, ch), + CTX_REGISTER(dw, cycle_sync, dir, ch), + CTX_REGISTER(dw, transfer_size, dir, ch), + CTX_REGISTER(dw, sar.lsb, dir, ch), + CTX_REGISTER(dw, sar.msb, dir, ch), + CTX_REGISTER(dw, dar.lsb, dir, ch), + CTX_REGISTER(dw, dar.msb, dir, ch), + CTX_REGISTER(dw, watermark_en, dir, ch), + CTX_REGISTER(dw, control1, dir, ch), + CTX_REGISTER(dw, func_num, dir, ch), + CTX_REGISTER(dw, qos, dir, ch), + CTX_REGISTER(dw, ch_stat, dir, ch), + CTX_REGISTER(dw, int_stat, dir, ch), + CTX_REGISTER(dw, int_setup, dir, ch), + CTX_REGISTER(dw, int_clear, dir, ch), + CTX_REGISTER(dw, msi_stop.lsb, dir, ch), + CTX_REGISTER(dw, msi_stop.msb, dir, ch), + CTX_REGISTER(dw, msi_watermark.lsb, dir, ch), + CTX_REGISTER(dw, msi_watermark.msb, dir, ch), + CTX_REGISTER(dw, msi_abort.lsb, dir, ch), + CTX_REGISTER(dw, msi_abort.msb, dir, ch), + CTX_REGISTER(dw, msi_msgdata, dir, ch), + }; + int nr_entries = ARRAY_SIZE(debugfs_regs); + + dw_hdma_debugfs_create_x32(dw, debugfs_regs, nr_entries, dent); +} + +static void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent) +{ + struct dentry *regs_dent, *ch_dent; + char name[16]; + int i; + + regs_dent = debugfs_create_dir(WRITE_STR, dent); + + for (i = 0; i < dw->wr_ch_cnt; i++) { + snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i); + + ch_dent = debugfs_create_dir(name, regs_dent); + + dw_hdma_debugfs_regs_ch(dw, EDMA_DIR_WRITE, i, ch_dent); + } +} + +static void dw_hdma_debugfs_regs_rd(struct dw_edma *dw, struct dentry *dent) +{ + struct dentry *regs_dent, *ch_dent; + char name[16]; + int i; + + regs_dent = debugfs_create_dir(READ_STR, dent); + + for (i = 0; i < dw->rd_ch_cnt; i++) { + snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i); + + ch_dent = debugfs_create_dir(name, regs_dent); + + dw_hdma_debugfs_regs_ch(dw, EDMA_DIR_READ, i, ch_dent); + } +} + +static void dw_hdma_debugfs_regs(struct dw_edma *dw) +{ + struct dentry *regs_dent; + + regs_dent = debugfs_create_dir(REGISTERS_STR, dw->dma.dbg_dev_root); + + dw_hdma_debugfs_regs_wr(dw, regs_dent); + dw_hdma_debugfs_regs_rd(dw, regs_dent); +} + +void dw_hdma_v0_debugfs_on(struct dw_edma *dw) +{ + if (!debugfs_initialized()) + return; + + debugfs_create_u32("mf", 0444, dw->dma.dbg_dev_root, &dw->chip->mf); + debugfs_create_u16("wr_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->wr_ch_cnt); + debugfs_create_u16("rd_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->rd_ch_cnt); + + dw_hdma_debugfs_regs(dw); +} diff --git a/drivers/dma/dw-edma/dw-hdma-v0-debugfs.h b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.h new file mode 100644 index 000000000000..e6842c83777d --- /dev/null +++ b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Cai Huoqing + * Synopsys DesignWare HDMA v0 debugfs + * + * Author: Cai Huoqing + */ + +#ifndef _DW_HDMA_V0_DEBUG_FS_H +#define _DW_HDMA_V0_DEBUG_FS_H + +#include + +#ifdef CONFIG_DEBUG_FS +void dw_hdma_v0_debugfs_on(struct dw_edma *dw); +#else +static inline void dw_hdma_v0_debugfs_on(struct dw_edma *dw) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +#endif /* _DW_HDMA_V0_DEBUG_FS_H */ From 8975dd41a9dbca3b47f7b8dac5bc4dfb23011000 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Fri, 19 May 2023 13:00:13 +0200 Subject: [PATCH 23/28] dmaengine: qcom: bam_dma: allow omitting num-{channels,ees} The bam_dma driver needs to know the number of channels and execution environments (EEs) at probe time. If we are in full control of the BAM controller this information can be obtained from the BAM identification registers (BAM_REVISION/BAM_NUM_PIPES). When the BAM is "controlled remotely" it is more complicated. The BAM might not be on at probe time, so reading the registers could fail. This is why the information must be added to the device tree in this case, using "num-channels" and "qcom,num-ees". However, there are also some BAM instances that are initialized by something else but we still have a clock that allows to turn it on when needed. This can be set up in the DT with "qcom,controlled-remotely" and "clocks" and is already supported by the bam_dma driver. Examples for this are the typical BLSP BAM instances on older SoCs, QPIC BAM (for NAND) and the crypto BAM on some SoCs. In this case, there is no need to read "num-channels" and "qcom,num-ees" from the DT. The BAN can be turned on using the clock so we can just read it from the BAM registers like in the normal case. Check for the BAM clock earlier and skip reading "num-channels" and "qcom,num-ees" if it is present to allow simplifying the DT description a bit. Signed-off-by: Stephan Gerhold Reviewed-by: Bhupesh Sharma Link: https://lore.kernel.org/r/20230518-bamclk-dt-v2-1-a1a857b966ca@gerhold.net Signed-off-by: Vinod Koul --- drivers/dma/qcom/bam_dma.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 1e47d27e1f81..4c3eb972039d 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -1272,7 +1272,15 @@ static int bam_dma_probe(struct platform_device *pdev) bdev->powered_remotely = of_property_read_bool(pdev->dev.of_node, "qcom,powered-remotely"); - if (bdev->controlled_remotely || bdev->powered_remotely) { + if (bdev->controlled_remotely || bdev->powered_remotely) + bdev->bamclk = devm_clk_get_optional(bdev->dev, "bam_clk"); + else + bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk"); + + if (IS_ERR(bdev->bamclk)) + return PTR_ERR(bdev->bamclk); + + if (!bdev->bamclk) { ret = of_property_read_u32(pdev->dev.of_node, "num-channels", &bdev->num_channels); if (ret) @@ -1284,14 +1292,6 @@ static int bam_dma_probe(struct platform_device *pdev) dev_err(bdev->dev, "num-ees unspecified in dt\n"); } - if (bdev->controlled_remotely || bdev->powered_remotely) - bdev->bamclk = devm_clk_get_optional(bdev->dev, "bam_clk"); - else - bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk"); - - if (IS_ERR(bdev->bamclk)) - return PTR_ERR(bdev->bamclk); - ret = clk_prepare_enable(bdev->bamclk); if (ret) { dev_err(bdev->dev, "failed to prepare/enable clock\n"); From 3a4905c59832896f811f8b3e840be936ae598dd1 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 21 May 2023 18:02:48 +0800 Subject: [PATCH 24/28] dmaengine: dw-axi-dmac: Don't set chancnt The dma framework will calculate the dma channels chancnt, setting it ourself is wrong. Signed-off-by: Jisheng Zhang Link: https://lore.kernel.org/r/20230521100252.3197-2-jszhang@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 1 - 1 file changed, 1 deletion(-) 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 6937cc0c0b65..796b6caf0bab 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1466,7 +1466,6 @@ static int dw_probe(struct platform_device *pdev) dma_cap_set(DMA_CYCLIC, dw->dma.cap_mask); /* DMA capabilities */ - dw->dma.chancnt = hdata->nr_channels; dw->dma.max_burst = hdata->axi_rw_burst_len; dw->dma.src_addr_widths = AXI_DMA_BUSWIDTHS; dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS; From d27afd7ae6a316fac4d1f613db2de02ce1e872a4 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 21 May 2023 18:02:49 +0800 Subject: [PATCH 25/28] dmaengine: axi-dmac: Don't set chancnt The dma framework will calculate the dma channels chancnt, setting it ourself is wrong. Signed-off-by: Jisheng Zhang Acked-by: Lars-Peter Clausen Link: https://lore.kernel.org/r/20230521100252.3197-3-jszhang@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/dma-axi-dmac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index a812b9b00e6b..fc7cdad37161 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -963,7 +963,6 @@ static int axi_dmac_probe(struct platform_device *pdev) dma_dev->device_terminate_all = axi_dmac_terminate_all; dma_dev->device_synchronize = axi_dmac_synchronize; dma_dev->dev = &pdev->dev; - dma_dev->chancnt = 1; dma_dev->src_addr_widths = BIT(dmac->chan.src_width); dma_dev->dst_addr_widths = BIT(dmac->chan.dest_width); dma_dev->directions = BIT(dmac->chan.direction); From c68533337cad07e9239b7cac42d4e07f844ba95b Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 21 May 2023 18:02:50 +0800 Subject: [PATCH 26/28] dmaengine: plx_dma: Don't set chancnt The dma framework will calculate the dma channels chancnt, setting it ourself is wrong. Signed-off-by: Jisheng Zhang Acked-by: Logan Gunthorpe Link: https://lore.kernel.org/r/20230521100252.3197-4-jszhang@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/plx_dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/plx_dma.c b/drivers/dma/plx_dma.c index 12725fa1655f..34b6416c3287 100644 --- a/drivers/dma/plx_dma.c +++ b/drivers/dma/plx_dma.c @@ -517,7 +517,6 @@ static int plx_dma_create(struct pci_dev *pdev) plxdev->bar = pcim_iomap_table(pdev)[0]; dma = &plxdev->dma_dev; - dma->chancnt = 1; INIT_LIST_HEAD(&dma->channels); dma_cap_set(DMA_MEMCPY, dma->cap_mask); dma->copy_align = DMAENGINE_ALIGN_1_BYTE; From a10119a8b49bbd59c1bea4dfe5ea75d08d8506e5 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 21 May 2023 18:02:51 +0800 Subject: [PATCH 27/28] dmaengine: hidma: Don't set chancnt The dma framework will calculate the dma channels chancnt, setting it ourself is wrong. Signed-off-by: Jisheng Zhang Link: https://lore.kernel.org/r/20230521100252.3197-5-jszhang@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 04d1c33afc12..344525c3a32f 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -214,7 +214,6 @@ static int hidma_chan_init(struct hidma_dev *dmadev, u32 dma_sig) spin_lock_init(&mchan->lock); list_add_tail(&mchan->chan.device_node, &ddev->channels); - dmadev->ddev.chancnt++; return 0; } From 907514a7dc4c574136e8fb576b014be05d25813a Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sun, 21 May 2023 18:02:52 +0800 Subject: [PATCH 28/28] dmaengine: sprd: Don't set chancnt The dma framework will calculate the dma channels chancnt, setting it ourself is wrong. Signed-off-by: Jisheng Zhang Reviewed-by: Baolin Wang Link: https://lore.kernel.org/r/20230521100252.3197-6-jszhang@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 474d3ba8ec9f..2b639adb48ba 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -1169,7 +1169,6 @@ static int sprd_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_MEMCPY, sdev->dma_dev.cap_mask); sdev->total_chns = chn_count; - sdev->dma_dev.chancnt = chn_count; INIT_LIST_HEAD(&sdev->dma_dev.channels); INIT_LIST_HEAD(&sdev->dma_dev.global_node); sdev->dma_dev.dev = &pdev->dev;