Re: [PATCH 2/2] dma: xilinx: Add driver for Video Framebuffer IP

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Dec 20, 2017 at 02:00:18PM +0530, Vishal Sagar wrote:
> The Video Framebuffer IP is available in two forms: read or write.
> This driver supports either form of the IP.
> Each IP is a single channel DMA and is video format aware.
> It can read/write video data arranged from/to memory as packed or
> semi-planar way based on the selected video format.
> To get list of supported video formats, clients can call certain
> APIs exposed by the driver. This driver introduces support for
> these IPs and integrates with the DMA Engine Framework.

The subsytem name is dmaengine!

> Signed-off-by: Radhey Shyam Pandey <radheys@xxxxxxxxxx>
> Signed-off-by: John Nichols <jnichol@xxxxxxxxxx>
> Signed-off-by: Jeffrey Mouroux <jmouroux@xxxxxxxxxx>
> Signed-off-by: Michal Simek <michal.simek@xxxxxxxxxx>
> Signed-off-by: Hyun Kwon <hyun.kwon@xxxxxxxxxx>
> Signed-off-by: Vishal Sagar <vsagar@xxxxxxxxxx>
> ---
>  drivers/dma/Kconfig                |   14 +-
>  drivers/dma/xilinx/Makefile        |    1 +
>  drivers/dma/xilinx/xilinx_frmbuf.c | 1155 ++++++++++++++++++++++++++++++++++++

Thats a very large file for review, do consider splitting stuff

> @@ -342,7 +342,7 @@ config MOXART_DMA
>  	select DMA_VIRTUAL_CHANNELS
>  	help
>  	  Enable support for the MOXA ART SoC DMA controller.
> -
> +

why this noise, this patch has some many sign-off's but didnt anyone see this
noise?

> +// SPDX-License-Identifier: GPL-2.0

Copyright needs to follow this in C99 style

> +/*
> + * DMAEngine driver for Xilinx Framebuffer IP
> + *
> + * Copyright (C) 2016 - 2017 Xilinx, Inc. All rights reserved.
> + *
> + * Authors: Radhey Shyam Pandey <radheys@xxxxxxxxxx>
> + *          John Nichols <jnichol@xxxxxxxxxx>
> + *          Jeffrey Mouroux <jmouroux@xxxxxxxxxx>
> + *
> + * Based on the Freescale DMA driver.
> + *
> + * Description:
> + * The AXI Framebuffer core is a soft Xilinx IP core that
> + * provides high-bandwidth direct memory access between memory
> + * and AXI4-Stream.
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.

why do you need this license text? With SPDX tag this is implied..

> +#include <linux/bitops.h>
> +#include <linux/dma/xilinx_frmbuf.h>
> +#include <linux/dmapool.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_dma.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/slab.h>
> +#include <linux/videodev2.h>

do you need so many headers?

> +struct xilinx_frmbuf_chan {
> +	struct xilinx_frmbuf_device *xdev;
> +	/* Descriptor operation lock */

this is duplicate comment

> +static LIST_HEAD(frmbuf_chan_list);
> +static DEFINE_MUTEX(frmbuf_chan_list_lock);

why do you need these globals?

