[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <f3ffb5fc-7e85-4949-a326-7515e491d43d@marvell.com>
Date: Thu, 31 Oct 2024 23:45:45 +0530
From: Amit Singh Tomar <amitsinght@...vell.com>
To: Csókás, Bence <csokas.bence@...lan.hu>,
dmaengine@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
linux-sunxi@...ts.linux.dev, linux-kernel@...r.kernel.org
Cc: Mesih Kilinc <mesihkilinc@...il.com>, Vinod Koul <vkoul@...nel.org>,
Chen-Yu Tsai <wens@...e.org>,
Jernej Skrabec <jernej.skrabec@...il.com>,
Samuel Holland <samuel@...lland.org>
Subject: [PATCH v4 01/10] dma-engine: sun4i: Add a quirk to support different
chips
Hi,
>
> Notes:
> Changes in v2:
> * Whitespace
>
> drivers/dma/sun4i-dma.c | 138 ++++++++++++++++++++++++++++++----------
> 1 file changed, 106 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
> index 2e7f9b07fdd2..d472f57a39ea 100644
> --- a/drivers/dma/sun4i-dma.c
> +++ b/drivers/dma/sun4i-dma.c
> @@ -13,6 +13,7 @@
> #include <linux/interrupt.h>
> #include <linux/module.h>
> #include <linux/of_dma.h>
> +#include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
> @@ -31,6 +32,8 @@
> #define SUN4I_DMA_CFG_SRC_ADDR_MODE(mode) ((mode) << 5)
> #define SUN4I_DMA_CFG_SRC_DRQ_TYPE(type) (type)
>
> +#define SUN4I_MAX_BURST 8
> +
> /** Normal DMA register values **/
>
> /* Normal DMA source/destination data request type values */
> @@ -132,6 +135,32 @@
> #define SUN4I_DDMA_MAX_SEG_SIZE SZ_16M
> #define SUN4I_DMA_MAX_SEG_SIZE SUN4I_NDMA_MAX_SEG_SIZE
>
> +/*
> + * Hardware channels / ports representation
> + *
> + * The hardware is used in several SoCs, with differing numbers
> + * of channels and endpoints. This structure ties those numbers
> + * to a certain compatible string.
> + */
> +struct sun4i_dma_config {
> + u32 ndma_nr_max_channels;
> + u32 ndma_nr_max_vchans;
> +
> + u32 ddma_nr_max_channels;
> + u32 ddma_nr_max_vchans;
> +
> + u32 dma_nr_max_channels;
> +
> + void (*set_dst_data_width)(u32 *p_cfg, s8 data_width);
> + void (*set_src_data_width)(u32 *p_cfg, s8 data_width);
> + int (*convert_burst)(u32 maxburst);
> +
> + u8 ndma_drq_sdram;
> + u8 ddma_drq_sdram;
> +
> + u8 max_burst;
> +};
> +
> struct sun4i_dma_pchan {
> /* Register base of channel */
> void __iomem *base;
> @@ -170,7 +199,7 @@ struct sun4i_dma_contract {
> };
>
> struct sun4i_dma_dev {
> - DECLARE_BITMAP(pchans_used, SUN4I_DMA_NR_MAX_CHANNELS);
Is this macro "SUN4I_DMA_NR_MAX_CHANNELS" referenced elsewhere? If it’s
not in use, can we clean it up?
> + unsigned long *pchans_used;
> struct dma_device slave;
> struct sun4i_dma_pchan *pchans;
> struct sun4i_dma_vchan *vchans;
> @@ -178,6 +207,7 @@ struct sun4i_dma_dev {
> struct clk *clk;
> int irq;
> spinlock_t lock;
> + const struct sun4i_dma_config *cfg;
> };
>
> static struct sun4i_dma_dev *to_sun4i_dma_dev(struct dma_device *dev)
> @@ -200,7 +230,17 @@ static struct device *chan2dev(struct dma_chan *chan)
> return &chan->dev->device;
> }
>
> -static int convert_burst(u32 maxburst)
> +static void set_dst_data_width_a10(u32 *p_cfg, s8 data_width)
> +{
> + *p_cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(data_width);
> +}
> +
> +static void set_src_data_width_a10(u32 *p_cfg, s8 data_width)
> +{
> + *p_cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(data_width);
> +}
> +
> +static int convert_burst_a10(u32 maxburst)
> {
> if (maxburst > 8)
> return -EINVAL;
> @@ -233,15 +273,15 @@ static struct sun4i_dma_pchan *find_and_use_pchan(struct sun4i_dma_dev *priv,
> int i, max;
>
> /*
> - * pchans 0-SUN4I_NDMA_NR_MAX_CHANNELS are normal, and
> - * SUN4I_NDMA_NR_MAX_CHANNELS+ are dedicated ones
> + * pchans 0-priv->cfg->ndma_nr_max_channels are normal, and
> + * priv->cfg->ndma_nr_max_channels+ are dedicated ones
> */
> if (vchan->is_dedicated) {
> - i = SUN4I_NDMA_NR_MAX_CHANNELS;
> - max = SUN4I_DMA_NR_MAX_CHANNELS;
> + i = priv->cfg->ndma_nr_max_channels;
> + max = priv->cfg->dma_nr_max_channels;
> } else {
> i = 0;
> - max = SUN4I_NDMA_NR_MAX_CHANNELS;
> + max = priv->cfg->ndma_nr_max_channels;
> }
>
> spin_lock_irqsave(&priv->lock, flags);
> @@ -444,6 +484,7 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
> size_t len, struct dma_slave_config *sconfig,
> enum dma_transfer_direction direction)
> {
> + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
> struct sun4i_dma_promise *promise;
> int ret;
>
> @@ -467,13 +508,13 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
> sconfig->src_addr_width, sconfig->dst_addr_width);
>
> /* Source burst */
> - ret = convert_burst(sconfig->src_maxburst);
> + ret = priv->cfg->convert_burst(sconfig->src_maxburst);
> if (ret < 0)
> goto fail;
> promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
>
> /* Destination burst */
> - ret = convert_burst(sconfig->dst_maxburst);
> + ret = priv->cfg->convert_burst(sconfig->dst_maxburst);
> if (ret < 0)
> goto fail;
> promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
> @@ -482,13 +523,13 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
> ret = convert_buswidth(sconfig->src_addr_width);
> if (ret < 0)
> goto fail;
> - promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
> + priv->cfg->set_src_data_width(&promise->cfg, ret);
>
> /* Destination bus width */
> ret = convert_buswidth(sconfig->dst_addr_width);
> if (ret < 0)
> goto fail;
> - promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
> + priv->cfg->set_dst_data_width(&promise->cfg, ret);
>
> return promise;
>
> @@ -510,6 +551,7 @@ static struct sun4i_dma_promise *
> generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
> size_t len, struct dma_slave_config *sconfig)
> {
> + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
> struct sun4i_dma_promise *promise;
> int ret;
>
> @@ -524,13 +566,13 @@ generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
> SUN4I_DDMA_CFG_BYTE_COUNT_MODE_REMAIN;
>
> /* Source burst */
> - ret = convert_burst(sconfig->src_maxburst);
> + ret = priv->cfg->convert_burst(sconfig->src_maxburst);
> if (ret < 0)
> goto fail;
> promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
>
> /* Destination burst */
> - ret = convert_burst(sconfig->dst_maxburst);
> + ret = priv->cfg->convert_burst(sconfig->dst_maxburst);
> if (ret < 0)
> goto fail;
> promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
> @@ -539,13 +581,13 @@ generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
> ret = convert_buswidth(sconfig->src_addr_width);
> if (ret < 0)
> goto fail;
> - promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
> + priv->cfg->set_src_data_width(&promise->cfg, ret);
>
> /* Destination bus width */
> ret = convert_buswidth(sconfig->dst_addr_width);
> if (ret < 0)
> goto fail;
> - promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
> + priv->cfg->set_dst_data_width(&promise->cfg, ret);
>
> return promise;
>
> @@ -622,6 +664,7 @@ static struct dma_async_tx_descriptor *
> sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
> dma_addr_t src, size_t len, unsigned long flags)
> {
> + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
> struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
> struct dma_slave_config *sconfig = &vchan->cfg;
> struct sun4i_dma_promise *promise;
> @@ -638,8 +681,8 @@ sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
> */
> sconfig->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> sconfig->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> - sconfig->src_maxburst = 8;
> - sconfig->dst_maxburst = 8;
> + sconfig->src_maxburst = priv->cfg->max_burst;
> + sconfig->dst_maxburst = priv->cfg->max_burst;
>
> if (vchan->is_dedicated)
> promise = generate_ddma_promise(chan, src, dest, len, sconfig);
> @@ -654,11 +697,13 @@ sun4i_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
>
> /* Configure memcpy mode */
> if (vchan->is_dedicated) {
> - promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM) |
> - SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_DDMA_DRQ_TYPE_SDRAM);
> + promise->cfg |=
> + SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ddma_drq_sdram) |
> + SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ddma_drq_sdram);
> } else {
> - promise->cfg |= SUN4I_DMA_CFG_SRC_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM) |
> - SUN4I_DMA_CFG_DST_DRQ_TYPE(SUN4I_NDMA_DRQ_TYPE_SDRAM);
> + promise->cfg |=
> + SUN4I_DMA_CFG_SRC_DRQ_TYPE(priv->cfg->ndma_drq_sdram) |
> + SUN4I_DMA_CFG_DST_DRQ_TYPE(priv->cfg->ndma_drq_sdram);
> }
>
> /* Fill the contract with our only promise */
> @@ -673,6 +718,7 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
> size_t period_len, enum dma_transfer_direction dir,
> unsigned long flags)
> {
> + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
> struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
> struct dma_slave_config *sconfig = &vchan->cfg;
> struct sun4i_dma_promise *promise;
> @@ -696,11 +742,11 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
> if (vchan->is_dedicated) {
> io_mode = SUN4I_DDMA_ADDR_MODE_IO;
> linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR;
> - ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM;
> + ram_type = priv->cfg->ddma_drq_sdram;
> } else {
> io_mode = SUN4I_NDMA_ADDR_MODE_IO;
> linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR;
> - ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM;
> + ram_type = priv->cfg->ndma_drq_sdram;
> }
>
> if (dir == DMA_MEM_TO_DEV) {
> @@ -793,6 +839,7 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
> unsigned int sg_len, enum dma_transfer_direction dir,
> unsigned long flags, void *context)
> {
> + struct sun4i_dma_dev *priv = to_sun4i_dma_dev(chan->device);
> struct sun4i_dma_vchan *vchan = to_sun4i_dma_vchan(chan);
> struct dma_slave_config *sconfig = &vchan->cfg;
> struct sun4i_dma_promise *promise;
> @@ -818,11 +865,11 @@ sun4i_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
> if (vchan->is_dedicated) {
> io_mode = SUN4I_DDMA_ADDR_MODE_IO;
> linear_mode = SUN4I_DDMA_ADDR_MODE_LINEAR;
> - ram_type = SUN4I_DDMA_DRQ_TYPE_SDRAM;
> + ram_type = priv->cfg->ddma_drq_sdram;
> } else {
> io_mode = SUN4I_NDMA_ADDR_MODE_IO;
> linear_mode = SUN4I_NDMA_ADDR_MODE_LINEAR;
> - ram_type = SUN4I_NDMA_DRQ_TYPE_SDRAM;
> + ram_type = priv->cfg->ndma_drq_sdram;
> }
>
> if (dir == DMA_MEM_TO_DEV)
> @@ -1150,6 +1197,10 @@ static int sun4i_dma_probe(struct platform_device *pdev)
> if (!priv)
> return -ENOMEM;
>
> + priv->cfg = of_device_get_match_data(&pdev->dev);
> + if (!priv->cfg)
> + return -ENODEV;
> +
> priv->base = devm_platform_ioremap_resource(pdev, 0);
> if (IS_ERR(priv->base))
> return PTR_ERR(priv->base);
> @@ -1197,23 +1248,26 @@ static int sun4i_dma_probe(struct platform_device *pdev)
>
> priv->slave.dev = &pdev->dev;
>
> - priv->pchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_CHANNELS,
> + priv->pchans = devm_kcalloc(&pdev->dev, priv->cfg->dma_nr_max_channels,
> sizeof(struct sun4i_dma_pchan), GFP_KERNEL);
> priv->vchans = devm_kcalloc(&pdev->dev, SUN4I_DMA_NR_MAX_VCHANS,
> sizeof(struct sun4i_dma_vchan), GFP_KERNEL);
> - if (!priv->vchans || !priv->pchans)
> + priv->pchans_used = devm_kcalloc(&pdev->dev,
> + BITS_TO_LONGS(priv->cfg->dma_nr_max_channels),
> + sizeof(unsigned long), GFP_KERNEL);
> + if (!priv->vchans || !priv->pchans || !priv->pchans_used)
> return -ENOMEM;
>
> /*
> - * [0..SUN4I_NDMA_NR_MAX_CHANNELS) are normal pchans, and
> - * [SUN4I_NDMA_NR_MAX_CHANNELS..SUN4I_DMA_NR_MAX_CHANNELS) are
> + * [0..priv->cfg->ndma_nr_max_channels) are normal pchans, and
> + * [priv->cfg->ndma_nr_max_channels..priv->cfg->dma_nr_max_channels) are
> * dedicated ones
> */
> - for (i = 0; i < SUN4I_NDMA_NR_MAX_CHANNELS; i++)
> + for (i = 0; i < priv->cfg->ndma_nr_max_channels; i++)
> priv->pchans[i].base = priv->base +
> SUN4I_NDMA_CHANNEL_REG_BASE(i);
>
> - for (j = 0; i < SUN4I_DMA_NR_MAX_CHANNELS; i++, j++) {
> + for (j = 0; i < priv->cfg->dma_nr_max_channels; i++, j++) {
> priv->pchans[i].base = priv->base +
> SUN4I_DDMA_CHANNEL_REG_BASE(j);
> priv->pchans[i].is_dedicated = 1;
> @@ -1284,8 +1338,28 @@ static void sun4i_dma_remove(struct platform_device *pdev)
> clk_disable_unprepare(priv->clk);
> }
>
> +static struct sun4i_dma_config sun4i_a10_dma_cfg = {
> + .ndma_nr_max_channels = SUN4I_NDMA_NR_MAX_CHANNELS,
> + .ndma_nr_max_vchans = SUN4I_NDMA_NR_MAX_VCHANS,
> +
> + .ddma_nr_max_channels = SUN4I_DDMA_NR_MAX_CHANNELS,
> + .ddma_nr_max_vchans = SUN4I_DDMA_NR_MAX_VCHANS,
> +
> + .dma_nr_max_channels = SUN4I_NDMA_NR_MAX_CHANNELS +
> + SUN4I_DDMA_NR_MAX_CHANNELS,
> +
Or else use "SUN4I_DMA_NR_MAX_CHANNELS" here.
> + .set_dst_data_width = set_dst_data_width_a10,
> + .set_src_data_width = set_src_data_width_a10,
> + .convert_burst = convert_burst_a10,
> +
> + .ndma_drq_sdram = SUN4I_NDMA_DRQ_TYPE_SDRAM,
> + .ddma_drq_sdram = SUN4I_DDMA_DRQ_TYPE_SDRAM,
> +
> + .max_burst = SUN4I_MAX_BURST,
> +};
> +
> static const struct of_device_id sun4i_dma_match[] = {
> - { .compatible = "allwinner,sun4i-a10-dma" },
> + { .compatible = "allwinner,sun4i-a10-dma", .data = &sun4i_a10_dma_cfg },
> { /* sentinel */ },
> };
> MODULE_DEVICE_TABLE(of, sun4i_dma_match);
> --
> 2.34.1
>
>
>
Powered by blists - more mailing lists