/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) STMicroelectronics SA 2014 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. */ #include <linux/clk.h> #include <linux/ktime.h> #include <linux/platform_device.h> #include <linux/spinlock.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-mem2mem.h> #include <media/videobuf2-dma-contig.h> #define BDISP_NAME "bdisp" /* * Max nb of nodes in node-list: * - 2 nodes to handle wide 4K pictures * - 2 nodes to handle two planes (Y & CbCr) */ #define MAX_OUTPUT_PLANES 2 #define MAX_VERTICAL_STRIDES 2 #define MAX_NB_NODE (MAX_OUTPUT_PLANES * MAX_VERTICAL_STRIDES) /* struct bdisp_ctrls - bdisp control set * @hflip: horizontal flip * @vflip: vertical flip */ struct bdisp_ctrls { struct v4l2_ctrl *hflip; struct v4l2_ctrl *vflip; }; /** * struct bdisp_fmt - driver's internal color format data * @pixelformat:fourcc code for this format * @nb_planes: number of planes (ex: [0]=RGB/Y - [1]=Cb/Cr, ...) * @bpp: bits per pixel (general) * @bpp_plane0: byte per pixel for the 1st plane * @w_align: width alignment in pixel (multiple of) * @h_align: height alignment in pixel (multiple of) */ struct bdisp_fmt { u32 pixelformat; u8 nb_planes; u8 bpp; u8 bpp_plane0; u8 w_align; u8 h_align; }; /** * struct bdisp_frame - frame properties * * @width: frame width (including padding) * @height: frame height (including padding) * @fmt: pointer to frame format descriptor * @field: frame / field type * @bytesperline: stride of the 1st plane * @sizeimage: image size in bytes * @colorspace: colorspace * @crop: crop area * @paddr: image physical addresses per plane ([0]=RGB/Y - [1]=Cb/Cr, ...) */ struct bdisp_frame { u32 width; u32 height; const struct bdisp_fmt *fmt; enum v4l2_field field; u32 bytesperline; u32 sizeimage; enum v4l2_colorspace colorspace; struct v4l2_rect crop; dma_addr_t paddr[4]; }; /** * struct bdisp_request - bdisp request * * @src: source frame properties * @dst: destination frame properties * @hflip: horizontal flip * @vflip: vertical flip * @nb_req: number of run request */ struct bdisp_request { struct bdisp_frame src; struct bdisp_frame dst; unsigned int hflip:1; unsigned int vflip:1; int nb_req; }; /** * struct bdisp_ctx - device context data * * @src: source frame properties * @dst: destination frame properties * @state: flags to keep track of user configuration * @hflip: horizontal flip * @vflip: vertical flip * @bdisp_dev: the device this context applies to * @node: node array * @node_paddr: node physical address array * @fh: v4l2 file handle * @ctrl_handler: v4l2 controls handler * @bdisp_ctrls: bdisp control set * @ctrls_rdy: true if the control handler is initialized */ struct bdisp_ctx { struct bdisp_frame src; struct bdisp_frame dst; u32 state; unsigned int hflip:1; unsigned int vflip:1; struct bdisp_dev *bdisp_dev; struct bdisp_node *node[MAX_NB_NODE]; dma_addr_t node_paddr[MAX_NB_NODE]; struct v4l2_fh fh; struct v4l2_ctrl_handler ctrl_handler; struct bdisp_ctrls bdisp_ctrls; bool ctrls_rdy; }; /** * struct bdisp_m2m_device - v4l2 memory-to-memory device data * * @vdev: video device node for v4l2 m2m mode * @m2m_dev: v4l2 m2m device data * @ctx: hardware context data * @refcnt: reference counter */ struct bdisp_m2m_device { struct video_device *vdev; struct v4l2_m2m_dev *m2m_dev; struct bdisp_ctx *ctx; int refcnt; }; /** * struct bdisp_dbg - debug info * * @debugfs_entry: debugfs * @copy_node: array of last used nodes * @copy_request: last bdisp request * @hw_start: start time of last HW request * @last_duration: last HW processing duration in microsecs * @min_duration: min HW processing duration in microsecs * @max_duration: max HW processing duration in microsecs * @tot_duration: total HW processing duration in microsecs */ struct bdisp_dbg { struct dentry *debugfs_entry; struct bdisp_node *copy_node[MAX_NB_NODE]; struct bdisp_request copy_request; ktime_t hw_start; s64 last_duration; s64 min_duration; s64 max_duration; s64 tot_duration; }; /** * struct bdisp_dev - abstraction for bdisp entity * * @v4l2_dev: v4l2 device * @vdev: video device * @pdev: platform device * @dev: device * @lock: mutex protecting this data structure * @slock: spinlock protecting this data structure * @id: device index * @m2m: memory-to-memory V4L2 device information * @state: flags used to synchronize m2m and capture mode operation * @clock: IP clock * @regs: registers * @irq_queue: interrupt handler waitqueue * @work_queue: workqueue to handle timeouts * @timeout_work: IRQ timeout structure * @dbg: debug info */ struct bdisp_dev { struct v4l2_device v4l2_dev; struct video_device vdev; struct platform_device *pdev; struct device *dev; spinlock_t slock; struct mutex lock; u16 id; struct bdisp_m2m_device m2m; unsigned long state; struct clk *clock; void __iomem *regs; wait_queue_head_t irq_queue; struct workqueue_struct *work_queue; struct delayed_work timeout_work; struct bdisp_dbg dbg; }; void bdisp_hw_free_nodes(struct bdisp_ctx *ctx); int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx); void bdisp_hw_free_filters(struct device *dev); int bdisp_hw_alloc_filters(struct device *dev); int bdisp_hw_reset(struct bdisp_dev *bdisp); int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp); int bdisp_hw_update(struct bdisp_ctx *ctx); void bdisp_debugfs_remove(struct bdisp_dev *bdisp); void bdisp_debugfs_create(struct bdisp_dev *bdisp); void bdisp_dbg_perf_begin(struct bdisp_dev *bdisp); void bdisp_dbg_perf_end(struct bdisp_dev *bdisp)