> +static const struct xilinx_frmbuf_format_desc xilinx_frmbuf_formats[] = {
> +	{
> +		.dts_name = "xbgr8888",
> +		.id = XILINX_FRMBUF_FMT_RGBX8,
> +		.bpp = 4,
> +		.num_planes = 1,
> +		.drm_fmt = DRM_FORMAT_XBGR8888,
> +		.v4l2_fmt = 0,
> +		.fmt_bitmask = BIT(0),
> +	},
> +	{
> +		.dts_name = "unsupported",
> +		.id = XILINX_FRMBUF_FMT_YUVX8,
> +		.bpp = 4,
> +		.num_planes = 1,
> +		.drm_fmt = 0,
> +		.v4l2_fmt = 0,
> +		.fmt_bitmask = BIT(1),
> +	},

am no DT expert, but this doesn't look right to me. Care to explain what
this struct does?

> +static const struct of_device_id xilinx_frmbuf_of_ids[] = {
> +	{ .compatible = "xlnx,axi-frmbuf-wr-v2",
> +		.data = (void *)DMA_DEV_TO_MEM},
> +	{ .compatible = "xlnx,axi-frmbuf-rd-v2",
> +		.data = (void *)DMA_MEM_TO_DEV},

is the direction a hw property or configurable?

> +static inline void frmbuf_write(struct xilinx_frmbuf_chan *chan, u32 reg,
> +				u32 value)

right justfied pls, here and other places

> +{
> +	iowrite32(value, chan->xdev->regs + reg);
> +}
> +
> +static inline void frmbuf_writeq(struct xilinx_frmbuf_chan *chan, u32 reg,
> +				 u64 value)
> +{
> +	iowrite32(lower_32_bits(value), chan->xdev->regs + reg);
> +	iowrite32(upper_32_bits(value), chan->xdev->regs + reg + 4);
> +}
> +
> +static void writeq_addr(struct xilinx_frmbuf_chan *chan, u32 reg,
> +			dma_addr_t addr)
> +{
> +	frmbuf_writeq(chan, reg, (u64)addr);

why the cast?


> +static struct xilinx_frmbuf_device *frmbuf_find_dev(struct dma_chan *chan)
> +{
> +	struct xilinx_frmbuf_chan *xchan, *temp;
> +	struct xilinx_frmbuf_device *xdev;
> +	bool is_frmbuf_chan = false;
> +
> +	list_for_each_entry_safe(xchan, temp, &frmbuf_chan_list, chan_node) {
> +		if (chan == &xchan->common)
> +			is_frmbuf_chan = true;
> +	}
> +
> +	if (!is_frmbuf_chan)
> +		return ERR_PTR(-ENODEV);
> +
> +	xchan = to_xilinx_chan(chan);
> +	xdev = container_of(xchan, struct xilinx_frmbuf_device, chan);
> +
> +	return xdev;

hmm this sounds strange to me, care to explain this pls?

> +static int frmbuf_verify_format(struct dma_chan *chan, u32 fourcc, u32 type)
> +{
> +	struct xilinx_frmbuf_chan *xil_chan = to_xilinx_chan(chan);
> +	u32 i, sz = ARRAY_SIZE(xilinx_frmbuf_formats);
> +
> +	for (i = 0; i < sz; i++) {
> +		if ((type == XDMA_DRM &&
> +		     fourcc != xilinx_frmbuf_formats[i].drm_fmt) ||
> +		   (type == XDMA_V4L2 &&
> +		    fourcc != xilinx_frmbuf_formats[i].v4l2_fmt))

this is very hard to read..

> +static void xilinx_xdma_set_config(struct dma_chan *chan, u32 fourcc, u32 type)
> +{
> +	struct xilinx_frmbuf_chan *xil_chan;
> +	bool found_xchan = false;
> +	int ret;
> +
> +	mutex_lock(&frmbuf_chan_list_lock);
> +	list_for_each_entry(xil_chan, &frmbuf_chan_list, chan_node) {
> +		if (chan == &xil_chan->common) {
> +			found_xchan = true;
> +			break;
> +		}
> +	}

again this seaching and am not sure why?

> +void xilinx_xdma_drm_config(struct dma_chan *chan, u32 drm_fourcc)
> +{
> +	xilinx_xdma_set_config(chan, drm_fourcc, XDMA_DRM);
> +
> +} EXPORT_SYMBOL_GPL(xilinx_xdma_drm_config);

first EXPORT_SYMBOL_GPL should be in different line, second what is being
set? some documentation for EXPORT_SYMBOLs is required..

> +
> +void xilinx_xdma_v4l2_config(struct dma_chan *chan, u32 v4l2_fourcc)
> +{
> +	xilinx_xdma_set_config(chan, v4l2_fourcc, XDMA_V4L2);
> +
> +} EXPORT_SYMBOL_GPL(xilinx_xdma_v4l2_config);

here too..

> +
> +int xilinx_xdma_get_drm_vid_fmts(struct dma_chan *chan, u32 *fmt_cnt,
> +				 u32 **fmts)
> +{
> +	struct xilinx_frmbuf_device *xdev;
> +
> +	xdev = frmbuf_find_dev(chan);
> +
> +	if (IS_ERR(xdev))
> +		return PTR_ERR(xdev);
> +
> +	*fmt_cnt = xdev->drm_fmt_cnt;
> +	*fmts = xdev->drm_memory_fmts;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(xilinx_xdma_get_drm_vid_fmts);

and here

> +
> +int xilinx_xdma_get_v4l2_vid_fmts(struct dma_chan *chan, u32 *fmt_cnt,
> +				  u32 **fmts)
> +{
> +	struct xilinx_frmbuf_device *xdev;
> +
> +	xdev = frmbuf_find_dev(chan);
> +
> +	if (IS_ERR(xdev))
> +		return PTR_ERR(xdev);
> +
> +	*fmt_cnt = xdev->v4l2_fmt_cnt;
> +	*fmts = xdev->v4l2_memory_fmts;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(xilinx_xdma_get_v4l2_vid_fmts);

and this

> +/* -----------------------------------------------------------------------------

do you mind getting rid of these, at best they are distraction

> +static struct xilinx_frmbuf_tx_descriptor *
> +xilinx_frmbuf_alloc_tx_descriptor(struct xilinx_frmbuf_chan *chan)
> +{
> +	struct xilinx_frmbuf_tx_descriptor *desc;
> +
> +	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
> +	if (!desc)
> +		return NULL;

this can be skipped here!

> +static void xilinx_frmbuf_free_descriptors(struct xilinx_frmbuf_chan *chan)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&chan->lock, flags);
> +
> +	xilinx_frmbuf_free_desc_list(chan, &chan->pending_list);
> +	xilinx_frmbuf_free_desc_list(chan, &chan->done_list);
> +	kfree(chan->active_desc);
> +	kfree(chan->staged_desc);
> +
> +	chan->staged_desc = NULL;
> +	chan->active_desc = NULL;
> +	INIT_LIST_HEAD(&chan->pending_list);
> +	INIT_LIST_HEAD(&chan->done_list);

initializing lists in free?

> +static int xilinx_frmbuf_alloc_chan_resources(struct dma_chan *dchan)
> +{
> +	dma_cookie_init(dchan);

this can be done in your probe and not on alloc.. and consequently you can
get rid of alloc..

> +static enum dma_status xilinx_frmbuf_tx_status(struct dma_chan *dchan,
> +					       dma_cookie_t cookie,
> +					       struct dma_tx_state *txstate)
> +{
> +	return dma_cookie_status(dchan, cookie, txstate);

no residue caln?

> +static int xilinx_frmbuf_chan_probe(struct xilinx_frmbuf_device *xdev,
> +				    struct device_node *node)
> +{
> +	struct xilinx_frmbuf_chan *chan;
> +	int err;
> +	u32 dma_addr_size;
> +
> +	chan = &xdev->chan;
> +
> +	chan->dev = xdev->dev;
> +	chan->xdev = xdev;
> +	chan->idle = true;
> +
> +	err = of_property_read_u32(node, "xlnx,dma-addr-width",

why not device_property_read_u32

> +static int xilinx_frmbuf_probe(struct platform_device *pdev)
> +{
> +	struct device_node *node = pdev->dev.of_node;
> +	struct xilinx_frmbuf_device *xdev;
> +	struct resource *io;
> +	enum dma_transfer_direction dma_dir;
> +	const struct of_device_id *match;
> +	int err;
> +	u32 i, j;
> +	int hw_vid_fmt_cnt;
> +	const char *vid_fmts[ARRAY_SIZE(xilinx_frmbuf_formats)];

inverted x-mas tree helps in readablity

> +	INIT_LIST_HEAD(&xdev->common.channels);
> +	dma_cap_set(DMA_SLAVE, xdev->common.cap_mask);

why slave and why not DMA_INTERLEAVE?

> +	dma_cap_set(DMA_PRIVATE, xdev->common.cap_mask);
> +
> +	/* Initialize the channels */
> +	err = xilinx_frmbuf_chan_probe(xdev, node);
> +	if (err < 0)
> +		return err;
> +
> +	xdev->chan.direction = dma_dir;
> +
> +	if (xdev->chan.direction == DMA_DEV_TO_MEM) {
> +		xdev->common.directions = BIT(DMA_DEV_TO_MEM);
> +		dev_info(&pdev->dev, "Xilinx AXI frmbuf DMA_DEV_TO_MEM\n");
> +	} else if (xdev->chan.direction == DMA_MEM_TO_DEV) {
> +		xdev->common.directions = BIT(DMA_MEM_TO_DEV);
> +		dev_info(&pdev->dev, "Xilinx AXI frmbuf DMA_MEM_TO_DEV\n");
> +	} else {
> +		xilinx_frmbuf_chan_remove(&xdev->chan);

why not do the checks first!

> +MODULE_AUTHOR("Xilinx, Inc.");
> +MODULE_DESCRIPTION("Xilinx Framebuffer driver");
> +MODULE_LICENSE("GPL v2");

no MODULE_ALIAS, how did you test this?

> +#if IS_ENABLED(CONFIG_XILINX_FRMBUF)
> +/**
> + * xilinx_xdma_drm_config - configure video format in video aware DMA
> + * @chan: dma channel instance
> + * @drm_fourcc: DRM fourcc code describing the memory layout of video data
> + *
> + * This routine is used when utilizing "video format aware" Xilinx DMA IP
> + * (such as Video Framebuffer Read or Video Framebuffer Write).  This call
> + * must be made prior to dma_async_issue_pending() to enstablish the video
> + * data memory format within the hardware DMA.
> + */

pls move this to src..
-- 
~Vinod
--
To unsubscribe from this list: send the line "unsubscribe dmaengine" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux PCI]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux