| .. | .. |
|---|
| 5 | 5 | * Author: Dingxian Wen <shawn.wen@rock-chips.com> |
|---|
| 6 | 6 | */ |
|---|
| 7 | 7 | |
|---|
| 8 | | -#include <dt-bindings/soc/rockchip-system-status.h> |
|---|
| 9 | 8 | #include <linux/clk.h> |
|---|
| 10 | 9 | #include <linux/cpufreq.h> |
|---|
| 11 | 10 | #include <linux/debugfs.h> |
|---|
| 12 | 11 | #include <linux/delay.h> |
|---|
| 12 | +#include <linux/dma-fence.h> |
|---|
| 13 | 13 | #include <linux/dma-mapping.h> |
|---|
| 14 | 14 | #include <linux/extcon-provider.h> |
|---|
| 15 | 15 | #include <linux/fs.h> |
|---|
| .. | .. |
|---|
| 30 | 30 | #include <linux/rk_hdmirx_config.h> |
|---|
| 31 | 31 | #include <linux/rockchip/rockchip_sip.h> |
|---|
| 32 | 32 | #include <linux/seq_file.h> |
|---|
| 33 | +#include <linux/sync_file.h> |
|---|
| 33 | 34 | #include <linux/v4l2-dv-timings.h> |
|---|
| 34 | 35 | #include <linux/workqueue.h> |
|---|
| 35 | 36 | #include <media/cec.h> |
|---|
| 36 | 37 | #include <media/cec-notifier.h> |
|---|
| 37 | 38 | #include <media/v4l2-common.h> |
|---|
| 39 | +#include <media/v4l2-controls_rockchip.h> |
|---|
| 38 | 40 | #include <media/v4l2-ctrls.h> |
|---|
| 39 | 41 | #include <media/v4l2-device.h> |
|---|
| 40 | 42 | #include <media/v4l2-dv-timings.h> |
|---|
| .. | .. |
|---|
| 45 | 47 | #include <media/videobuf2-v4l2.h> |
|---|
| 46 | 48 | #include <soc/rockchip/rockchip-system-status.h> |
|---|
| 47 | 49 | #include <sound/hdmi-codec.h> |
|---|
| 50 | +#include <linux/rk_hdmirx_class.h> |
|---|
| 48 | 51 | #include "rk_hdmirx.h" |
|---|
| 49 | 52 | #include "rk_hdmirx_cec.h" |
|---|
| 50 | 53 | #include "rk_hdmirx_hdcp.h" |
|---|
| 51 | 54 | |
|---|
| 52 | | -static struct class *hdmirx_class; |
|---|
| 53 | 55 | static int debug; |
|---|
| 54 | 56 | module_param(debug, int, 0644); |
|---|
| 55 | | -MODULE_PARM_DESC(debug, "debug level (0-3)"); |
|---|
| 57 | +MODULE_PARM_DESC(debug, "debug level (0-4)"); |
|---|
| 58 | + |
|---|
| 59 | +static bool low_latency; |
|---|
| 60 | +module_param(low_latency, bool, 0644); |
|---|
| 61 | +MODULE_PARM_DESC(low_latency, "low_latency en(0-1)"); |
|---|
| 56 | 62 | |
|---|
| 57 | 63 | #define RK_HDMIRX_DRVNAME "rk_hdmirx" |
|---|
| 58 | 64 | #define EDID_NUM_BLOCKS_MAX 2 |
|---|
| .. | .. |
|---|
| 143 | 149 | enum hdmirx_reg_attr attr; |
|---|
| 144 | 150 | }; |
|---|
| 145 | 151 | |
|---|
| 152 | +struct hdmirx_fence_context { |
|---|
| 153 | + u64 context; |
|---|
| 154 | + u64 seqno; |
|---|
| 155 | + spinlock_t spinlock; |
|---|
| 156 | +}; |
|---|
| 157 | + |
|---|
| 146 | 158 | struct hdmirx_buffer { |
|---|
| 147 | 159 | struct vb2_v4l2_buffer vb; |
|---|
| 148 | 160 | struct list_head queue; |
|---|
| .. | .. |
|---|
| 177 | 189 | u32 irq_stat; |
|---|
| 178 | 190 | }; |
|---|
| 179 | 191 | |
|---|
| 192 | +struct hdmirx_fence { |
|---|
| 193 | + struct list_head fence_list; |
|---|
| 194 | + struct dma_fence *fence; |
|---|
| 195 | + int fence_fd; |
|---|
| 196 | +}; |
|---|
| 197 | + |
|---|
| 180 | 198 | struct rk_hdmirx_dev { |
|---|
| 181 | 199 | struct cec_notifier *cec_notifier; |
|---|
| 182 | 200 | struct cpufreq_policy *policy; |
|---|
| .. | .. |
|---|
| 188 | 206 | struct v4l2_device v4l2_dev; |
|---|
| 189 | 207 | struct v4l2_ctrl_handler hdl; |
|---|
| 190 | 208 | struct v4l2_ctrl *detect_tx_5v_ctrl; |
|---|
| 209 | + struct v4l2_ctrl *audio_sampling_rate_ctrl; |
|---|
| 210 | + struct v4l2_ctrl *audio_present_ctrl; |
|---|
| 191 | 211 | struct v4l2_dv_timings timings; |
|---|
| 192 | 212 | struct gpio_desc *hdmirx_det_gpio; |
|---|
| 193 | 213 | struct work_struct work_wdt_config; |
|---|
| .. | .. |
|---|
| 201 | 221 | struct hdmirx_audiostate audio_state; |
|---|
| 202 | 222 | struct extcon_dev *extcon; |
|---|
| 203 | 223 | struct hdmirx_cec *cec; |
|---|
| 224 | + struct hdmirx_fence_context fence_ctx; |
|---|
| 204 | 225 | struct mutex stream_lock; |
|---|
| 205 | 226 | struct mutex work_lock; |
|---|
| 206 | 227 | struct pm_qos_request pm_qos; |
|---|
| .. | .. |
|---|
| 212 | 233 | struct regmap *grf; |
|---|
| 213 | 234 | struct regmap *vo1_grf; |
|---|
| 214 | 235 | struct rk_hdmirx_hdcp *hdcp; |
|---|
| 236 | + struct hdmirx_fence *hdmirx_fence; |
|---|
| 237 | + struct list_head qbuf_fence_list_head; |
|---|
| 238 | + struct list_head done_fence_list_head; |
|---|
| 215 | 239 | void __iomem *regs; |
|---|
| 216 | 240 | int edid_version; |
|---|
| 217 | 241 | int audio_present; |
|---|
| .. | .. |
|---|
| 243 | 267 | u32 color_depth; |
|---|
| 244 | 268 | u32 cpu_freq_khz; |
|---|
| 245 | 269 | u32 bound_cpu; |
|---|
| 270 | + u32 phy_cpuid; |
|---|
| 246 | 271 | u32 fps; |
|---|
| 247 | 272 | u32 wdt_cfg_bound_cpu; |
|---|
| 248 | 273 | u8 edid[EDID_BLOCK_SIZE * 2]; |
|---|
| 249 | 274 | hdmi_codec_plugged_cb plugged_cb; |
|---|
| 250 | 275 | spinlock_t rst_lock; |
|---|
| 276 | + spinlock_t fence_lock; |
|---|
| 251 | 277 | }; |
|---|
| 252 | 278 | |
|---|
| 253 | 279 | static const unsigned int hdmirx_extcon_cable[] = { |
|---|
| .. | .. |
|---|
| 269 | 295 | static void hdmirx_cancel_cpu_limit_freq(struct rk_hdmirx_dev *hdmirx_dev); |
|---|
| 270 | 296 | static void hdmirx_plugout(struct rk_hdmirx_dev *hdmirx_dev); |
|---|
| 271 | 297 | static void process_signal_change(struct rk_hdmirx_dev *hdmirx_dev); |
|---|
| 298 | +static void hdmirx_interrupts_setup(struct rk_hdmirx_dev *hdmirx_dev, bool en); |
|---|
| 272 | 299 | |
|---|
| 273 | 300 | static u8 edid_init_data_340M[] = { |
|---|
| 274 | 301 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, |
|---|
| .. | .. |
|---|
| 409 | 436 | return val; |
|---|
| 410 | 437 | } |
|---|
| 411 | 438 | |
|---|
| 439 | +static const char *hdmirx_fence_get_name(struct dma_fence *fence) |
|---|
| 440 | +{ |
|---|
| 441 | + return RK_HDMIRX_DRVNAME; |
|---|
| 442 | +} |
|---|
| 443 | + |
|---|
| 444 | +static const struct dma_fence_ops hdmirx_fence_ops = { |
|---|
| 445 | + .get_driver_name = hdmirx_fence_get_name, |
|---|
| 446 | + .get_timeline_name = hdmirx_fence_get_name, |
|---|
| 447 | +}; |
|---|
| 448 | + |
|---|
| 449 | +static void hdmirx_fence_context_init(struct hdmirx_fence_context *fence_ctx) |
|---|
| 450 | +{ |
|---|
| 451 | + fence_ctx->context = dma_fence_context_alloc(1); |
|---|
| 452 | + spin_lock_init(&fence_ctx->spinlock); |
|---|
| 453 | +} |
|---|
| 454 | + |
|---|
| 455 | +static struct dma_fence *hdmirx_dma_fence_alloc(struct hdmirx_fence_context *fence_ctx) |
|---|
| 456 | +{ |
|---|
| 457 | + struct dma_fence *fence = NULL; |
|---|
| 458 | + |
|---|
| 459 | + if (fence_ctx == NULL) { |
|---|
| 460 | + pr_err("fence_context is NULL!\n"); |
|---|
| 461 | + return ERR_PTR(-EINVAL); |
|---|
| 462 | + } |
|---|
| 463 | + |
|---|
| 464 | + fence = kzalloc(sizeof(*fence), GFP_KERNEL); |
|---|
| 465 | + if (!fence) |
|---|
| 466 | + return ERR_PTR(-ENOMEM); |
|---|
| 467 | + |
|---|
| 468 | + dma_fence_init(fence, &hdmirx_fence_ops, &fence_ctx->spinlock, |
|---|
| 469 | + fence_ctx->context, ++fence_ctx->seqno); |
|---|
| 470 | + |
|---|
| 471 | + return fence; |
|---|
| 472 | +} |
|---|
| 473 | + |
|---|
| 474 | +static int hdmirx_dma_fence_get_fd(struct dma_fence *fence) |
|---|
| 475 | +{ |
|---|
| 476 | + struct sync_file *sync_file = NULL; |
|---|
| 477 | + int fence_fd = -1; |
|---|
| 478 | + |
|---|
| 479 | + if (!fence) |
|---|
| 480 | + return -EINVAL; |
|---|
| 481 | + |
|---|
| 482 | + fence_fd = get_unused_fd_flags(O_CLOEXEC); |
|---|
| 483 | + if (fence_fd < 0) |
|---|
| 484 | + return fence_fd; |
|---|
| 485 | + |
|---|
| 486 | + sync_file = sync_file_create(fence); |
|---|
| 487 | + if (!sync_file) { |
|---|
| 488 | + put_unused_fd(fence_fd); |
|---|
| 489 | + return -ENOMEM; |
|---|
| 490 | + } |
|---|
| 491 | + |
|---|
| 492 | + fd_install(fence_fd, sync_file->file); |
|---|
| 493 | + |
|---|
| 494 | + return fence_fd; |
|---|
| 495 | +} |
|---|
| 496 | + |
|---|
| 412 | 497 | static void hdmirx_reset_dma(struct rk_hdmirx_dev *hdmirx_dev) |
|---|
| 413 | 498 | { |
|---|
| 414 | 499 | unsigned long lock_flags = 0; |
|---|
| .. | .. |
|---|
| 470 | 555 | case V4L2_EVENT_CTRL: |
|---|
| 471 | 556 | return v4l2_ctrl_subscribe_event(fh, sub); |
|---|
| 472 | 557 | case RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST: |
|---|
| 558 | + case RK_HDMIRX_V4L2_EVENT_AUDIOINFO: |
|---|
| 473 | 559 | return v4l2_event_subscribe(fh, sub, 0, NULL); |
|---|
| 474 | 560 | |
|---|
| 475 | 561 | default: |
|---|
| .. | .. |
|---|
| 528 | 614 | struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; |
|---|
| 529 | 615 | struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 530 | 616 | u32 dma_cfg1; |
|---|
| 617 | + |
|---|
| 618 | + if (port_no_link(hdmirx_dev)) { |
|---|
| 619 | + v4l2_err(v4l2_dev, "%s port has no link!\n", __func__); |
|---|
| 620 | + return -ENOLINK; |
|---|
| 621 | + } |
|---|
| 622 | + |
|---|
| 623 | + if (signal_not_lock(hdmirx_dev)) { |
|---|
| 624 | + v4l2_err(v4l2_dev, "%s signal is not locked!\n", __func__); |
|---|
| 625 | + return -ENOLCK; |
|---|
| 626 | + } |
|---|
| 531 | 627 | |
|---|
| 532 | 628 | *timings = hdmirx_dev->timings; |
|---|
| 533 | 629 | dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1); |
|---|
| .. | .. |
|---|
| 615 | 711 | static void hdmirx_get_pix_fmt(struct rk_hdmirx_dev *hdmirx_dev) |
|---|
| 616 | 712 | { |
|---|
| 617 | 713 | u32 val; |
|---|
| 714 | + int timeout = 10; |
|---|
| 618 | 715 | struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 619 | 716 | |
|---|
| 717 | +try_loop: |
|---|
| 620 | 718 | val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); |
|---|
| 621 | 719 | hdmirx_dev->pix_fmt = val & HDMIRX_FORMAT_MASK; |
|---|
| 622 | 720 | |
|---|
| .. | .. |
|---|
| 635 | 733 | break; |
|---|
| 636 | 734 | |
|---|
| 637 | 735 | default: |
|---|
| 736 | + if (timeout-- > 0) { |
|---|
| 737 | + usleep_range(200 * 1000, 200 * 1010); |
|---|
| 738 | + v4l2_err(v4l2_dev, "%s: get format failed, read again!\n", __func__); |
|---|
| 739 | + goto try_loop; |
|---|
| 740 | + } |
|---|
| 741 | + hdmirx_dev->pix_fmt = HDMIRX_RGB888; |
|---|
| 742 | + hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; |
|---|
| 638 | 743 | v4l2_err(v4l2_dev, |
|---|
| 639 | 744 | "%s: err pix_fmt: %d, set RGB888 as default\n", |
|---|
| 640 | 745 | __func__, hdmirx_dev->pix_fmt); |
|---|
| 641 | | - hdmirx_dev->pix_fmt = HDMIRX_RGB888; |
|---|
| 642 | | - hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; |
|---|
| 643 | 746 | break; |
|---|
| 644 | 747 | } |
|---|
| 645 | 748 | |
|---|
| .. | .. |
|---|
| 880 | 983 | struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 881 | 984 | u32 last_w, last_h; |
|---|
| 882 | 985 | struct v4l2_bt_timings *bt = &timings->bt; |
|---|
| 986 | + enum hdmirx_pix_fmt last_fmt; |
|---|
| 883 | 987 | |
|---|
| 884 | 988 | last_w = 0; |
|---|
| 885 | 989 | last_h = 0; |
|---|
| 990 | + last_fmt = HDMIRX_RGB888; |
|---|
| 991 | + |
|---|
| 886 | 992 | for (i = 0; i < try_cnt; i++) { |
|---|
| 887 | 993 | ret = hdmirx_get_detected_timings(hdmirx_dev, timings, from_dma); |
|---|
| 888 | 994 | |
|---|
| .. | .. |
|---|
| 891 | 997 | last_h = bt->height; |
|---|
| 892 | 998 | } |
|---|
| 893 | 999 | |
|---|
| 894 | | - if (ret || (last_w != bt->width) || (last_h != bt->height)) |
|---|
| 1000 | + if (ret || (last_w != bt->width) || (last_h != bt->height) |
|---|
| 1001 | + || (last_fmt != hdmirx_dev->pix_fmt)) |
|---|
| 895 | 1002 | cnt = 0; |
|---|
| 896 | 1003 | else |
|---|
| 897 | 1004 | cnt++; |
|---|
| .. | .. |
|---|
| 901 | 1008 | |
|---|
| 902 | 1009 | last_w = bt->width; |
|---|
| 903 | 1010 | last_h = bt->height; |
|---|
| 1011 | + last_fmt = hdmirx_dev->pix_fmt; |
|---|
| 904 | 1012 | usleep_range(10*1000, 10*1100); |
|---|
| 905 | 1013 | } |
|---|
| 906 | 1014 | |
|---|
| .. | .. |
|---|
| 1545 | 1653 | } |
|---|
| 1546 | 1654 | |
|---|
| 1547 | 1655 | hdmirx_reset_dma(hdmirx_dev); |
|---|
| 1548 | | - usleep_range(200*1000, 200*1010); |
|---|
| 1656 | + usleep_range(500*1000, 500*1010); |
|---|
| 1549 | 1657 | hdmirx_format_change(hdmirx_dev); |
|---|
| 1550 | 1658 | |
|---|
| 1551 | 1659 | return 0; |
|---|
| .. | .. |
|---|
| 1908 | 2016 | return 0; |
|---|
| 1909 | 2017 | } |
|---|
| 1910 | 2018 | |
|---|
| 2019 | +static void hdmirx_qbuf_alloc_fence(struct rk_hdmirx_dev *hdmirx_dev) |
|---|
| 2020 | +{ |
|---|
| 2021 | + struct dma_fence *fence; |
|---|
| 2022 | + int fence_fd; |
|---|
| 2023 | + struct hdmirx_fence *hdmirx_fence; |
|---|
| 2024 | + unsigned long lock_flags = 0; |
|---|
| 2025 | + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2026 | + |
|---|
| 2027 | + fence = hdmirx_dma_fence_alloc(&hdmirx_dev->fence_ctx); |
|---|
| 2028 | + if (!IS_ERR(fence)) { |
|---|
| 2029 | + fence_fd = hdmirx_dma_fence_get_fd(fence); |
|---|
| 2030 | + if (fence_fd >= 0) { |
|---|
| 2031 | + hdmirx_fence = kzalloc(sizeof(struct hdmirx_fence), GFP_KERNEL); |
|---|
| 2032 | + if (!hdmirx_fence) { |
|---|
| 2033 | + v4l2_err(v4l2_dev, "%s: failed to alloc hdmirx_fence!\n", __func__); |
|---|
| 2034 | + return; |
|---|
| 2035 | + } |
|---|
| 2036 | + hdmirx_fence->fence = fence; |
|---|
| 2037 | + hdmirx_fence->fence_fd = fence_fd; |
|---|
| 2038 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2039 | + list_add_tail(&hdmirx_fence->fence_list, &hdmirx_dev->qbuf_fence_list_head); |
|---|
| 2040 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2041 | + v4l2_dbg(3, debug, v4l2_dev, "%s: fence:%p, fence_fd:%d\n", |
|---|
| 2042 | + __func__, fence, fence_fd); |
|---|
| 2043 | + } else { |
|---|
| 2044 | + dma_fence_put(fence); |
|---|
| 2045 | + v4l2_err(v4l2_dev, "%s: failed to get fence fd!\n", __func__); |
|---|
| 2046 | + } |
|---|
| 2047 | + } else { |
|---|
| 2048 | + v4l2_err(v4l2_dev, "%s: alloc fence failed!\n", __func__); |
|---|
| 2049 | + } |
|---|
| 2050 | +} |
|---|
| 2051 | + |
|---|
| 1911 | 2052 | /* |
|---|
| 1912 | 2053 | * The vb2_buffer are stored in hdmirx_buffer, in order to unify |
|---|
| 1913 | 2054 | * mplane buffer and none-mplane buffer. |
|---|
| .. | .. |
|---|
| 1922 | 2063 | const struct hdmirx_output_fmt *out_fmt; |
|---|
| 1923 | 2064 | unsigned long lock_flags = 0; |
|---|
| 1924 | 2065 | int i; |
|---|
| 2066 | + struct rk_hdmirx_dev *hdmirx_dev; |
|---|
| 2067 | + struct v4l2_device *v4l2_dev; |
|---|
| 1925 | 2068 | |
|---|
| 1926 | 2069 | if (vb == NULL) { |
|---|
| 1927 | 2070 | pr_err("%s: vb null pointer err!\n", __func__); |
|---|
| .. | .. |
|---|
| 1934 | 2077 | stream = vb2_get_drv_priv(queue); |
|---|
| 1935 | 2078 | pixm = &stream->pixm; |
|---|
| 1936 | 2079 | out_fmt = stream->out_fmt; |
|---|
| 2080 | + |
|---|
| 2081 | + hdmirx_dev = stream->hdmirx_dev; |
|---|
| 2082 | + v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 1937 | 2083 | |
|---|
| 1938 | 2084 | memset(hdmirx_buf->buff_addr, 0, sizeof(hdmirx_buf->buff_addr)); |
|---|
| 1939 | 2085 | /* |
|---|
| .. | .. |
|---|
| 1956 | 2102 | } |
|---|
| 1957 | 2103 | } |
|---|
| 1958 | 2104 | |
|---|
| 2105 | + v4l2_dbg(4, debug, v4l2_dev, "qbuf fd:%d\n", vb->planes[0].m.fd); |
|---|
| 2106 | + |
|---|
| 1959 | 2107 | spin_lock_irqsave(&stream->vbq_lock, lock_flags); |
|---|
| 1960 | 2108 | list_add_tail(&hdmirx_buf->queue, &stream->buf_head); |
|---|
| 1961 | 2109 | spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); |
|---|
| 2110 | + |
|---|
| 2111 | + if (low_latency) |
|---|
| 2112 | + hdmirx_qbuf_alloc_fence(hdmirx_dev); |
|---|
| 2113 | +} |
|---|
| 2114 | + |
|---|
| 2115 | +static void hdmirx_free_fence(struct rk_hdmirx_dev *hdmirx_dev) |
|---|
| 2116 | +{ |
|---|
| 2117 | + unsigned long lock_flags = 0; |
|---|
| 2118 | + struct hdmirx_fence *vb_fence, *done_fence; |
|---|
| 2119 | + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2120 | + LIST_HEAD(local_list); |
|---|
| 2121 | + |
|---|
| 2122 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2123 | + if (hdmirx_dev->hdmirx_fence) { |
|---|
| 2124 | + v4l2_dbg(2, debug, v4l2_dev, "%s: signal hdmirx_fence fd:%d\n", |
|---|
| 2125 | + __func__, hdmirx_dev->hdmirx_fence->fence_fd); |
|---|
| 2126 | + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2127 | + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2128 | + kfree(hdmirx_dev->hdmirx_fence); |
|---|
| 2129 | + hdmirx_dev->hdmirx_fence = NULL; |
|---|
| 2130 | + } |
|---|
| 2131 | + |
|---|
| 2132 | + list_replace_init(&hdmirx_dev->qbuf_fence_list_head, &local_list); |
|---|
| 2133 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2134 | + |
|---|
| 2135 | + while (!list_empty(&local_list)) { |
|---|
| 2136 | + vb_fence = list_first_entry(&local_list, struct hdmirx_fence, fence_list); |
|---|
| 2137 | + list_del(&vb_fence->fence_list); |
|---|
| 2138 | + v4l2_dbg(2, debug, v4l2_dev, "%s: free qbuf_fence fd:%d\n", |
|---|
| 2139 | + __func__, vb_fence->fence_fd); |
|---|
| 2140 | + dma_fence_put(vb_fence->fence); |
|---|
| 2141 | + put_unused_fd(vb_fence->fence_fd); |
|---|
| 2142 | + kfree(vb_fence); |
|---|
| 2143 | + } |
|---|
| 2144 | + |
|---|
| 2145 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2146 | + list_replace_init(&hdmirx_dev->done_fence_list_head, &local_list); |
|---|
| 2147 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2148 | + while (!list_empty(&local_list)) { |
|---|
| 2149 | + done_fence = list_first_entry(&local_list, struct hdmirx_fence, fence_list); |
|---|
| 2150 | + list_del(&done_fence->fence_list); |
|---|
| 2151 | + v4l2_dbg(2, debug, v4l2_dev, "%s: free done_fence fd:%d\n", |
|---|
| 2152 | + __func__, done_fence->fence_fd); |
|---|
| 2153 | + dma_fence_put(done_fence->fence); |
|---|
| 2154 | + put_unused_fd(done_fence->fence_fd); |
|---|
| 2155 | + kfree(done_fence); |
|---|
| 2156 | + } |
|---|
| 1962 | 2157 | } |
|---|
| 1963 | 2158 | |
|---|
| 1964 | 2159 | static void return_all_buffers(struct hdmirx_stream *stream, |
|---|
| .. | .. |
|---|
| 1966 | 2161 | { |
|---|
| 1967 | 2162 | struct hdmirx_buffer *buf; |
|---|
| 1968 | 2163 | unsigned long flags; |
|---|
| 2164 | + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; |
|---|
| 1969 | 2165 | |
|---|
| 1970 | 2166 | spin_lock_irqsave(&stream->vbq_lock, flags); |
|---|
| 1971 | 2167 | if (stream->curr_buf) |
|---|
| .. | .. |
|---|
| 1984 | 2180 | spin_lock_irqsave(&stream->vbq_lock, flags); |
|---|
| 1985 | 2181 | } |
|---|
| 1986 | 2182 | spin_unlock_irqrestore(&stream->vbq_lock, flags); |
|---|
| 2183 | + |
|---|
| 2184 | + hdmirx_free_fence(hdmirx_dev); |
|---|
| 1987 | 2185 | } |
|---|
| 1988 | 2186 | |
|---|
| 1989 | 2187 | static void hdmirx_stop_streaming(struct vb2_queue *queue) |
|---|
| .. | .. |
|---|
| 2032 | 2230 | struct v4l2_dv_timings timings = hdmirx_dev->timings; |
|---|
| 2033 | 2231 | struct v4l2_bt_timings *bt = &timings.bt; |
|---|
| 2034 | 2232 | int line_flag; |
|---|
| 2233 | + int delay_line; |
|---|
| 2035 | 2234 | uint32_t touch_flag; |
|---|
| 2036 | 2235 | |
|---|
| 2037 | 2236 | if (!hdmirx_dev->get_timing) { |
|---|
| .. | .. |
|---|
| 2046 | 2245 | } |
|---|
| 2047 | 2246 | |
|---|
| 2048 | 2247 | mutex_lock(&hdmirx_dev->stream_lock); |
|---|
| 2049 | | - touch_flag = (hdmirx_dev->bound_cpu << 1) | 0x1; |
|---|
| 2248 | + touch_flag = (hdmirx_dev->phy_cpuid << 1) | 0x1; |
|---|
| 2050 | 2249 | sip_hdmirx_config(HDMIRX_AUTO_TOUCH_EN, 0, touch_flag, 100); |
|---|
| 2051 | 2250 | stream->frame_idx = 0; |
|---|
| 2052 | 2251 | stream->line_flag_int_cnt = 0; |
|---|
| .. | .. |
|---|
| 2083 | 2282 | |
|---|
| 2084 | 2283 | if (bt->height) { |
|---|
| 2085 | 2284 | if (bt->interlaced == V4L2_DV_INTERLACED) |
|---|
| 2086 | | - line_flag = bt->height / 4; |
|---|
| 2087 | | - else |
|---|
| 2088 | 2285 | line_flag = bt->height / 2; |
|---|
| 2286 | + else |
|---|
| 2287 | + line_flag = bt->height; |
|---|
| 2288 | + |
|---|
| 2289 | + if (low_latency && hdmirx_dev->fps >= 59) |
|---|
| 2290 | + delay_line = 10; |
|---|
| 2291 | + else |
|---|
| 2292 | + delay_line = line_flag * 2 / 3; |
|---|
| 2293 | + |
|---|
| 2294 | + v4l2_info(v4l2_dev, "%s: delay_line:%d\n", __func__, delay_line); |
|---|
| 2089 | 2295 | hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, |
|---|
| 2090 | 2296 | LINE_FLAG_NUM_MASK, |
|---|
| 2091 | | - LINE_FLAG_NUM(line_flag)); |
|---|
| 2297 | + LINE_FLAG_NUM(delay_line)); |
|---|
| 2092 | 2298 | } else { |
|---|
| 2093 | 2299 | v4l2_err(v4l2_dev, "height err: %d\n", bt->height); |
|---|
| 2094 | 2300 | } |
|---|
| .. | .. |
|---|
| 2147 | 2353 | val = hdmirx_readl(hdmirx_dev, HDCP_INT_STATUS) & 0x40; |
|---|
| 2148 | 2354 | |
|---|
| 2149 | 2355 | return val ? 1 : 0; |
|---|
| 2356 | +} |
|---|
| 2357 | + |
|---|
| 2358 | +static void hdmirx_dqbuf_get_done_fence(struct rk_hdmirx_dev *hdmirx_dev) |
|---|
| 2359 | +{ |
|---|
| 2360 | + unsigned long lock_flags = 0; |
|---|
| 2361 | + struct hdmirx_fence *done_fence; |
|---|
| 2362 | + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2363 | + |
|---|
| 2364 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2365 | + if (!list_empty(&hdmirx_dev->done_fence_list_head)) { |
|---|
| 2366 | + done_fence = list_first_entry(&hdmirx_dev->done_fence_list_head, |
|---|
| 2367 | + struct hdmirx_fence, fence_list); |
|---|
| 2368 | + list_del(&done_fence->fence_list); |
|---|
| 2369 | + } else { |
|---|
| 2370 | + done_fence = NULL; |
|---|
| 2371 | + } |
|---|
| 2372 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2373 | + |
|---|
| 2374 | + if (done_fence) { |
|---|
| 2375 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2376 | + if (hdmirx_dev->hdmirx_fence) { |
|---|
| 2377 | + v4l2_err(v4l2_dev, "%s: last fence not signal, signal now!\n", __func__); |
|---|
| 2378 | + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2379 | + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2380 | + v4l2_dbg(2, debug, v4l2_dev, "%s: signal fence:%p, old_fd:%d\n", |
|---|
| 2381 | + __func__, |
|---|
| 2382 | + hdmirx_dev->hdmirx_fence->fence, |
|---|
| 2383 | + hdmirx_dev->hdmirx_fence->fence_fd); |
|---|
| 2384 | + kfree(hdmirx_dev->hdmirx_fence); |
|---|
| 2385 | + hdmirx_dev->hdmirx_fence = NULL; |
|---|
| 2386 | + } |
|---|
| 2387 | + hdmirx_dev->hdmirx_fence = done_fence; |
|---|
| 2388 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2389 | + v4l2_dbg(3, debug, v4l2_dev, "%s: fence:%p, fence_fd:%d\n", |
|---|
| 2390 | + __func__, done_fence->fence, done_fence->fence_fd); |
|---|
| 2391 | + } |
|---|
| 2392 | +} |
|---|
| 2393 | + |
|---|
| 2394 | +static int hdmirx_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) |
|---|
| 2395 | +{ |
|---|
| 2396 | + int ret; |
|---|
| 2397 | + struct hdmirx_stream *stream = video_drvdata(file); |
|---|
| 2398 | + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; |
|---|
| 2399 | + |
|---|
| 2400 | + if (!hdmirx_dev->get_timing) |
|---|
| 2401 | + return -EINVAL; |
|---|
| 2402 | + |
|---|
| 2403 | + ret = vb2_ioctl_dqbuf(file, priv, p); |
|---|
| 2404 | + hdmirx_dqbuf_get_done_fence(hdmirx_dev); |
|---|
| 2405 | + |
|---|
| 2406 | + return ret; |
|---|
| 2150 | 2407 | } |
|---|
| 2151 | 2408 | |
|---|
| 2152 | 2409 | static long hdmirx_ioctl_default(struct file *file, void *fh, |
|---|
| .. | .. |
|---|
| 2267 | 2524 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
|---|
| 2268 | 2525 | .vidioc_qbuf = vb2_ioctl_qbuf, |
|---|
| 2269 | 2526 | .vidioc_expbuf = vb2_ioctl_expbuf, |
|---|
| 2270 | | - .vidioc_dqbuf = vb2_ioctl_dqbuf, |
|---|
| 2527 | + .vidioc_dqbuf = hdmirx_dqbuf, |
|---|
| 2271 | 2528 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
|---|
| 2272 | 2529 | .vidioc_streamon = vb2_ioctl_streamon, |
|---|
| 2273 | 2530 | .vidioc_streamoff = vb2_ioctl_streamoff, |
|---|
| .. | .. |
|---|
| 2330 | 2587 | return 0; |
|---|
| 2331 | 2588 | } |
|---|
| 2332 | 2589 | |
|---|
| 2590 | +static void process_audio_change(struct rk_hdmirx_dev *hdmirx_dev) |
|---|
| 2591 | +{ |
|---|
| 2592 | + struct hdmirx_stream *stream = &hdmirx_dev->stream; |
|---|
| 2593 | + const struct v4l2_event evt_audio_info = { |
|---|
| 2594 | + .type = RK_HDMIRX_V4L2_EVENT_AUDIOINFO, |
|---|
| 2595 | + }; |
|---|
| 2596 | + v4l2_event_queue(&stream->vdev, &evt_audio_info); |
|---|
| 2597 | +} |
|---|
| 2598 | + |
|---|
| 2333 | 2599 | static void process_signal_change(struct rk_hdmirx_dev *hdmirx_dev) |
|---|
| 2334 | 2600 | { |
|---|
| 2601 | + unsigned long lock_flags = 0; |
|---|
| 2335 | 2602 | struct hdmirx_stream *stream = &hdmirx_dev->stream; |
|---|
| 2336 | 2603 | const struct v4l2_event evt_signal_lost = { |
|---|
| 2337 | 2604 | .type = RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST, |
|---|
| 2338 | 2605 | }; |
|---|
| 2606 | + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2339 | 2607 | |
|---|
| 2340 | 2608 | hdmirx_dev->get_timing = false; |
|---|
| 2341 | 2609 | sip_hdmirx_config(HDMIRX_INFO_NOTIFY, 0, DMA_CONFIG6, 0); |
|---|
| .. | .. |
|---|
| 2349 | 2617 | FIFO_UNDERFLOW_INT_EN | |
|---|
| 2350 | 2618 | HDMIRX_AXI_ERROR_INT_EN, 0); |
|---|
| 2351 | 2619 | hdmirx_reset_dma(hdmirx_dev); |
|---|
| 2620 | + hdmirx_interrupts_setup(hdmirx_dev, false); |
|---|
| 2352 | 2621 | v4l2_event_queue(&stream->vdev, &evt_signal_lost); |
|---|
| 2353 | 2622 | if (hdmirx_dev->hdcp && hdmirx_dev->hdcp->hdcp_stop) |
|---|
| 2354 | 2623 | hdmirx_dev->hdcp->hdcp_stop(hdmirx_dev->hdcp); |
|---|
| 2624 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2625 | + if (hdmirx_dev->hdmirx_fence) { |
|---|
| 2626 | + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2627 | + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2628 | + v4l2_dbg(2, debug, v4l2_dev, "%s: signal fence:%p, old_fd:%d\n", |
|---|
| 2629 | + __func__, |
|---|
| 2630 | + hdmirx_dev->hdmirx_fence->fence, |
|---|
| 2631 | + hdmirx_dev->hdmirx_fence->fence_fd); |
|---|
| 2632 | + kfree(hdmirx_dev->hdmirx_fence); |
|---|
| 2633 | + hdmirx_dev->hdmirx_fence = NULL; |
|---|
| 2634 | + } |
|---|
| 2635 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2355 | 2636 | schedule_delayed_work_on(hdmirx_dev->bound_cpu, |
|---|
| 2356 | 2637 | &hdmirx_dev->delayed_work_res_change, |
|---|
| 2357 | 2638 | msecs_to_jiffies(1000)); |
|---|
| .. | .. |
|---|
| 2459 | 2740 | hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_FORCE, 0x0); |
|---|
| 2460 | 2741 | } |
|---|
| 2461 | 2742 | |
|---|
| 2743 | +/* |
|---|
| 2744 | + * In the normal preview, some scenarios will trigger the change interrupt |
|---|
| 2745 | + * by mistake, and the trigger source of the interrupt needs to be detected |
|---|
| 2746 | + * to avoid the problem. |
|---|
| 2747 | + */ |
|---|
| 2462 | 2748 | static void pkt_0_int_handler(struct rk_hdmirx_dev *hdmirx_dev, |
|---|
| 2463 | 2749 | int status, bool *handled) |
|---|
| 2464 | 2750 | { |
|---|
| 2465 | 2751 | struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2752 | + u32 pre_fmt_fourcc = hdmirx_dev->cur_fmt_fourcc; |
|---|
| 2753 | + u32 pre_color_range = hdmirx_dev->cur_color_range; |
|---|
| 2754 | + u32 pre_color_space = hdmirx_dev->cur_color_space; |
|---|
| 2466 | 2755 | |
|---|
| 2467 | 2756 | if ((status & PKTDEC_AVIIF_CHG_IRQ)) { |
|---|
| 2468 | | - process_signal_change(hdmirx_dev); |
|---|
| 2757 | + hdmirx_get_color_range(hdmirx_dev); |
|---|
| 2758 | + hdmirx_get_color_space(hdmirx_dev); |
|---|
| 2759 | + hdmirx_get_pix_fmt(hdmirx_dev); |
|---|
| 2760 | + if (hdmirx_dev->cur_fmt_fourcc != pre_fmt_fourcc || |
|---|
| 2761 | + hdmirx_dev->cur_color_range != pre_color_range || |
|---|
| 2762 | + hdmirx_dev->cur_color_space != pre_color_space) { |
|---|
| 2763 | + process_signal_change(hdmirx_dev); |
|---|
| 2764 | + } |
|---|
| 2469 | 2765 | v4l2_dbg(2, debug, v4l2_dev, "%s: ptk0_st:%#x\n", |
|---|
| 2470 | 2766 | __func__, status); |
|---|
| 2471 | 2767 | *handled = true; |
|---|
| .. | .. |
|---|
| 2569 | 2865 | { |
|---|
| 2570 | 2866 | const struct hdmirx_output_fmt *fmt = stream->out_fmt; |
|---|
| 2571 | 2867 | u32 i; |
|---|
| 2868 | + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; |
|---|
| 2869 | + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2572 | 2870 | |
|---|
| 2573 | 2871 | /* Dequeue a filled buffer */ |
|---|
| 2574 | 2872 | for (i = 0; i < fmt->mplanes; i++) { |
|---|
| .. | .. |
|---|
| 2578 | 2876 | |
|---|
| 2579 | 2877 | vb_done->vb2_buf.timestamp = ktime_get_ns(); |
|---|
| 2580 | 2878 | vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); |
|---|
| 2879 | + v4l2_dbg(4, debug, v4l2_dev, "vb_done fd:%d", vb_done->vb2_buf.planes[0].m.fd); |
|---|
| 2581 | 2880 | } |
|---|
| 2582 | 2881 | |
|---|
| 2583 | 2882 | static void dma_idle_int_handler(struct rk_hdmirx_dev *hdmirx_dev, bool *handled) |
|---|
| 2584 | 2883 | { |
|---|
| 2884 | + unsigned long lock_flags = 0; |
|---|
| 2585 | 2885 | struct hdmirx_stream *stream = &hdmirx_dev->stream; |
|---|
| 2586 | 2886 | struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2587 | 2887 | struct v4l2_dv_timings timings = hdmirx_dev->timings; |
|---|
| .. | .. |
|---|
| 2591 | 2891 | if (!(stream->irq_stat) && !(stream->irq_stat & LINE_FLAG_INT_EN)) |
|---|
| 2592 | 2892 | v4l2_dbg(1, debug, v4l2_dev, |
|---|
| 2593 | 2893 | "%s: last time have no line_flag_irq\n", __func__); |
|---|
| 2894 | + |
|---|
| 2895 | + if (low_latency) { |
|---|
| 2896 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2897 | + if (hdmirx_dev->hdmirx_fence) { |
|---|
| 2898 | + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2899 | + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 2900 | + v4l2_dbg(3, debug, v4l2_dev, "%s: signal fence:%p, old_fd:%d\n", |
|---|
| 2901 | + __func__, |
|---|
| 2902 | + hdmirx_dev->hdmirx_fence->fence, |
|---|
| 2903 | + hdmirx_dev->hdmirx_fence->fence_fd); |
|---|
| 2904 | + kfree(hdmirx_dev->hdmirx_fence); |
|---|
| 2905 | + hdmirx_dev->hdmirx_fence = NULL; |
|---|
| 2906 | + } |
|---|
| 2907 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2908 | + goto DMA_IDLE_OUT; |
|---|
| 2909 | + } |
|---|
| 2594 | 2910 | |
|---|
| 2595 | 2911 | if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) |
|---|
| 2596 | 2912 | goto DMA_IDLE_OUT; |
|---|
| .. | .. |
|---|
| 2604 | 2920 | if (vb_done) { |
|---|
| 2605 | 2921 | vb_done->vb2_buf.timestamp = ktime_get_ns(); |
|---|
| 2606 | 2922 | vb_done->sequence = stream->frame_idx; |
|---|
| 2923 | + /* config userbits 0 or 0xffffffff as invalid fence_fd*/ |
|---|
| 2924 | + memset(vb_done->timecode.userbits, 0xff, |
|---|
| 2925 | + sizeof(vb_done->timecode.userbits)); |
|---|
| 2607 | 2926 | hdmirx_vb_done(stream, vb_done); |
|---|
| 2608 | 2927 | stream->frame_idx++; |
|---|
| 2609 | 2928 | if (stream->frame_idx == 30) |
|---|
| .. | .. |
|---|
| 2625 | 2944 | *handled = true; |
|---|
| 2626 | 2945 | } |
|---|
| 2627 | 2946 | |
|---|
| 2947 | +static void hdmirx_add_fence_to_vb_done(struct hdmirx_stream *stream, |
|---|
| 2948 | + struct vb2_v4l2_buffer *vb_done) |
|---|
| 2949 | +{ |
|---|
| 2950 | + unsigned long lock_flags = 0; |
|---|
| 2951 | + struct hdmirx_fence *vb_fence; |
|---|
| 2952 | + struct rk_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; |
|---|
| 2953 | + struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2954 | + |
|---|
| 2955 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2956 | + if (!list_empty(&hdmirx_dev->qbuf_fence_list_head)) { |
|---|
| 2957 | + vb_fence = list_first_entry(&hdmirx_dev->qbuf_fence_list_head, |
|---|
| 2958 | + struct hdmirx_fence, fence_list); |
|---|
| 2959 | + list_del(&vb_fence->fence_list); |
|---|
| 2960 | + } else { |
|---|
| 2961 | + vb_fence = NULL; |
|---|
| 2962 | + } |
|---|
| 2963 | + |
|---|
| 2964 | + if (vb_fence) |
|---|
| 2965 | + list_add_tail(&vb_fence->fence_list, &hdmirx_dev->done_fence_list_head); |
|---|
| 2966 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 2967 | + |
|---|
| 2968 | + if (vb_fence) { |
|---|
| 2969 | + /* pass the fence_fd to userspace through timecode.userbits */ |
|---|
| 2970 | + if (put_user(vb_fence->fence_fd, vb_done->timecode.userbits)) |
|---|
| 2971 | + v4l2_err(v4l2_dev, "%s: failed to trans fence fd!\n", __func__); |
|---|
| 2972 | + |
|---|
| 2973 | + v4l2_dbg(3, debug, v4l2_dev, "%s: fence:%p, fence_fd:%d\n", |
|---|
| 2974 | + __func__, vb_fence->fence, vb_fence->fence_fd); |
|---|
| 2975 | + } else { |
|---|
| 2976 | + /* config userbits 0 or 0xffffffff as invalid fence_fd*/ |
|---|
| 2977 | + memset(vb_done->timecode.userbits, 0xff, sizeof(vb_done->timecode.userbits)); |
|---|
| 2978 | + v4l2_err(v4l2_dev, "%s: failed to get fence fd!\n", __func__); |
|---|
| 2979 | + } |
|---|
| 2980 | +} |
|---|
| 2981 | + |
|---|
| 2628 | 2982 | static void line_flag_int_handler(struct rk_hdmirx_dev *hdmirx_dev, bool *handled) |
|---|
| 2629 | 2983 | { |
|---|
| 2984 | + unsigned long lock_flags = 0; |
|---|
| 2630 | 2985 | struct hdmirx_stream *stream = &hdmirx_dev->stream; |
|---|
| 2631 | 2986 | struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; |
|---|
| 2632 | 2987 | struct v4l2_dv_timings timings = hdmirx_dev->timings; |
|---|
| 2633 | 2988 | struct v4l2_bt_timings *bt = &timings.bt; |
|---|
| 2634 | 2989 | u32 dma_cfg6; |
|---|
| 2990 | + struct vb2_v4l2_buffer *vb_done = NULL; |
|---|
| 2635 | 2991 | |
|---|
| 2636 | 2992 | stream->line_flag_int_cnt++; |
|---|
| 2637 | 2993 | if (!(stream->irq_stat) && !(stream->irq_stat & HDMIRX_DMA_IDLE_INT)) |
|---|
| .. | .. |
|---|
| 2648 | 3004 | |
|---|
| 2649 | 3005 | if ((bt->interlaced != V4L2_DV_INTERLACED) || |
|---|
| 2650 | 3006 | (stream->line_flag_int_cnt % 2 == 0)) { |
|---|
| 3007 | + spin_lock_irqsave(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 3008 | + if (hdmirx_dev->hdmirx_fence) { |
|---|
| 3009 | + dma_fence_signal(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 3010 | + dma_fence_put(hdmirx_dev->hdmirx_fence->fence); |
|---|
| 3011 | + v4l2_dbg(2, debug, v4l2_dev, "%s: signal last fence:%p, old_fd:%d\n", |
|---|
| 3012 | + __func__, |
|---|
| 3013 | + hdmirx_dev->hdmirx_fence->fence, |
|---|
| 3014 | + hdmirx_dev->hdmirx_fence->fence_fd); |
|---|
| 3015 | + kfree(hdmirx_dev->hdmirx_fence); |
|---|
| 3016 | + hdmirx_dev->hdmirx_fence = NULL; |
|---|
| 3017 | + } |
|---|
| 3018 | + spin_unlock_irqrestore(&hdmirx_dev->fence_lock, lock_flags); |
|---|
| 3019 | + |
|---|
| 2651 | 3020 | if (!stream->next_buf) { |
|---|
| 2652 | 3021 | spin_lock(&stream->vbq_lock); |
|---|
| 2653 | 3022 | if (!list_empty(&stream->buf_head)) { |
|---|
| .. | .. |
|---|
| 2659 | 3028 | } |
|---|
| 2660 | 3029 | spin_unlock(&stream->vbq_lock); |
|---|
| 2661 | 3030 | |
|---|
| 2662 | | - if (stream->next_buf) { |
|---|
| 2663 | | - hdmirx_writel(hdmirx_dev, DMA_CONFIG2, |
|---|
| 2664 | | - stream->next_buf->buff_addr[HDMIRX_PLANE_Y]); |
|---|
| 2665 | | - hdmirx_writel(hdmirx_dev, DMA_CONFIG3, |
|---|
| 2666 | | - stream->next_buf->buff_addr[HDMIRX_PLANE_CBCR]); |
|---|
| 2667 | | - } else { |
|---|
| 2668 | | - v4l2_dbg(3, debug, v4l2_dev, |
|---|
| 2669 | | - "%s: No buffer is available\n", __func__); |
|---|
| 3031 | + } |
|---|
| 3032 | + |
|---|
| 3033 | + if (stream->next_buf) { |
|---|
| 3034 | + hdmirx_writel(hdmirx_dev, DMA_CONFIG2, |
|---|
| 3035 | + stream->next_buf->buff_addr[HDMIRX_PLANE_Y]); |
|---|
| 3036 | + hdmirx_writel(hdmirx_dev, DMA_CONFIG3, |
|---|
| 3037 | + stream->next_buf->buff_addr[HDMIRX_PLANE_CBCR]); |
|---|
| 3038 | + |
|---|
| 3039 | + if (low_latency) { |
|---|
| 3040 | + if (stream->curr_buf) |
|---|
| 3041 | + vb_done = &stream->curr_buf->vb; |
|---|
| 3042 | + |
|---|
| 3043 | + if (vb_done) { |
|---|
| 3044 | + hdmirx_add_fence_to_vb_done(stream, vb_done); |
|---|
| 3045 | + vb_done->vb2_buf.timestamp = ktime_get_ns(); |
|---|
| 3046 | + vb_done->sequence = stream->frame_idx; |
|---|
| 3047 | + hdmirx_vb_done(stream, vb_done); |
|---|
| 3048 | + stream->frame_idx++; |
|---|
| 3049 | + if (stream->frame_idx == 30) |
|---|
| 3050 | + v4l2_info(v4l2_dev, "rcv frames\n"); |
|---|
| 3051 | + } |
|---|
| 3052 | + |
|---|
| 3053 | + stream->curr_buf = stream->next_buf; |
|---|
| 3054 | + stream->next_buf = NULL; |
|---|
| 2670 | 3055 | } |
|---|
| 3056 | + } else { |
|---|
| 3057 | + v4l2_dbg(3, debug, v4l2_dev, |
|---|
| 3058 | + "%s: next_buf NULL, drop the frame!\n", __func__); |
|---|
| 3059 | + } |
|---|
| 3060 | + |
|---|
| 3061 | + if (stream->curr_buf) { |
|---|
| 3062 | + v4l2_dbg(4, debug, v4l2_dev, "%s: curr_fd:%d\n", |
|---|
| 3063 | + __func__, stream->curr_buf->vb.vb2_buf.planes[0].m.fd); |
|---|
| 3064 | + } |
|---|
| 3065 | + |
|---|
| 3066 | + if (stream->next_buf) { |
|---|
| 3067 | + v4l2_dbg(4, debug, v4l2_dev, "%s: next_fd:%d\n", |
|---|
| 3068 | + __func__, stream->next_buf->vb.vb2_buf.planes[0].m.fd); |
|---|
| 2671 | 3069 | } |
|---|
| 2672 | 3070 | } else { |
|---|
| 2673 | 3071 | v4l2_dbg(3, debug, v4l2_dev, "%s: interlace:%d, line_flag_int_cnt:%d\n", |
|---|
| .. | .. |
|---|
| 3158 | 3556 | struct rk_hdmirx_dev, |
|---|
| 3159 | 3557 | delayed_work_audio); |
|---|
| 3160 | 3558 | struct hdmirx_audiostate *as = &hdmirx_dev->audio_state; |
|---|
| 3161 | | - u32 fs_audio, ch_audio; |
|---|
| 3559 | + u32 fs_audio, ch_audio, sample_flat; |
|---|
| 3162 | 3560 | int cur_state, init_state, pre_state, fifo_status2; |
|---|
| 3163 | 3561 | unsigned long delay = 200; |
|---|
| 3164 | 3562 | |
|---|
| .. | .. |
|---|
| 3209 | 3607 | if (!hdmirx_dev->audio_present) { |
|---|
| 3210 | 3608 | dev_info(hdmirx_dev->dev, "audio on"); |
|---|
| 3211 | 3609 | hdmirx_audio_handle_plugged_change(hdmirx_dev, 1); |
|---|
| 3610 | + process_audio_change(hdmirx_dev); |
|---|
| 3212 | 3611 | hdmirx_dev->audio_present = true; |
|---|
| 3213 | 3612 | } |
|---|
| 3214 | 3613 | if (cur_state - init_state > 16 && cur_state - pre_state > 0) |
|---|
| .. | .. |
|---|
| 3219 | 3618 | if (hdmirx_dev->audio_present) { |
|---|
| 3220 | 3619 | dev_info(hdmirx_dev->dev, "audio off"); |
|---|
| 3221 | 3620 | hdmirx_audio_handle_plugged_change(hdmirx_dev, 0); |
|---|
| 3621 | + process_audio_change(hdmirx_dev); |
|---|
| 3222 | 3622 | hdmirx_dev->audio_present = false; |
|---|
| 3223 | 3623 | } |
|---|
| 3224 | 3624 | } |
|---|
| 3225 | 3625 | as->pre_state = cur_state; |
|---|
| 3626 | + |
|---|
| 3627 | + sample_flat = hdmirx_readl(hdmirx_dev, AUDIO_PROC_STATUS1) & AUD_SAMPLE_FLAT; |
|---|
| 3628 | + hdmirx_update_bits(hdmirx_dev, AUDIO_PROC_CONFIG0, I2S_EN, sample_flat ? 0 : I2S_EN); |
|---|
| 3629 | + |
|---|
| 3226 | 3630 | exit: |
|---|
| 3227 | 3631 | schedule_delayed_work_on(hdmirx_dev->bound_cpu, |
|---|
| 3228 | 3632 | &hdmirx_dev->delayed_work_audio, |
|---|
| .. | .. |
|---|
| 3243 | 3647 | plugin = tx_5v_power_present(hdmirx_dev); |
|---|
| 3244 | 3648 | v4l2_dbg(1, debug, v4l2_dev, "%s: plugin:%d\n", __func__, plugin); |
|---|
| 3245 | 3649 | if (plugin) { |
|---|
| 3246 | | - hdmirx_interrupts_setup(hdmirx_dev, false); |
|---|
| 3247 | 3650 | hdmirx_submodule_init(hdmirx_dev); |
|---|
| 3248 | 3651 | hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, |
|---|
| 3249 | 3652 | POWERPROVIDED); |
|---|
| .. | .. |
|---|
| 4133 | 4536 | dev_err(hdmirx_dev->dev, "%s freq qos nod add\n", __func__); |
|---|
| 4134 | 4537 | } |
|---|
| 4135 | 4538 | |
|---|
| 4539 | +static int hdmirx_get_custom_ctrl(struct v4l2_ctrl *ctrl) |
|---|
| 4540 | +{ |
|---|
| 4541 | + struct rk_hdmirx_dev *hdmirx_dev = container_of(ctrl->handler, struct rk_hdmirx_dev, hdl); |
|---|
| 4542 | + int ret = 0; |
|---|
| 4543 | + |
|---|
| 4544 | + if (ctrl->id == RK_V4L2_CID_AUDIO_SAMPLING_RATE) { |
|---|
| 4545 | + *ctrl->p_new.p_s32 = hdmirx_dev->audio_state.fs_audio; |
|---|
| 4546 | + } else if (ctrl->id == RK_V4L2_CID_AUDIO_PRESENT) { |
|---|
| 4547 | + *ctrl->p_new.p_s32 = tx_5v_power_present(hdmirx_dev) ? |
|---|
| 4548 | + hdmirx_dev->audio_present : 0; |
|---|
| 4549 | + } else { |
|---|
| 4550 | + ret = -EINVAL; |
|---|
| 4551 | + } |
|---|
| 4552 | + return ret; |
|---|
| 4553 | +} |
|---|
| 4554 | + |
|---|
| 4555 | +static const struct v4l2_ctrl_ops hdmirx_custom_ctrl_ops = { |
|---|
| 4556 | + .g_volatile_ctrl = hdmirx_get_custom_ctrl, |
|---|
| 4557 | +}; |
|---|
| 4558 | + |
|---|
| 4559 | +static const struct v4l2_ctrl_config hdmirx_ctrl_audio_sampling_rate = { |
|---|
| 4560 | + .ops = &hdmirx_custom_ctrl_ops, |
|---|
| 4561 | + .id = RK_V4L2_CID_AUDIO_SAMPLING_RATE, |
|---|
| 4562 | + .name = "Audio sampling rate", |
|---|
| 4563 | + .type = V4L2_CTRL_TYPE_INTEGER, |
|---|
| 4564 | + .min = 0, |
|---|
| 4565 | + .max = 768000, |
|---|
| 4566 | + .step = 1, |
|---|
| 4567 | + .def = 0, |
|---|
| 4568 | + .flags = V4L2_CTRL_FLAG_READ_ONLY, |
|---|
| 4569 | +}; |
|---|
| 4570 | + |
|---|
| 4571 | +static const struct v4l2_ctrl_config hdmirx_ctrl_audio_present = { |
|---|
| 4572 | + .ops = &hdmirx_custom_ctrl_ops, |
|---|
| 4573 | + .id = RK_V4L2_CID_AUDIO_PRESENT, |
|---|
| 4574 | + .name = "Audio present", |
|---|
| 4575 | + .type = V4L2_CTRL_TYPE_BOOLEAN, |
|---|
| 4576 | + .min = 0, |
|---|
| 4577 | + .max = 1, |
|---|
| 4578 | + .step = 1, |
|---|
| 4579 | + .def = 0, |
|---|
| 4580 | + .flags = V4L2_CTRL_FLAG_READ_ONLY, |
|---|
| 4581 | +}; |
|---|
| 4582 | + |
|---|
| 4136 | 4583 | static int hdmirx_probe(struct platform_device *pdev) |
|---|
| 4137 | 4584 | { |
|---|
| 4138 | 4585 | const struct v4l2_dv_timings timings_def = HDMIRX_DEFAULT_TIMING; |
|---|
| .. | .. |
|---|
| 4166 | 4613 | return PTR_ERR(hdmirx_dev->regs); |
|---|
| 4167 | 4614 | } |
|---|
| 4168 | 4615 | |
|---|
| 4169 | | - if (sip_cpu_logical_map_mpidr(0) == 0) |
|---|
| 4170 | | - cpu_aff = sip_cpu_logical_map_mpidr(4); // big cpu0 |
|---|
| 4171 | | - else |
|---|
| 4172 | | - cpu_aff = sip_cpu_logical_map_mpidr(1); // big cpu1 |
|---|
| 4616 | + /* |
|---|
| 4617 | + * Bind HDMIRX's FIQ and driver interrupt processing to big cpu1 |
|---|
| 4618 | + * in order to quickly respond to FIQ and prevent them from affecting |
|---|
| 4619 | + * each other. |
|---|
| 4620 | + */ |
|---|
| 4621 | + if (sip_cpu_logical_map_mpidr(0) == 0) { |
|---|
| 4622 | + cpu_aff = sip_cpu_logical_map_mpidr(5); |
|---|
| 4623 | + hdmirx_dev->bound_cpu = 5; |
|---|
| 4624 | + } else { |
|---|
| 4625 | + cpu_aff = sip_cpu_logical_map_mpidr(1); |
|---|
| 4626 | + hdmirx_dev->bound_cpu = 1; |
|---|
| 4627 | + } |
|---|
| 4173 | 4628 | |
|---|
| 4174 | 4629 | sip_fiq_control(RK_SIP_FIQ_CTRL_SET_AFF, RK_IRQ_HDMIRX_HDMI, cpu_aff); |
|---|
| 4175 | | - hdmirx_dev->bound_cpu = (cpu_aff >> 8) & 0xf; |
|---|
| 4630 | + hdmirx_dev->phy_cpuid = (cpu_aff >> 8) & 0xf; |
|---|
| 4176 | 4631 | hdmirx_dev->wdt_cfg_bound_cpu = hdmirx_dev->bound_cpu + 1; |
|---|
| 4177 | | - dev_info(dev, "%s: cpu_aff:%#x, Bound_cpu:%d, wdt_cfg_bound_cpu:%d\n", |
|---|
| 4632 | + dev_info(dev, "%s: cpu_aff:%#x, Bound_cpu:%d, wdt_cfg_bound_cpu:%d, phy_cpuid:%d\n", |
|---|
| 4178 | 4633 | __func__, cpu_aff, |
|---|
| 4179 | 4634 | hdmirx_dev->bound_cpu, |
|---|
| 4180 | | - hdmirx_dev->wdt_cfg_bound_cpu); |
|---|
| 4635 | + hdmirx_dev->wdt_cfg_bound_cpu, |
|---|
| 4636 | + hdmirx_dev->phy_cpuid); |
|---|
| 4181 | 4637 | cpu_latency_qos_add_request(&hdmirx_dev->pm_qos, PM_QOS_DEFAULT_VALUE); |
|---|
| 4182 | 4638 | |
|---|
| 4183 | 4639 | mutex_init(&hdmirx_dev->stream_lock); |
|---|
| 4184 | 4640 | mutex_init(&hdmirx_dev->work_lock); |
|---|
| 4185 | 4641 | spin_lock_init(&hdmirx_dev->rst_lock); |
|---|
| 4642 | + spin_lock_init(&hdmirx_dev->fence_lock); |
|---|
| 4643 | + INIT_LIST_HEAD(&hdmirx_dev->qbuf_fence_list_head); |
|---|
| 4644 | + INIT_LIST_HEAD(&hdmirx_dev->done_fence_list_head); |
|---|
| 4186 | 4645 | INIT_WORK(&hdmirx_dev->work_wdt_config, |
|---|
| 4187 | 4646 | hdmirx_work_wdt_config); |
|---|
| 4188 | 4647 | INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_hotplug, |
|---|
| .. | .. |
|---|
| 4246 | 4705 | strscpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name)); |
|---|
| 4247 | 4706 | |
|---|
| 4248 | 4707 | hdl = &hdmirx_dev->hdl; |
|---|
| 4249 | | - v4l2_ctrl_handler_init(hdl, 1); |
|---|
| 4708 | + v4l2_ctrl_handler_init(hdl, 3); |
|---|
| 4250 | 4709 | hdmirx_dev->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, |
|---|
| 4251 | 4710 | NULL, V4L2_CID_DV_RX_POWER_PRESENT, |
|---|
| 4252 | 4711 | 0, 1, 0, 0); |
|---|
| 4712 | + /* custom controls */ |
|---|
| 4713 | + hdmirx_dev->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(hdl, |
|---|
| 4714 | + &hdmirx_ctrl_audio_sampling_rate, NULL); |
|---|
| 4715 | + if (hdmirx_dev->audio_sampling_rate_ctrl) |
|---|
| 4716 | + hdmirx_dev->audio_sampling_rate_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; |
|---|
| 4717 | + hdmirx_dev->audio_present_ctrl = v4l2_ctrl_new_custom(hdl, |
|---|
| 4718 | + &hdmirx_ctrl_audio_present, NULL); |
|---|
| 4719 | + if (hdmirx_dev->audio_present_ctrl) |
|---|
| 4720 | + hdmirx_dev->audio_present_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; |
|---|
| 4253 | 4721 | if (hdl->error) { |
|---|
| 4254 | 4722 | dev_err(dev, "v4l2 ctrl handler init failed!\n"); |
|---|
| 4255 | 4723 | ret = hdl->error; |
|---|
| .. | .. |
|---|
| 4280 | 4748 | if (ret) |
|---|
| 4281 | 4749 | goto err_unreg_video_dev; |
|---|
| 4282 | 4750 | |
|---|
| 4283 | | - hdmirx_dev->classdev = device_create_with_groups(hdmirx_class, |
|---|
| 4751 | + hdmirx_dev->classdev = device_create_with_groups(rk_hdmirx_class(), |
|---|
| 4284 | 4752 | dev, MKDEV(0, 0), |
|---|
| 4285 | 4753 | hdmirx_dev, |
|---|
| 4286 | 4754 | hdmirx_groups, |
|---|
| .. | .. |
|---|
| 4357 | 4825 | hdmirx_register_hdcp(dev, hdmirx_dev, hdmirx_dev->hdcp_enable); |
|---|
| 4358 | 4826 | |
|---|
| 4359 | 4827 | hdmirx_register_debugfs(hdmirx_dev->dev, hdmirx_dev); |
|---|
| 4360 | | - |
|---|
| 4828 | + hdmirx_fence_context_init(&hdmirx_dev->fence_ctx); |
|---|
| 4829 | + hdmirx_dev->hdmirx_fence = NULL; |
|---|
| 4361 | 4830 | hdmirx_dev->initialized = true; |
|---|
| 4362 | 4831 | dev_info(dev, "%s driver probe ok!\n", dev_name(dev)); |
|---|
| 4363 | 4832 | |
|---|
| .. | .. |
|---|
| 4388 | 4857 | struct rk_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); |
|---|
| 4389 | 4858 | |
|---|
| 4390 | 4859 | debugfs_remove_recursive(hdmirx_dev->debugfs_dir); |
|---|
| 4391 | | - |
|---|
| 4392 | 4860 | cpu_latency_qos_remove_request(&hdmirx_dev->pm_qos); |
|---|
| 4393 | 4861 | cancel_delayed_work(&hdmirx_dev->delayed_work_hotplug); |
|---|
| 4394 | 4862 | cancel_delayed_work(&hdmirx_dev->delayed_work_res_change); |
|---|
| .. | .. |
|---|
| 4438 | 4906 | |
|---|
| 4439 | 4907 | static int __init hdmirx_init(void) |
|---|
| 4440 | 4908 | { |
|---|
| 4441 | | - hdmirx_class = class_create(THIS_MODULE, "hdmirx"); |
|---|
| 4442 | | - if (IS_ERR(hdmirx_class)) |
|---|
| 4443 | | - return PTR_ERR(hdmirx_class); |
|---|
| 4444 | 4909 | return platform_driver_register(&hdmirx_driver); |
|---|
| 4445 | 4910 | } |
|---|
| 4446 | 4911 | module_init(hdmirx_init); |
|---|
| .. | .. |
|---|
| 4448 | 4913 | static void __exit hdmirx_exit(void) |
|---|
| 4449 | 4914 | { |
|---|
| 4450 | 4915 | platform_driver_unregister(&hdmirx_driver); |
|---|
| 4451 | | - class_destroy(hdmirx_class); |
|---|
| 4452 | 4916 | } |
|---|
| 4453 | 4917 | module_exit(hdmirx_exit); |
|---|
| 4454 | 4918 | |
|---|