From f618d3b9e121d8036139419b139f7011903c77dc Mon Sep 17 00:00:00 2001 From: Jeffrey Mouroux Date: Wed, 6 Sep 2017 16:32:59 -0700 Subject: [PATCH] dma: xilinx: Add private API to permit retrieval of supported mem formats The video Framebuffer DMA IP requires clients to send a fourcc code to indicate the memory format layout. The IP can be configured to support a variety of memory formats ranging from YUYV, RGB and in either 8 bit or 10 bit formats. There has been no method for clients to obtain this list of supported formats. This patch adds private APIs that can be called from clients to retrieve this list so that user space applications can choose from any of the available memory formats. Depends on patch 13fd162 (dma: xilinx: Bug fix to ensure only video formats enabled in IP are in driver) Signed-off-by: Jeffrey Mouroux Reviewed-by: Hyun Kwon Signed-off-by: Michal Simek --- drivers/dma/xilinx/xilinx_frmbuf.c | 124 ++++++++++++++++++++++++----- include/linux/dma/xilinx_frmbuf.h | 36 +++++++++ 2 files changed, 142 insertions(+), 18 deletions(-) diff --git a/drivers/dma/xilinx/xilinx_frmbuf.c b/drivers/dma/xilinx/xilinx_frmbuf.c index eb32e96948a8..54ab68e34eee 100644 --- a/drivers/dma/xilinx/xilinx_frmbuf.c +++ b/drivers/dma/xilinx/xilinx_frmbuf.c @@ -148,24 +148,6 @@ struct xilinx_frmbuf_chan { const struct xilinx_frmbuf_format_desc *vid_fmt; }; -/** - * struct xilinx_frmbuf_device - dma device structure - * @regs: I/O mapped base address - * @dev: Device Structure - * @common: DMA device structure - * @chan: Driver specific dma channel - * @rst_gpio: GPIO reset - * @enabled_vid_fmts: Bitmask of video formats enabled in hardware - */ -struct xilinx_frmbuf_device { - void __iomem *regs; - struct device *dev; - struct dma_device common; - struct xilinx_frmbuf_chan chan; - struct gpio_desc *rst_gpio; - u32 enabled_vid_fmts; -}; - /** * struct xilinx_frmbuf_format_desc - lookup table to match fourcc to format * @dts_name: Device tree name for this entry. @@ -265,6 +247,32 @@ static const struct xilinx_frmbuf_format_desc xilinx_frmbuf_formats[] = { }, }; +/** + * struct xilinx_frmbuf_device - dma device structure + * @regs: I/O mapped base address + * @dev: Device Structure + * @common: DMA device structure + * @chan: Driver specific dma channel + * @rst_gpio: GPIO reset + * @enabled_vid_fmts: Bitmask of video formats enabled in hardware + * @drm_memory_fmts: Array of supported DRM fourcc codes + * @drm_fmt_cnt: Count of supported DRM fourcc codes + * @v4l2_memory_fmts: Array of supported V4L2 fourcc codes + * @v4l2_fmt_cnt: Count of supported V4L2 fourcc codes + */ +struct xilinx_frmbuf_device { + void __iomem *regs; + struct device *dev; + struct dma_device common; + struct xilinx_frmbuf_chan chan; + struct gpio_desc *rst_gpio; + u32 enabled_vid_fmts; + u32 drm_memory_fmts[ARRAY_SIZE(xilinx_frmbuf_formats)]; + u32 drm_fmt_cnt; + u32 v4l2_memory_fmts[ARRAY_SIZE(xilinx_frmbuf_formats)]; + u32 v4l2_fmt_cnt; +}; + static const struct of_device_id xilinx_frmbuf_of_ids[] = { { .compatible = "xlnx,axi-frmbuf-wr-v2", .data = (void *)DMA_DEV_TO_MEM}, @@ -321,6 +329,49 @@ static inline void frmbuf_set(struct xilinx_frmbuf_chan *chan, u32 reg, frmbuf_write(chan, reg, frmbuf_read(chan, reg) | set); } +static void frmbuf_init_format_array(struct xilinx_frmbuf_device *xdev) +{ + u32 i, cnt; + + for (i = 0; i < ARRAY_SIZE(xilinx_frmbuf_formats); i++) { + if (!(xdev->enabled_vid_fmts & + xilinx_frmbuf_formats[i].fmt_bitmask)) + continue; + + if (xilinx_frmbuf_formats[i].drm_fmt) { + cnt = xdev->drm_fmt_cnt++; + xdev->drm_memory_fmts[cnt] = + xilinx_frmbuf_formats[i].drm_fmt; + } + + if (xilinx_frmbuf_formats[i].v4l2_fmt) { + cnt = xdev->v4l2_fmt_cnt++; + xdev->v4l2_memory_fmts[cnt] = + xilinx_frmbuf_formats[i].v4l2_fmt; + } + } +} + +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; +} + static int frmbuf_verify_format(struct dma_chan *chan, u32 fourcc, u32 type) { struct xilinx_frmbuf_chan *xil_chan = to_xilinx_chan(chan); @@ -385,6 +436,40 @@ void xilinx_xdma_v4l2_config(struct dma_chan *chan, u32 v4l2_fourcc) } EXPORT_SYMBOL_GPL(xilinx_xdma_v4l2_config); +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); + +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); + /** * of_dma_xilinx_xlate - Translation function * @dma_spec: Pointer to DMA specifier as found in the device tree @@ -1003,6 +1088,9 @@ static int xilinx_frmbuf_probe(struct platform_device *pdev) } } + /* Determine supported vid framework formats */ + frmbuf_init_format_array(xdev); + xdev->common.device_alloc_chan_resources = xilinx_frmbuf_alloc_chan_resources; xdev->common.device_free_chan_resources = diff --git a/include/linux/dma/xilinx_frmbuf.h b/include/linux/dma/xilinx_frmbuf.h index 6356d05eabeb..0c7160534e88 100644 --- a/include/linux/dma/xilinx_frmbuf.h +++ b/include/linux/dma/xilinx_frmbuf.h @@ -48,6 +48,30 @@ void xilinx_xdma_drm_config(struct dma_chan *chan, u32 drm_fourcc); * data memory format within the hardware DMA. */ void xilinx_xdma_v4l2_config(struct dma_chan *chan, u32 v4l2_fourcc); + +/** + * xilinx_xdma_get_drm_vid_fmts - obtain list of supported DRM mem formats + * @chan: dma channel instance + * @fmt_cnt: Output param - total count of supported DRM fourcc codes + * @fmts: Output param - pointer to array of DRM fourcc codes (not a copy) + * + * Return: a reference to an array of DRM fourcc codes supported by this + * instance of the Video Framebuffer Driver + */ +int xilinx_xdma_get_drm_vid_fmts(struct dma_chan *chan, u32 *fmt_cnt, + u32 **fmts); + +/** + * xilinx_xdma_get_v4l2_vid_fmts - obtain list of supported V4L2 mem formats + * @chan: dma channel instance + * @fmt_cnt: Output param - total count of supported V4L2 fourcc codes + * @fmts: Output param - pointer to array of V4L2 fourcc codes (not a copy) + * + * Return: a reference to an array of V4L2 fourcc codes supported by this + * instance of the Video Framebuffer Driver + */ +int xilinx_xdma_get_v4l2_vid_fmts(struct dma_chan *chan, u32 *fmt_cnt, + u32 **fmts); #else static inline void xilinx_xdma_drm_config(struct dma_chan *chan, u32 drm_fourcc) { } @@ -55,6 +79,18 @@ static inline void xilinx_xdma_drm_config(struct dma_chan *chan, u32 drm_fourcc) static inline void xilinx_xdma_v4l2_config(struct dma_chan *chan, u32 v4l2_fourcc) { } + +int xilinx_xdma_get_drm_vid_fmts(struct dma_chan *chan, u32 *fmt_cnt, + u32 **fmts); +{ + return -ENODEV; +} + +int xilinx_xdma_get_v4l2_vid_fmts(struct dma_chan *chan, u32 *fmt_cnt, + u32 **fmts); +{ + return -ENODEV; +} #endif #endif /*__XILINX_FRMBUF_DMA_H*/ -- 2.39.2