From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 03 Jan 2024 09:43:39 +0000 Subject: [PATCH] update kernel to 5.10.198 --- kernel/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 451 insertions(+), 25 deletions(-) diff --git a/kernel/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c b/kernel/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c index dcd49b6..d3c54ba 100644 --- a/kernel/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c +++ b/kernel/drivers/media/platform/rockchip/hdmirx/rk_hdmirx.c @@ -5,11 +5,11 @@ * Author: Dingxian Wen <shawn.wen@rock-chips.com> */ -#include <dt-bindings/soc/rockchip-system-status.h> #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/debugfs.h> #include <linux/delay.h> +#include <linux/dma-fence.h> #include <linux/dma-mapping.h> #include <linux/extcon-provider.h> #include <linux/fs.h> @@ -30,11 +30,13 @@ #include <linux/rk_hdmirx_config.h> #include <linux/rockchip/rockchip_sip.h> #include <linux/seq_file.h> +#include <linux/sync_file.h> #include <linux/v4l2-dv-timings.h> #include <linux/workqueue.h> #include <media/cec.h> #include <media/cec-notifier.h> #include <media/v4l2-common.h> +#include <media/v4l2-controls_rockchip.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-dv-timings.h> @@ -52,7 +54,11 @@ static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-3)"); +MODULE_PARM_DESC(debug, "debug level (0-4)"); + +static bool low_latency; +module_param(low_latency, bool, 0644); +MODULE_PARM_DESC(low_latency, "low_latency en(0-1)"); #define RK_HDMIRX_DRVNAME "rk_hdmirx" #define EDID_NUM_BLOCKS_MAX 2 @@ -143,6 +149,12 @@ enum hdmirx_reg_attr attr; }; +struct hdmirx_fence_context { + u64 context; + u64 seqno; + spinlock_t spinlock; +}; + struct hdmirx_buffer { struct vb2_v4l2_buffer vb; struct list_head queue; @@ -177,6 +189,12 @@ u32 irq_stat; }; +struct hdmirx_fence { + struct list_head fence_list; + struct dma_fence *fence; + int fence_fd; +}; + struct rk_hdmirx_dev { struct cec_notifier *cec_notifier; struct cpufreq_policy *policy; @@ -188,6 +206,8 @@ struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler hdl; struct v4l2_ctrl *detect_tx_5v_ctrl; + struct v4l2_ctrl *audio_sampling_rate_ctrl; + struct v4l2_ctrl *audio_present_ctrl; struct v4l2_dv_timings timings; struct gpio_desc *hdmirx_det_gpio; struct work_struct work_wdt_config; @@ -201,6 +221,7 @@ struct hdmirx_audiostate audio_state; struct extcon_dev *extcon; struct hdmirx_cec *cec; + struct hdmirx_fence_context fence_ctx; struct mutex stream_lock; struct mutex work_lock; struct pm_qos_request pm_qos; @@ -212,6 +233,9 @@ struct regmap *grf; struct regmap *vo1_grf; struct rk_hdmirx_hdcp *hdcp; + struct hdmirx_fence *hdmirx_fence; + struct list_head qbuf_fence_list_head; + struct list_head done_fence_list_head; void __iomem *regs; int edid_version; int audio_present; @@ -243,11 +267,13 @@ u32 color_depth; u32 cpu_freq_khz; u32 bound_cpu; + u32 phy_cpuid; u32 fps; u32 wdt_cfg_bound_cpu; u8 edid[EDID_BLOCK_SIZE * 2]; hdmi_codec_plugged_cb plugged_cb; spinlock_t rst_lock; + spinlock_t fence_lock; }; static const unsigned int hdmirx_extcon_cable[] = { @@ -410,6 +436,64 @@ return val; } +static const char *hdmirx_fence_get_name(struct dma_fence *fence) +{ + return RK_HDMIRX_DRVNAME; +} + +static const struct dma_fence_ops hdmirx_fence_ops = { + .get_driver_name = hdmirx_fence_get_name, + .get_timeline_name = hdmirx_fence_get_name, +}; + +static void hdmirx_fence_context_init(struct hdmirx_fence_context *fence_ctx) +{ + fence_ctx->context = dma_fence_context_alloc(1); + spin_lock_init(&fence_ctx->spinlock); +} + +static struct dma_fence *hdmirx_dma_fence_alloc(struct hdmirx_fence_context *fence_ctx) +{ + struct dma_fence *fence = NULL; + + if (fence_ctx == NULL) { + pr_err("fence_context is NULL!\n"); + return ERR_PTR(-EINVAL); + } + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return ERR_PTR(-ENOMEM); + + dma_fence_init(fence, &hdmirx_fence_ops, &fence_ctx->spinlock, + fence_ctx->context, ++fence_ctx->seqno); + + return fence; +} + +static int hdmirx_dma_fence_get_fd(struct dma_fence *fence) +{ + struct sync_file *sync_file = NULL; + int fence_fd = -1; + + if (!fence) + return -EINVAL; + + fence_fd = get_unused_fd_flags(O_CLOEXEC); + if (fence_fd < 0) + return fence_fd; + + sync_file = sync_file_create(fence); + if (!sync_file) { + put_unused_fd(fence_fd); + return -ENOMEM; + } + + fd_install(fence_fd, sync_file->file); + + return fence_fd; +} + static void hdmirx_reset_dma(struct rk_hdmirx_dev *hdmirx_dev) { unsigned long lock_flags = 0; @@ -471,6 +555,7 @@ case V4L2_EVENT_CTRL: return v4l2_ctrl_subscribe_event(fh, sub); case RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST: + case RK_HDMIRX_V4L2_EVENT_AUDIOINFO: return v4l2_event_subscribe(fh, sub, 0, NULL); default: @@ -1931,6 +2016,39 @@ return 0; } +static void hdmirx_qbuf_alloc_fence(struct rk_hdmirx_dev *hdmirx_dev) +{ + struct dma_fence *fence; + int fence_fd; + struct hdmirx_fence *hdmirx_fence; + unsigned long lock_flags = 0; + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + + fence = hdmirx_dma_fence_alloc(&hdmirx_dev->fence_ctx); + if (!IS_ERR(fence)) { + fence_fd = hdmirx_dma_fence_get_fd(fence); + if (fence_fd >= 0) { + hdmirx_fence = kzalloc(sizeof(struct hdmirx_fence), GFP_KERNEL); + if (!hdmirx_fence) { + v4l2_err(v4l2_dev, "%s: failed to alloc hdmirx_fence!\n", __func__); + return; + } + hdmirx_fence->fence = fence; + hdmirx_fence->fence_fd = fence_fd; + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + list_add_tail(&hdmirx_fence->fence_list, &hdmirx_dev->qbuf_fence_list_head); + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + v4l2_dbg(3, debug, v4l2_dev, "%s: fence:%p, fence_fd:%d\n", + __func__, fence, fence_fd); + } else { + dma_fence_put(fence); + v4l2_err(v4l2_dev, "%s: failed to get fence fd!\n", __func__); + } + } else { + v4l2_err(v4l2_dev, "%s: alloc fence failed!\n", __func__); + } +} + /* * The vb2_buffer are stored in hdmirx_buffer, in order to unify * mplane buffer and none-mplane buffer. @@ -1945,6 +2063,8 @@ const struct hdmirx_output_fmt *out_fmt; unsigned long lock_flags = 0; int i; + struct rk_hdmirx_dev *hdmirx_dev; + struct v4l2_device *v4l2_dev; if (vb == NULL) { pr_err("%s: vb null pointer err!\n", __func__); @@ -1957,6 +2077,9 @@ stream = vb2_get_drv_priv(queue); pixm = &stream->pixm; out_fmt = stream->out_fmt; + + hdmirx_dev = stream->hdmirx_dev; + v4l2_dev = &hdmirx_dev->v4l2_dev; memset(hdmirx_buf->buff_addr, 0, sizeof(hdmirx_buf->buff_addr)); /* @@ -1979,9 +2102,58 @@ } } + v4l2_dbg(4, debug, v4l2_dev, "qbuf fd:%d\n", vb->planes[0].m.fd); + spin_lock_irqsave(&stream->vbq_lock, lock_flags); list_add_tail(&hdmirx_buf->queue, &stream->buf_head); spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + + if (low_latency) + hdmirx_qbuf_alloc_fence(hdmirx_dev); +} + +static void hdmirx_free_fence(struct rk_hdmirx_dev *hdmirx_dev) +{ + unsigned long lock_flags = 0; + struct hdmirx_fence *vb_fence, *done_fence; + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + LIST_HEAD(local_list); + + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + if (hdmirx_dev->hdmirx_fence) { + v4l2_dbg(2, debug, v4l2_dev, "%s: signal hdmirx_fence fd:%d\n", + __func__, hdmirx_dev->hdmirx_fence->fence_fd); + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); + kfree(hdmirx_dev->hdmirx_fence); + hdmirx_dev->hdmirx_fence = NULL; + } + + list_replace_init(&hdmirx_dev->qbuf_fence_list_head, &local_list); + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + + while (!list_empty(&local_list)) { + vb_fence = list_first_entry(&local_list, struct hdmirx_fence, fence_list); + list_del(&vb_fence->fence_list); + v4l2_dbg(2, debug, v4l2_dev, "%s: free qbuf_fence fd:%d\n", + __func__, vb_fence->fence_fd); + dma_fence_put(vb_fence->fence); + put_unused_fd(vb_fence->fence_fd); + kfree(vb_fence); + } + + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + list_replace_init(&hdmirx_dev->done_fence_list_head, &local_list); + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + while (!list_empty(&local_list)) { + done_fence = list_first_entry(&local_list, struct hdmirx_fence, fence_list); + list_del(&done_fence->fence_list); + v4l2_dbg(2, debug, v4l2_dev, "%s: free done_fence fd:%d\n", + __func__, done_fence->fence_fd); + dma_fence_put(done_fence->fence); + put_unused_fd(done_fence->fence_fd); + kfree(done_fence); + } } static void return_all_buffers(struct hdmirx_stream *stream, @@ -1989,6 +2161,7 @@ { struct hdmirx_buffer *buf; unsigned long flags; + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; spin_lock_irqsave(&stream->vbq_lock, flags); if (stream->curr_buf) @@ -2007,6 +2180,8 @@ spin_lock_irqsave(&stream->vbq_lock, flags); } spin_unlock_irqrestore(&stream->vbq_lock, flags); + + hdmirx_free_fence(hdmirx_dev); } static void hdmirx_stop_streaming(struct vb2_queue *queue) @@ -2055,6 +2230,7 @@ struct v4l2_dv_timings timings = hdmirx_dev->timings; struct v4l2_bt_timings *bt = &timings.bt; int line_flag; + int delay_line; uint32_t touch_flag; if (!hdmirx_dev->get_timing) { @@ -2069,7 +2245,7 @@ } mutex_lock(&hdmirx_dev->stream_lock); - touch_flag = (hdmirx_dev->bound_cpu << 1) | 0x1; + touch_flag = (hdmirx_dev->phy_cpuid << 1) | 0x1; sip_hdmirx_config(HDMIRX_AUTO_TOUCH_EN, 0, touch_flag, 100); stream->frame_idx = 0; stream->line_flag_int_cnt = 0; @@ -2106,12 +2282,19 @@ if (bt->height) { if (bt->interlaced == V4L2_DV_INTERLACED) - line_flag = bt->height / 4; - else line_flag = bt->height / 2; + else + line_flag = bt->height; + + if (low_latency && hdmirx_dev->fps >= 59) + delay_line = 10; + else + delay_line = line_flag * 2 / 3; + + v4l2_info(v4l2_dev, "%s: delay_line:%d\n", __func__, delay_line); hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, LINE_FLAG_NUM_MASK, - LINE_FLAG_NUM(line_flag)); + LINE_FLAG_NUM(delay_line)); } else { v4l2_err(v4l2_dev, "height err: %d\n", bt->height); } @@ -2170,6 +2353,57 @@ val = hdmirx_readl(hdmirx_dev, HDCP_INT_STATUS) & 0x40; return val ? 1 : 0; +} + +static void hdmirx_dqbuf_get_done_fence(struct rk_hdmirx_dev *hdmirx_dev) +{ + unsigned long lock_flags = 0; + struct hdmirx_fence *done_fence; + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + if (!list_empty(&hdmirx_dev->done_fence_list_head)) { + done_fence = list_first_entry(&hdmirx_dev->done_fence_list_head, + struct hdmirx_fence, fence_list); + list_del(&done_fence->fence_list); + } else { + done_fence = NULL; + } + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + + if (done_fence) { + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + if (hdmirx_dev->hdmirx_fence) { + v4l2_err(v4l2_dev, "%s: last fence not signal, signal now!\n", __func__); + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); + v4l2_dbg(2, debug, v4l2_dev, "%s: signal fence:%p, old_fd:%d\n", + __func__, + hdmirx_dev->hdmirx_fence->fence, + hdmirx_dev->hdmirx_fence->fence_fd); + kfree(hdmirx_dev->hdmirx_fence); + hdmirx_dev->hdmirx_fence = NULL; + } + hdmirx_dev->hdmirx_fence = done_fence; + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + v4l2_dbg(3, debug, v4l2_dev, "%s: fence:%p, fence_fd:%d\n", + __func__, done_fence->fence, done_fence->fence_fd); + } +} + +static int hdmirx_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + int ret; + struct hdmirx_stream *stream = video_drvdata(file); + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; + + if (!hdmirx_dev->get_timing) + return -EINVAL; + + ret = vb2_ioctl_dqbuf(file, priv, p); + hdmirx_dqbuf_get_done_fence(hdmirx_dev); + + return ret; } static long hdmirx_ioctl_default(struct file *file, void *fh, @@ -2290,7 +2524,7 @@ .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_dqbuf = hdmirx_dqbuf, .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, @@ -2353,12 +2587,23 @@ return 0; } +static void process_audio_change(struct rk_hdmirx_dev *hdmirx_dev) +{ + struct hdmirx_stream *stream = &hdmirx_dev->stream; + const struct v4l2_event evt_audio_info = { + .type = RK_HDMIRX_V4L2_EVENT_AUDIOINFO, + }; + v4l2_event_queue(&stream->vdev, &evt_audio_info); +} + static void process_signal_change(struct rk_hdmirx_dev *hdmirx_dev) { + unsigned long lock_flags = 0; struct hdmirx_stream *stream = &hdmirx_dev->stream; const struct v4l2_event evt_signal_lost = { .type = RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST, }; + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; hdmirx_dev->get_timing = false; sip_hdmirx_config(HDMIRX_INFO_NOTIFY, 0, DMA_CONFIG6, 0); @@ -2376,6 +2621,18 @@ v4l2_event_queue(&stream->vdev, &evt_signal_lost); if (hdmirx_dev->hdcp && hdmirx_dev->hdcp->hdcp_stop) hdmirx_dev->hdcp->hdcp_stop(hdmirx_dev->hdcp); + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + if (hdmirx_dev->hdmirx_fence) { + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); + v4l2_dbg(2, debug, v4l2_dev, "%s: signal fence:%p, old_fd:%d\n", + __func__, + hdmirx_dev->hdmirx_fence->fence, + hdmirx_dev->hdmirx_fence->fence_fd); + kfree(hdmirx_dev->hdmirx_fence); + hdmirx_dev->hdmirx_fence = NULL; + } + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); schedule_delayed_work_on(hdmirx_dev->bound_cpu, &hdmirx_dev->delayed_work_res_change, msecs_to_jiffies(1000)); @@ -2608,6 +2865,8 @@ { const struct hdmirx_output_fmt *fmt = stream->out_fmt; u32 i; + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; /* Dequeue a filled buffer */ for (i = 0; i < fmt->mplanes; i++) { @@ -2617,10 +2876,12 @@ vb_done->vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); + v4l2_dbg(4, debug, v4l2_dev, "vb_done fd:%d", vb_done->vb2_buf.planes[0].m.fd); } static void dma_idle_int_handler(struct rk_hdmirx_dev *hdmirx_dev, bool *handled) { + unsigned long lock_flags = 0; struct hdmirx_stream *stream = &hdmirx_dev->stream; struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; struct v4l2_dv_timings timings = hdmirx_dev->timings; @@ -2630,6 +2891,22 @@ if (!(stream->irq_stat) && !(stream->irq_stat & LINE_FLAG_INT_EN)) v4l2_dbg(1, debug, v4l2_dev, "%s: last time have no line_flag_irq\n", __func__); + + if (low_latency) { + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + if (hdmirx_dev->hdmirx_fence) { + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); + v4l2_dbg(3, debug, v4l2_dev, "%s: signal fence:%p, old_fd:%d\n", + __func__, + hdmirx_dev->hdmirx_fence->fence, + hdmirx_dev->hdmirx_fence->fence_fd); + kfree(hdmirx_dev->hdmirx_fence); + hdmirx_dev->hdmirx_fence = NULL; + } + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + goto DMA_IDLE_OUT; + } if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) goto DMA_IDLE_OUT; @@ -2643,6 +2920,9 @@ if (vb_done) { vb_done->vb2_buf.timestamp = ktime_get_ns(); vb_done->sequence = stream->frame_idx; + /* config userbits 0 or 0xffffffff as invalid fence_fd*/ + memset(vb_done->timecode.userbits, 0xff, + sizeof(vb_done->timecode.userbits)); hdmirx_vb_done(stream, vb_done); stream->frame_idx++; if (stream->frame_idx == 30) @@ -2664,13 +2944,50 @@ *handled = true; } +static void hdmirx_add_fence_to_vb_done(struct hdmirx_stream *stream, + struct vb2_v4l2_buffer *vb_done) +{ + unsigned long lock_flags = 0; + struct hdmirx_fence *vb_fence; + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; + + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + if (!list_empty(&hdmirx_dev->qbuf_fence_list_head)) { + vb_fence = list_first_entry(&hdmirx_dev->qbuf_fence_list_head, + struct hdmirx_fence, fence_list); + list_del(&vb_fence->fence_list); + } else { + vb_fence = NULL; + } + + if (vb_fence) + list_add_tail(&vb_fence->fence_list, &hdmirx_dev->done_fence_list_head); + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + + if (vb_fence) { + /* pass the fence_fd to userspace through timecode.userbits */ + if (put_user(vb_fence->fence_fd, vb_done->timecode.userbits)) + v4l2_err(v4l2_dev, "%s: failed to trans fence fd!\n", __func__); + + v4l2_dbg(3, debug, v4l2_dev, "%s: fence:%p, fence_fd:%d\n", + __func__, vb_fence->fence, vb_fence->fence_fd); + } else { + /* config userbits 0 or 0xffffffff as invalid fence_fd*/ + memset(vb_done->timecode.userbits, 0xff, sizeof(vb_done->timecode.userbits)); + v4l2_err(v4l2_dev, "%s: failed to get fence fd!\n", __func__); + } +} + static void line_flag_int_handler(struct rk_hdmirx_dev *hdmirx_dev, bool *handled) { + unsigned long lock_flags = 0; struct hdmirx_stream *stream = &hdmirx_dev->stream; struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; struct v4l2_dv_timings timings = hdmirx_dev->timings; struct v4l2_bt_timings *bt = &timings.bt; u32 dma_cfg6; + struct vb2_v4l2_buffer *vb_done = NULL; stream->line_flag_int_cnt++; if (!(stream->irq_stat) && !(stream->irq_stat & HDMIRX_DMA_IDLE_INT)) @@ -2687,6 +3004,19 @@ if ((bt->interlaced != V4L2_DV_INTERLACED) || (stream->line_flag_int_cnt % 2 == 0)) { + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); + if (hdmirx_dev->hdmirx_fence) { + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); + v4l2_dbg(2, debug, v4l2_dev, "%s: signal last fence:%p, old_fd:%d\n", + __func__, + hdmirx_dev->hdmirx_fence->fence, + hdmirx_dev->hdmirx_fence->fence_fd); + kfree(hdmirx_dev->hdmirx_fence); + hdmirx_dev->hdmirx_fence = NULL; + } + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); + if (!stream->next_buf) { spin_lock(&stream->vbq_lock); if (!list_empty(&stream->buf_head)) { @@ -2698,15 +3028,44 @@ } spin_unlock(&stream->vbq_lock); - if (stream->next_buf) { - hdmirx_writel(hdmirx_dev, DMA_CONFIG2, - stream->next_buf->buff_addr[HDMIRX_PLANE_Y]); - hdmirx_writel(hdmirx_dev, DMA_CONFIG3, - stream->next_buf->buff_addr[HDMIRX_PLANE_CBCR]); - } else { - v4l2_dbg(3, debug, v4l2_dev, - "%s: No buffer is available\n", __func__); + } + + if (stream->next_buf) { + hdmirx_writel(hdmirx_dev, DMA_CONFIG2, + stream->next_buf->buff_addr[HDMIRX_PLANE_Y]); + hdmirx_writel(hdmirx_dev, DMA_CONFIG3, + stream->next_buf->buff_addr[HDMIRX_PLANE_CBCR]); + + if (low_latency) { + if (stream->curr_buf) + vb_done = &stream->curr_buf->vb; + + if (vb_done) { + hdmirx_add_fence_to_vb_done(stream, vb_done); + vb_done->vb2_buf.timestamp = ktime_get_ns(); + vb_done->sequence = stream->frame_idx; + hdmirx_vb_done(stream, vb_done); + stream->frame_idx++; + if (stream->frame_idx == 30) + v4l2_info(v4l2_dev, "rcv frames\n"); + } + + stream->curr_buf = stream->next_buf; + stream->next_buf = NULL; } + } else { + v4l2_dbg(3, debug, v4l2_dev, + "%s: next_buf NULL, drop the frame!\n", __func__); + } + + if (stream->curr_buf) { + v4l2_dbg(4, debug, v4l2_dev, "%s: curr_fd:%d\n", + __func__, stream->curr_buf->vb.vb2_buf.planes[0].m.fd); + } + + if (stream->next_buf) { + v4l2_dbg(4, debug, v4l2_dev, "%s: next_fd:%d\n", + __func__, stream->next_buf->vb.vb2_buf.planes[0].m.fd); } } else { v4l2_dbg(3, debug, v4l2_dev, "%s: interlace:%d, line_flag_int_cnt:%d\n", @@ -3248,6 +3607,7 @@ if (!hdmirx_dev->audio_present) { dev_info(hdmirx_dev->dev, "audio on"); hdmirx_audio_handle_plugged_change(hdmirx_dev, 1); + process_audio_change(hdmirx_dev); hdmirx_dev->audio_present = true; } if (cur_state - init_state > 16 && cur_state - pre_state > 0) @@ -3258,6 +3618,7 @@ if (hdmirx_dev->audio_present) { dev_info(hdmirx_dev->dev, "audio off"); hdmirx_audio_handle_plugged_change(hdmirx_dev, 0); + process_audio_change(hdmirx_dev); hdmirx_dev->audio_present = false; } } @@ -4175,6 +4536,50 @@ dev_err(hdmirx_dev->dev, "%s freq qos nod add\n", __func__); } +static int hdmirx_get_custom_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rk_hdmirx_dev *hdmirx_dev = container_of(ctrl->handler, struct rk_hdmirx_dev, hdl); + int ret = 0; + + if (ctrl->id == RK_V4L2_CID_AUDIO_SAMPLING_RATE) { + *ctrl->p_new.p_s32 = hdmirx_dev->audio_state.fs_audio; + } else if (ctrl->id == RK_V4L2_CID_AUDIO_PRESENT) { + *ctrl->p_new.p_s32 = tx_5v_power_present(hdmirx_dev) ? + hdmirx_dev->audio_present : 0; + } else { + ret = -EINVAL; + } + return ret; +} + +static const struct v4l2_ctrl_ops hdmirx_custom_ctrl_ops = { + .g_volatile_ctrl = hdmirx_get_custom_ctrl, +}; + +static const struct v4l2_ctrl_config hdmirx_ctrl_audio_sampling_rate = { + .ops = &hdmirx_custom_ctrl_ops, + .id = RK_V4L2_CID_AUDIO_SAMPLING_RATE, + .name = "Audio sampling rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 768000, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, +}; + +static const struct v4l2_ctrl_config hdmirx_ctrl_audio_present = { + .ops = &hdmirx_custom_ctrl_ops, + .id = RK_V4L2_CID_AUDIO_PRESENT, + .name = "Audio present", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, +}; + static int hdmirx_probe(struct platform_device *pdev) { const struct v4l2_dv_timings timings_def = HDMIRX_DEFAULT_TIMING; @@ -4208,23 +4613,35 @@ return PTR_ERR(hdmirx_dev->regs); } - if (sip_cpu_logical_map_mpidr(0) == 0) - cpu_aff = sip_cpu_logical_map_mpidr(4); // big cpu0 - else - cpu_aff = sip_cpu_logical_map_mpidr(1); // big cpu1 + /* + * Bind HDMIRX's FIQ and driver interrupt processing to big cpu1 + * in order to quickly respond to FIQ and prevent them from affecting + * each other. + */ + if (sip_cpu_logical_map_mpidr(0) == 0) { + cpu_aff = sip_cpu_logical_map_mpidr(5); + hdmirx_dev->bound_cpu = 5; + } else { + cpu_aff = sip_cpu_logical_map_mpidr(1); + hdmirx_dev->bound_cpu = 1; + } sip_fiq_control(RK_SIP_FIQ_CTRL_SET_AFF, RK_IRQ_HDMIRX_HDMI, cpu_aff); - hdmirx_dev->bound_cpu = (cpu_aff >> 8) & 0xf; + hdmirx_dev->phy_cpuid = (cpu_aff >> 8) & 0xf; hdmirx_dev->wdt_cfg_bound_cpu = hdmirx_dev->bound_cpu + 1; - dev_info(dev, "%s: cpu_aff:%#x, Bound_cpu:%d, wdt_cfg_bound_cpu:%d\n", + dev_info(dev, "%s: cpu_aff:%#x, Bound_cpu:%d, wdt_cfg_bound_cpu:%d, phy_cpuid:%d\n", __func__, cpu_aff, hdmirx_dev->bound_cpu, - hdmirx_dev->wdt_cfg_bound_cpu); + hdmirx_dev->wdt_cfg_bound_cpu, + hdmirx_dev->phy_cpuid); cpu_latency_qos_add_request(&hdmirx_dev->pm_qos, PM_QOS_DEFAULT_VALUE); mutex_init(&hdmirx_dev->stream_lock); mutex_init(&hdmirx_dev->work_lock); spin_lock_init(&hdmirx_dev->rst_lock); + spin_lock_init(&hdmirx_dev->fence_lock); + INIT_LIST_HEAD(&hdmirx_dev->qbuf_fence_list_head); + INIT_LIST_HEAD(&hdmirx_dev->done_fence_list_head); INIT_WORK(&hdmirx_dev->work_wdt_config, hdmirx_work_wdt_config); INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_hotplug, @@ -4288,10 +4705,19 @@ strscpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name)); hdl = &hdmirx_dev->hdl; - v4l2_ctrl_handler_init(hdl, 1); + v4l2_ctrl_handler_init(hdl, 3); hdmirx_dev->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); + /* custom controls */ + hdmirx_dev->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(hdl, + &hdmirx_ctrl_audio_sampling_rate, NULL); + if (hdmirx_dev->audio_sampling_rate_ctrl) + hdmirx_dev->audio_sampling_rate_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + hdmirx_dev->audio_present_ctrl = v4l2_ctrl_new_custom(hdl, + &hdmirx_ctrl_audio_present, NULL); + if (hdmirx_dev->audio_present_ctrl) + hdmirx_dev->audio_present_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; if (hdl->error) { dev_err(dev, "v4l2 ctrl handler init failed!\n"); ret = hdl->error; @@ -4399,7 +4825,8 @@ hdmirx_register_hdcp(dev, hdmirx_dev, hdmirx_dev->hdcp_enable); hdmirx_register_debugfs(hdmirx_dev->dev, hdmirx_dev); - + hdmirx_fence_context_init(&hdmirx_dev->fence_ctx); + hdmirx_dev->hdmirx_fence = NULL; hdmirx_dev->initialized = true; dev_info(dev, "%s driver probe ok!\n", dev_name(dev)); @@ -4430,7 +4857,6 @@ struct rk_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); debugfs_remove_recursive(hdmirx_dev->debugfs_dir); - cpu_latency_qos_remove_request(&hdmirx_dev->pm_qos); cancel_delayed_work(&hdmirx_dev->delayed_work_hotplug); cancel_delayed_work(&hdmirx_dev->delayed_work_res_change); -- Gitblit v1.6.2