17b59b132SShreeya Patel // SPDX-License-Identifier: GPL-2.0 27b59b132SShreeya Patel /* 37b59b132SShreeya Patel * Copyright (C) 2025 Collabora, Ltd. 47b59b132SShreeya Patel * Author: Shreeya Patel <shreeya.patel@collabora.com> 57b59b132SShreeya Patel * Author: Dmitry Osipenko <dmitry.osipenko@collabora.com> 67b59b132SShreeya Patel * 77b59b132SShreeya Patel * Copyright (c) 2021 Rockchip Electronics Co. Ltd. 87b59b132SShreeya Patel * Author: Dingxian Wen <shawn.wen@rock-chips.com> 97b59b132SShreeya Patel */ 107b59b132SShreeya Patel 117b59b132SShreeya Patel #include <linux/clk.h> 127b59b132SShreeya Patel #include <linux/completion.h> 137b59b132SShreeya Patel #include <linux/delay.h> 147b59b132SShreeya Patel #include <linux/dma-mapping.h> 157b59b132SShreeya Patel #include <linux/gpio/consumer.h> 167b59b132SShreeya Patel #include <linux/hdmi.h> 177b59b132SShreeya Patel #include <linux/interrupt.h> 187b59b132SShreeya Patel #include <linux/irq.h> 197b59b132SShreeya Patel #include <linux/mfd/syscon.h> 20fae8cab4SNathan Chancellor #include <linux/math64.h> 217b59b132SShreeya Patel #include <linux/module.h> 227b59b132SShreeya Patel #include <linux/of.h> 237b59b132SShreeya Patel #include <linux/of_platform.h> 247b59b132SShreeya Patel #include <linux/of_reserved_mem.h> 257b59b132SShreeya Patel #include <linux/pinctrl/consumer.h> 267b59b132SShreeya Patel #include <linux/platform_device.h> 277b59b132SShreeya Patel #include <linux/property.h> 287b59b132SShreeya Patel #include <linux/regmap.h> 297b59b132SShreeya Patel #include <linux/reset.h> 307b59b132SShreeya Patel #include <linux/v4l2-dv-timings.h> 317b59b132SShreeya Patel #include <linux/workqueue.h> 327b59b132SShreeya Patel 337b59b132SShreeya Patel #include <media/cec.h> 347b59b132SShreeya Patel #include <media/v4l2-common.h> 357b59b132SShreeya Patel #include <media/v4l2-ctrls.h> 367b59b132SShreeya Patel #include <media/v4l2-device.h> 377b59b132SShreeya Patel #include <media/v4l2-dv-timings.h> 387b59b132SShreeya Patel #include <media/v4l2-event.h> 397b59b132SShreeya Patel #include <media/v4l2-fh.h> 407b59b132SShreeya Patel #include <media/v4l2-ioctl.h> 417b59b132SShreeya Patel #include <media/videobuf2-dma-contig.h> 427b59b132SShreeya Patel #include <media/videobuf2-v4l2.h> 437b59b132SShreeya Patel 447b59b132SShreeya Patel #include "snps_hdmirx.h" 457b59b132SShreeya Patel #include "snps_hdmirx_cec.h" 467b59b132SShreeya Patel 477b59b132SShreeya Patel #define EDID_NUM_BLOCKS_MAX 4 487b59b132SShreeya Patel #define EDID_BLOCK_SIZE 128 497b59b132SShreeya Patel #define HDMIRX_PLANE_Y 0 507b59b132SShreeya Patel #define HDMIRX_PLANE_CBCR 1 517b59b132SShreeya Patel #define FILTER_FRAME_CNT 6 527b59b132SShreeya Patel 537b59b132SShreeya Patel static int debug; 547b59b132SShreeya Patel module_param(debug, int, 0644); 557b59b132SShreeya Patel MODULE_PARM_DESC(debug, "debug level (0-3)"); 567b59b132SShreeya Patel 577b59b132SShreeya Patel enum hdmirx_pix_fmt { 587b59b132SShreeya Patel HDMIRX_RGB888 = 0, 597b59b132SShreeya Patel HDMIRX_YUV422 = 1, 607b59b132SShreeya Patel HDMIRX_YUV444 = 2, 617b59b132SShreeya Patel HDMIRX_YUV420 = 3, 627b59b132SShreeya Patel }; 637b59b132SShreeya Patel 647b59b132SShreeya Patel enum ddr_store_fmt { 657b59b132SShreeya Patel STORE_RGB888 = 0, 667b59b132SShreeya Patel STORE_RGBA_ARGB, 677b59b132SShreeya Patel STORE_YUV420_8BIT, 687b59b132SShreeya Patel STORE_YUV420_10BIT, 697b59b132SShreeya Patel STORE_YUV422_8BIT, 707b59b132SShreeya Patel STORE_YUV422_10BIT, 717b59b132SShreeya Patel STORE_YUV444_8BIT, 727b59b132SShreeya Patel STORE_YUV420_16BIT = 8, 737b59b132SShreeya Patel STORE_YUV422_16BIT = 9, 747b59b132SShreeya Patel }; 757b59b132SShreeya Patel 767b59b132SShreeya Patel enum hdmirx_reg_attr { 777b59b132SShreeya Patel HDMIRX_ATTR_RW = 0, 787b59b132SShreeya Patel HDMIRX_ATTR_RO = 1, 797b59b132SShreeya Patel HDMIRX_ATTR_WO = 2, 807b59b132SShreeya Patel HDMIRX_ATTR_RE = 3, 817b59b132SShreeya Patel }; 827b59b132SShreeya Patel 837b59b132SShreeya Patel enum { 847b59b132SShreeya Patel HDMIRX_RST_A, 857b59b132SShreeya Patel HDMIRX_RST_P, 867b59b132SShreeya Patel HDMIRX_RST_REF, 877b59b132SShreeya Patel HDMIRX_RST_BIU, 887b59b132SShreeya Patel HDMIRX_NUM_RST, 897b59b132SShreeya Patel }; 907b59b132SShreeya Patel 917b59b132SShreeya Patel static const char *const pix_fmt_str[] = { 927b59b132SShreeya Patel "RGB888", 937b59b132SShreeya Patel "YUV422", 947b59b132SShreeya Patel "YUV444", 957b59b132SShreeya Patel "YUV420", 967b59b132SShreeya Patel }; 977b59b132SShreeya Patel 987b59b132SShreeya Patel struct hdmirx_buffer { 997b59b132SShreeya Patel struct vb2_v4l2_buffer vb; 1007b59b132SShreeya Patel struct list_head queue; 1017b59b132SShreeya Patel u32 buff_addr[VIDEO_MAX_PLANES]; 1027b59b132SShreeya Patel }; 1037b59b132SShreeya Patel 1047b59b132SShreeya Patel struct hdmirx_stream { 1057b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev; 1067b59b132SShreeya Patel struct video_device vdev; 1077b59b132SShreeya Patel struct vb2_queue buf_queue; 1087b59b132SShreeya Patel struct list_head buf_head; 1097b59b132SShreeya Patel struct hdmirx_buffer *curr_buf; 1107b59b132SShreeya Patel struct hdmirx_buffer *next_buf; 1117b59b132SShreeya Patel struct v4l2_pix_format_mplane pixm; 1127b59b132SShreeya Patel const struct v4l2_format_info *out_finfo; 1137b59b132SShreeya Patel struct mutex vlock; /* to lock resources associated with video buffer and video device */ 1147b59b132SShreeya Patel spinlock_t vbq_lock; /* to lock video buffer queue */ 1157b59b132SShreeya Patel bool stopping; 1167b59b132SShreeya Patel wait_queue_head_t wq_stopped; 1170400bee6SNicolas Dufresne u32 sequence; 1187b59b132SShreeya Patel u32 line_flag_int_cnt; 1197b59b132SShreeya Patel u32 irq_stat; 1207b59b132SShreeya Patel }; 1217b59b132SShreeya Patel 1227b59b132SShreeya Patel struct snps_hdmirx_dev { 1237b59b132SShreeya Patel struct device *dev; 1247b59b132SShreeya Patel struct hdmirx_stream stream; 1257b59b132SShreeya Patel struct v4l2_device v4l2_dev; 1267b59b132SShreeya Patel struct v4l2_ctrl_handler hdl; 1277b59b132SShreeya Patel struct v4l2_ctrl *detect_tx_5v_ctrl; 1287b59b132SShreeya Patel struct v4l2_ctrl *rgb_range; 1297b59b132SShreeya Patel struct v4l2_ctrl *content_type; 1307b59b132SShreeya Patel struct v4l2_dv_timings timings; 1317b59b132SShreeya Patel struct gpio_desc *detect_5v_gpio; 1327b59b132SShreeya Patel struct delayed_work delayed_work_hotplug; 1337b59b132SShreeya Patel struct delayed_work delayed_work_res_change; 1347b59b132SShreeya Patel struct hdmirx_cec *cec; 1357b59b132SShreeya Patel struct mutex stream_lock; /* to lock video stream capture */ 1367b59b132SShreeya Patel struct mutex work_lock; /* to lock the critical section of hotplug event */ 1377b59b132SShreeya Patel struct reset_control_bulk_data resets[HDMIRX_NUM_RST]; 1387b59b132SShreeya Patel struct clk_bulk_data *clks; 1397b59b132SShreeya Patel struct regmap *grf; 1407b59b132SShreeya Patel struct regmap *vo1_grf; 1417b59b132SShreeya Patel struct completion cr_write_done; 1427b59b132SShreeya Patel struct completion timer_base_lock; 1437b59b132SShreeya Patel struct completion avi_pkt_rcv; 1447b59b132SShreeya Patel struct dentry *debugfs_dir; 1457b59b132SShreeya Patel struct v4l2_debugfs_if *infoframes; 1467b59b132SShreeya Patel enum hdmirx_pix_fmt pix_fmt; 1477b59b132SShreeya Patel void __iomem *regs; 1487b59b132SShreeya Patel int hdmi_irq; 1497b59b132SShreeya Patel int dma_irq; 1507b59b132SShreeya Patel int det_irq; 1517b59b132SShreeya Patel bool hpd_trigger_level_high; 1527b59b132SShreeya Patel bool tmds_clk_ratio; 1537b59b132SShreeya Patel bool plugged; 154ca8dc595SDan Carpenter int num_clks; 1557b59b132SShreeya Patel u32 edid_blocks_written; 1567b59b132SShreeya Patel u32 cur_fmt_fourcc; 1577b59b132SShreeya Patel u32 color_depth; 1587b59b132SShreeya Patel spinlock_t rst_lock; /* to lock register access */ 159308e51f4SDmitry Osipenko u8 edid[EDID_NUM_BLOCKS_MAX * EDID_BLOCK_SIZE]; 1607b59b132SShreeya Patel }; 1617b59b132SShreeya Patel 1627b59b132SShreeya Patel static const struct v4l2_dv_timings cea640x480 = V4L2_DV_BT_CEA_640X480P59_94; 1637b59b132SShreeya Patel 1647b59b132SShreeya Patel static const struct v4l2_dv_timings_cap hdmirx_timings_cap = { 1657b59b132SShreeya Patel .type = V4L2_DV_BT_656_1120, 1667b59b132SShreeya Patel .reserved = { 0 }, 1677b59b132SShreeya Patel V4L2_INIT_BT_TIMINGS(640, 4096, /* min/max width */ 1687b59b132SShreeya Patel 480, 2160, /* min/max height */ 1697b59b132SShreeya Patel 20000000, 600000000, /* min/max pixelclock */ 1707b59b132SShreeya Patel /* standards */ 1717b59b132SShreeya Patel V4L2_DV_BT_STD_CEA861, 1727b59b132SShreeya Patel /* capabilities */ 1737b59b132SShreeya Patel V4L2_DV_BT_CAP_PROGRESSIVE | 1747b59b132SShreeya Patel V4L2_DV_BT_CAP_INTERLACED) 1757b59b132SShreeya Patel }; 1767b59b132SShreeya Patel 1777b59b132SShreeya Patel static void hdmirx_writel(struct snps_hdmirx_dev *hdmirx_dev, int reg, u32 val) 1787b59b132SShreeya Patel { 1797b59b132SShreeya Patel guard(spinlock_irqsave)(&hdmirx_dev->rst_lock); 1807b59b132SShreeya Patel 1817b59b132SShreeya Patel writel(val, hdmirx_dev->regs + reg); 1827b59b132SShreeya Patel } 1837b59b132SShreeya Patel 1847b59b132SShreeya Patel static u32 hdmirx_readl(struct snps_hdmirx_dev *hdmirx_dev, int reg) 1857b59b132SShreeya Patel { 1867b59b132SShreeya Patel guard(spinlock_irqsave)(&hdmirx_dev->rst_lock); 1877b59b132SShreeya Patel 1887b59b132SShreeya Patel return readl(hdmirx_dev->regs + reg); 1897b59b132SShreeya Patel } 1907b59b132SShreeya Patel 1917b59b132SShreeya Patel static void hdmirx_reset_dma(struct snps_hdmirx_dev *hdmirx_dev) 1927b59b132SShreeya Patel { 1937b59b132SShreeya Patel guard(spinlock_irqsave)(&hdmirx_dev->rst_lock); 1947b59b132SShreeya Patel 1957b59b132SShreeya Patel reset_control_reset(hdmirx_dev->resets[0].rstc); 1967b59b132SShreeya Patel } 1977b59b132SShreeya Patel 1987b59b132SShreeya Patel static void hdmirx_update_bits(struct snps_hdmirx_dev *hdmirx_dev, int reg, 1997b59b132SShreeya Patel u32 mask, u32 data) 2007b59b132SShreeya Patel { 2017b59b132SShreeya Patel u32 val; 2027b59b132SShreeya Patel 2037b59b132SShreeya Patel guard(spinlock_irqsave)(&hdmirx_dev->rst_lock); 2047b59b132SShreeya Patel 2057b59b132SShreeya Patel val = readl(hdmirx_dev->regs + reg) & ~mask; 2067b59b132SShreeya Patel val |= (data & mask); 2077b59b132SShreeya Patel writel(val, hdmirx_dev->regs + reg); 2087b59b132SShreeya Patel } 2097b59b132SShreeya Patel 2107b59b132SShreeya Patel static int hdmirx_subscribe_event(struct v4l2_fh *fh, 2117b59b132SShreeya Patel const struct v4l2_event_subscription *sub) 2127b59b132SShreeya Patel { 2137b59b132SShreeya Patel switch (sub->type) { 2147b59b132SShreeya Patel case V4L2_EVENT_SOURCE_CHANGE: 2157b59b132SShreeya Patel return v4l2_src_change_event_subscribe(fh, sub); 2167b59b132SShreeya Patel case V4L2_EVENT_CTRL: 2177b59b132SShreeya Patel return v4l2_ctrl_subscribe_event(fh, sub); 2187b59b132SShreeya Patel default: 2197b59b132SShreeya Patel break; 2207b59b132SShreeya Patel } 2217b59b132SShreeya Patel 2227b59b132SShreeya Patel return -EINVAL; 2237b59b132SShreeya Patel } 2247b59b132SShreeya Patel 2257b59b132SShreeya Patel static bool tx_5v_power_present(struct snps_hdmirx_dev *hdmirx_dev) 2267b59b132SShreeya Patel { 2277b59b132SShreeya Patel const unsigned int detection_threshold = 7; 2287b59b132SShreeya Patel int val, i, cnt = 0; 2297b59b132SShreeya Patel bool ret; 2307b59b132SShreeya Patel 2317b59b132SShreeya Patel for (i = 0; i < 10; i++) { 2327b59b132SShreeya Patel usleep_range(1000, 1100); 2337b59b132SShreeya Patel val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); 2347b59b132SShreeya Patel if (val > 0) 2357b59b132SShreeya Patel cnt++; 2367b59b132SShreeya Patel if (cnt >= detection_threshold) 2377b59b132SShreeya Patel break; 2387b59b132SShreeya Patel } 2397b59b132SShreeya Patel 2407b59b132SShreeya Patel ret = (cnt >= detection_threshold) ? true : false; 2417b59b132SShreeya Patel v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: %d\n", __func__, ret); 2427b59b132SShreeya Patel 2437b59b132SShreeya Patel return ret; 2447b59b132SShreeya Patel } 2457b59b132SShreeya Patel 2467b59b132SShreeya Patel static bool signal_not_lock(struct snps_hdmirx_dev *hdmirx_dev) 2477b59b132SShreeya Patel { 2487b59b132SShreeya Patel u32 mu_status, dma_st10, cmu_st; 2497b59b132SShreeya Patel 2507b59b132SShreeya Patel mu_status = hdmirx_readl(hdmirx_dev, MAINUNIT_STATUS); 2517b59b132SShreeya Patel dma_st10 = hdmirx_readl(hdmirx_dev, DMA_STATUS10); 2527b59b132SShreeya Patel cmu_st = hdmirx_readl(hdmirx_dev, CMU_STATUS); 2537b59b132SShreeya Patel 2547b59b132SShreeya Patel if ((mu_status & TMDSVALID_STABLE_ST) && 2557b59b132SShreeya Patel (dma_st10 & HDMIRX_LOCK) && 2567b59b132SShreeya Patel (cmu_st & TMDSQPCLK_LOCKED_ST)) 2577b59b132SShreeya Patel return false; 2587b59b132SShreeya Patel 2597b59b132SShreeya Patel return true; 2607b59b132SShreeya Patel } 2617b59b132SShreeya Patel 2627b59b132SShreeya Patel static void hdmirx_get_timings(struct snps_hdmirx_dev *hdmirx_dev, 2637b59b132SShreeya Patel struct v4l2_bt_timings *bt) 2647b59b132SShreeya Patel { 2657b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 2667b59b132SShreeya Patel u32 hact, vact, htotal, vtotal, fps; 2677b59b132SShreeya Patel u32 hfp, hs, hbp, vfp, vs, vbp; 2687b59b132SShreeya Patel u32 val; 2697b59b132SShreeya Patel 2707b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, DMA_STATUS2); 2717b59b132SShreeya Patel hact = (val >> 16) & 0xffff; 2727b59b132SShreeya Patel vact = val & 0xffff; 2737b59b132SShreeya Patel 2747b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, DMA_STATUS3); 2757b59b132SShreeya Patel htotal = (val >> 16) & 0xffff; 2767b59b132SShreeya Patel vtotal = val & 0xffff; 2777b59b132SShreeya Patel 2787b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, DMA_STATUS4); 2797b59b132SShreeya Patel hs = (val >> 16) & 0xffff; 2807b59b132SShreeya Patel vs = val & 0xffff; 2817b59b132SShreeya Patel 2827b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, DMA_STATUS5); 2837b59b132SShreeya Patel hbp = (val >> 16) & 0xffff; 2847b59b132SShreeya Patel vbp = val & 0xffff; 2857b59b132SShreeya Patel 2867b59b132SShreeya Patel if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) { 2877b59b132SShreeya Patel htotal *= 2; 2887b59b132SShreeya Patel hbp *= 2; 2897b59b132SShreeya Patel hs *= 2; 2907b59b132SShreeya Patel } 2917b59b132SShreeya Patel 2927b59b132SShreeya Patel hfp = htotal - hact - hs - hbp; 2937b59b132SShreeya Patel vfp = vtotal - vact - vs - vbp; 2947b59b132SShreeya Patel 295fae8cab4SNathan Chancellor fps = div_u64(bt->pixelclock + (htotal * vtotal) / 2, htotal * vtotal); 2967b59b132SShreeya Patel bt->width = hact; 2977b59b132SShreeya Patel bt->height = vact; 2987b59b132SShreeya Patel bt->hfrontporch = hfp; 2997b59b132SShreeya Patel bt->hsync = hs; 3007b59b132SShreeya Patel bt->hbackporch = hbp; 3017b59b132SShreeya Patel bt->vfrontporch = vfp; 3027b59b132SShreeya Patel bt->vsync = vs; 3037b59b132SShreeya Patel bt->vbackporch = vbp; 3047b59b132SShreeya Patel 3057b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "get timings from dma\n"); 3067b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 3077b59b132SShreeya Patel "act:%ux%u%s, total:%ux%u, fps:%u, pixclk:%llu\n", 3087b59b132SShreeya Patel bt->width, bt->height, bt->interlaced ? "i" : "p", 3097b59b132SShreeya Patel htotal, vtotal, fps, bt->pixelclock); 3107b59b132SShreeya Patel 3117b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, 3127b59b132SShreeya Patel "hfp:%u, hact:%u, hs:%u, hbp:%u, vfp:%u, vact:%u, vs:%u, vbp:%u\n", 3137b59b132SShreeya Patel bt->hfrontporch, hact, bt->hsync, bt->hbackporch, 3147b59b132SShreeya Patel bt->vfrontporch, vact, bt->vsync, bt->vbackporch); 3157b59b132SShreeya Patel 3167b59b132SShreeya Patel if (bt->interlaced == V4L2_DV_INTERLACED) { 3177b59b132SShreeya Patel bt->height *= 2; 3187b59b132SShreeya Patel bt->il_vfrontporch = bt->vfrontporch; 3197b59b132SShreeya Patel bt->il_vsync = bt->vsync + 1; 3207b59b132SShreeya Patel bt->il_vbackporch = bt->vbackporch; 3217b59b132SShreeya Patel } 3227b59b132SShreeya Patel } 3237b59b132SShreeya Patel 3247b59b132SShreeya Patel static bool hdmirx_check_timing_valid(struct v4l2_bt_timings *bt) 3257b59b132SShreeya Patel { 3267b59b132SShreeya Patel /* 3277b59b132SShreeya Patel * Sanity-check timing values. Some of the values will be outside 3287b59b132SShreeya Patel * of a valid range till hardware becomes ready to perform capture. 3297b59b132SShreeya Patel */ 3307b59b132SShreeya Patel if (bt->width < 100 || bt->width > 5000 || 3317b59b132SShreeya Patel bt->height < 100 || bt->height > 5000) 3327b59b132SShreeya Patel return false; 3337b59b132SShreeya Patel 3347b59b132SShreeya Patel if (!bt->hsync || bt->hsync > 200 || 3357b59b132SShreeya Patel !bt->vsync || bt->vsync > 100) 3367b59b132SShreeya Patel return false; 3377b59b132SShreeya Patel 3387b59b132SShreeya Patel /* 3397b59b132SShreeya Patel * According to the CEA-861, 1280x720p25 Hblank timing is up to 2680, 3407b59b132SShreeya Patel * and all standard video format timings are less than 3000. 3417b59b132SShreeya Patel */ 3427b59b132SShreeya Patel if (!bt->hbackporch || bt->hbackporch > 3000 || 3437b59b132SShreeya Patel !bt->vbackporch || bt->vbackporch > 3000) 3447b59b132SShreeya Patel return false; 3457b59b132SShreeya Patel 3467b59b132SShreeya Patel if (!bt->hfrontporch || bt->hfrontporch > 3000 || 3477b59b132SShreeya Patel !bt->vfrontporch || bt->vfrontporch > 3000) 3487b59b132SShreeya Patel return false; 3497b59b132SShreeya Patel 3507b59b132SShreeya Patel return true; 3517b59b132SShreeya Patel } 3527b59b132SShreeya Patel 3537b59b132SShreeya Patel static void hdmirx_toggle_polarity(struct snps_hdmirx_dev *hdmirx_dev) 3547b59b132SShreeya Patel { 3557b59b132SShreeya Patel u32 val = hdmirx_readl(hdmirx_dev, DMA_CONFIG6); 3567b59b132SShreeya Patel 3577b59b132SShreeya Patel if (!(val & (VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN))) { 3587b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, 3597b59b132SShreeya Patel VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN, 3607b59b132SShreeya Patel VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN); 3617b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, VIDEO_CONFIG2, 3627b59b132SShreeya Patel VPROC_VSYNC_POL_OVR_VALUE | 3637b59b132SShreeya Patel VPROC_VSYNC_POL_OVR_EN | 3647b59b132SShreeya Patel VPROC_HSYNC_POL_OVR_VALUE | 3657b59b132SShreeya Patel VPROC_HSYNC_POL_OVR_EN, 3667b59b132SShreeya Patel VPROC_VSYNC_POL_OVR_EN | 3677b59b132SShreeya Patel VPROC_HSYNC_POL_OVR_EN); 3687b59b132SShreeya Patel return; 3697b59b132SShreeya Patel } 3707b59b132SShreeya Patel 3717b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, 3727b59b132SShreeya Patel VSYNC_TOGGLE_EN | HSYNC_TOGGLE_EN, 0); 3737b59b132SShreeya Patel 3747b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, VIDEO_CONFIG2, 3757b59b132SShreeya Patel VPROC_VSYNC_POL_OVR_VALUE | 3767b59b132SShreeya Patel VPROC_VSYNC_POL_OVR_EN | 3777b59b132SShreeya Patel VPROC_HSYNC_POL_OVR_VALUE | 3787b59b132SShreeya Patel VPROC_HSYNC_POL_OVR_EN, 0); 3797b59b132SShreeya Patel } 3807b59b132SShreeya Patel 3817b59b132SShreeya Patel /* 3827b59b132SShreeya Patel * When querying DV timings during preview, if the DMA's timing is stable, 3837b59b132SShreeya Patel * we retrieve the timings directly from the DMA. However, if the current 3847b59b132SShreeya Patel * resolution is negative, obtaining the timing from CTRL may require a 3857b59b132SShreeya Patel * change in the sync polarity, potentially leading to DMA errors. 3867b59b132SShreeya Patel */ 3877b59b132SShreeya Patel static int hdmirx_get_detected_timings(struct snps_hdmirx_dev *hdmirx_dev, 3887b59b132SShreeya Patel struct v4l2_dv_timings *timings) 3897b59b132SShreeya Patel { 3907b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 3917b59b132SShreeya Patel struct v4l2_bt_timings *bt = &timings->bt; 3927b59b132SShreeya Patel u32 val, tmdsqpclk_freq, pix_clk; 3937b59b132SShreeya Patel unsigned int num_retries = 0; 3947b59b132SShreeya Patel u32 field_type, deframer_st; 3957b59b132SShreeya Patel u64 tmp_data, tmds_clk; 3967b59b132SShreeya Patel bool is_dvi_mode; 3977b59b132SShreeya Patel int ret; 3987b59b132SShreeya Patel 3997b59b132SShreeya Patel mutex_lock(&hdmirx_dev->work_lock); 4007b59b132SShreeya Patel retry: 4017b59b132SShreeya Patel memset(timings, 0, sizeof(struct v4l2_dv_timings)); 4027b59b132SShreeya Patel timings->type = V4L2_DV_BT_656_1120; 4037b59b132SShreeya Patel 4047b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); 4057b59b132SShreeya Patel field_type = (val & HDMIRX_TYPE_MASK) >> 7; 4067b59b132SShreeya Patel 4077b59b132SShreeya Patel if (field_type & BIT(0)) 4087b59b132SShreeya Patel bt->interlaced = V4L2_DV_INTERLACED; 4097b59b132SShreeya Patel else 4107b59b132SShreeya Patel bt->interlaced = V4L2_DV_PROGRESSIVE; 4117b59b132SShreeya Patel 4127b59b132SShreeya Patel deframer_st = hdmirx_readl(hdmirx_dev, DEFRAMER_STATUS); 4137b59b132SShreeya Patel is_dvi_mode = !(deframer_st & OPMODE_STS_MASK); 4147b59b132SShreeya Patel 4157b59b132SShreeya Patel tmdsqpclk_freq = hdmirx_readl(hdmirx_dev, CMU_TMDSQPCLK_FREQ); 4167b59b132SShreeya Patel tmds_clk = tmdsqpclk_freq * 4 * 1000; 4177b59b132SShreeya Patel tmp_data = tmds_clk * 24; 4187b59b132SShreeya Patel do_div(tmp_data, hdmirx_dev->color_depth); 4197b59b132SShreeya Patel pix_clk = tmp_data; 4207b59b132SShreeya Patel bt->pixelclock = pix_clk; 4217b59b132SShreeya Patel 4227b59b132SShreeya Patel if (hdmirx_dev->pix_fmt == HDMIRX_YUV420) 4237b59b132SShreeya Patel bt->pixelclock *= 2; 4247b59b132SShreeya Patel 4257b59b132SShreeya Patel hdmirx_get_timings(hdmirx_dev, bt); 4267b59b132SShreeya Patel 4277b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "tmds_clk:%llu, pix_clk:%d\n", tmds_clk, pix_clk); 4287b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "interlace:%d, fmt:%d, color:%d, mode:%s\n", 4297b59b132SShreeya Patel bt->interlaced, hdmirx_dev->pix_fmt, 4307b59b132SShreeya Patel hdmirx_dev->color_depth, 4317b59b132SShreeya Patel is_dvi_mode ? "dvi" : "hdmi"); 4327b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "deframer_st:%#x\n", deframer_st); 4337b59b132SShreeya Patel 4347b59b132SShreeya Patel /* 4357b59b132SShreeya Patel * Timing will be invalid until it's latched by HW or if signal's 4367b59b132SShreeya Patel * polarity doesn't match. 4377b59b132SShreeya Patel */ 4387b59b132SShreeya Patel if (!hdmirx_check_timing_valid(bt)) { 4397b59b132SShreeya Patel if (num_retries++ < 20) { 4407b59b132SShreeya Patel if (num_retries == 10) 4417b59b132SShreeya Patel hdmirx_toggle_polarity(hdmirx_dev); 4427b59b132SShreeya Patel 4437b59b132SShreeya Patel usleep_range(10 * 1000, 10 * 1100); 4447b59b132SShreeya Patel goto retry; 4457b59b132SShreeya Patel } 4467b59b132SShreeya Patel 4477b59b132SShreeya Patel ret = -ERANGE; 4487b59b132SShreeya Patel } else { 4497b59b132SShreeya Patel ret = 0; 4507b59b132SShreeya Patel } 4517b59b132SShreeya Patel 4527b59b132SShreeya Patel mutex_unlock(&hdmirx_dev->work_lock); 4537b59b132SShreeya Patel 4547b59b132SShreeya Patel return ret; 4557b59b132SShreeya Patel } 4567b59b132SShreeya Patel 4577b59b132SShreeya Patel static bool port_no_link(struct snps_hdmirx_dev *hdmirx_dev) 4587b59b132SShreeya Patel { 4597b59b132SShreeya Patel return !tx_5v_power_present(hdmirx_dev); 4607b59b132SShreeya Patel } 4617b59b132SShreeya Patel 4627b59b132SShreeya Patel static int hdmirx_query_dv_timings(struct file *file, void *_fh, 4637b59b132SShreeya Patel struct v4l2_dv_timings *timings) 4647b59b132SShreeya Patel { 4657b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 4667b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 4677b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 4687b59b132SShreeya Patel int ret; 4697b59b132SShreeya Patel 4707b59b132SShreeya Patel if (port_no_link(hdmirx_dev)) { 4717b59b132SShreeya Patel v4l2_err(v4l2_dev, "%s: port has no link\n", __func__); 4727b59b132SShreeya Patel return -ENOLINK; 4737b59b132SShreeya Patel } 4747b59b132SShreeya Patel 4757b59b132SShreeya Patel if (signal_not_lock(hdmirx_dev)) { 4767b59b132SShreeya Patel v4l2_err(v4l2_dev, "%s: signal is not locked\n", __func__); 4777b59b132SShreeya Patel return -ENOLCK; 4787b59b132SShreeya Patel } 4797b59b132SShreeya Patel 4807b59b132SShreeya Patel ret = hdmirx_get_detected_timings(hdmirx_dev, timings); 4817b59b132SShreeya Patel if (ret) 4827b59b132SShreeya Patel return ret; 4837b59b132SShreeya Patel 4847b59b132SShreeya Patel if (debug) 4857b59b132SShreeya Patel v4l2_print_dv_timings(hdmirx_dev->v4l2_dev.name, 4867b59b132SShreeya Patel "query_dv_timings: ", timings, false); 4877b59b132SShreeya Patel 4887b59b132SShreeya Patel if (!v4l2_valid_dv_timings(timings, &hdmirx_timings_cap, NULL, NULL)) { 4897b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: timings out of range\n", __func__); 4907b59b132SShreeya Patel return -ERANGE; 4917b59b132SShreeya Patel } 4927b59b132SShreeya Patel 4937b59b132SShreeya Patel return 0; 4947b59b132SShreeya Patel } 4957b59b132SShreeya Patel 4967b59b132SShreeya Patel static void hdmirx_hpd_ctrl(struct snps_hdmirx_dev *hdmirx_dev, bool en) 4977b59b132SShreeya Patel { 4987b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 4997b59b132SShreeya Patel 5007b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: %sable, hpd_trigger_level_high:%d\n", 5017b59b132SShreeya Patel __func__, en ? "en" : "dis", hdmirx_dev->hpd_trigger_level_high); 5027b59b132SShreeya Patel 5037b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, HPDLOW, en ? 0 : HPDLOW); 5047b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, CORE_CONFIG, 5057b59b132SShreeya Patel hdmirx_dev->hpd_trigger_level_high ? en : !en); 5067b59b132SShreeya Patel 5077b59b132SShreeya Patel /* 100ms delay as per HDMI spec */ 5087b59b132SShreeya Patel if (!en) 5097b59b132SShreeya Patel msleep(100); 5107b59b132SShreeya Patel } 5117b59b132SShreeya Patel 5127b59b132SShreeya Patel static void hdmirx_write_edid_data(struct snps_hdmirx_dev *hdmirx_dev, 5137b59b132SShreeya Patel u8 *edid, unsigned int num_blocks) 5147b59b132SShreeya Patel { 5157b59b132SShreeya Patel static u8 data[EDID_NUM_BLOCKS_MAX * EDID_BLOCK_SIZE]; 5167b59b132SShreeya Patel unsigned int edid_len = num_blocks * EDID_BLOCK_SIZE; 5177b59b132SShreeya Patel unsigned int i; 5187b59b132SShreeya Patel 5197b59b132SShreeya Patel cec_s_phys_addr_from_edid(hdmirx_dev->cec->adap, 5207b59b132SShreeya Patel (const struct edid *)edid); 5217b59b132SShreeya Patel 5227b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, 5237b59b132SShreeya Patel EDID_READ_EN_MASK | 5247b59b132SShreeya Patel EDID_WRITE_EN_MASK | 5257b59b132SShreeya Patel EDID_SLAVE_ADDR_MASK, 5267b59b132SShreeya Patel EDID_READ_EN(0) | 5277b59b132SShreeya Patel EDID_WRITE_EN(1) | 5287b59b132SShreeya Patel EDID_SLAVE_ADDR(0x50)); 5297b59b132SShreeya Patel for (i = 0; i < edid_len; i++) 5307b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG10, edid[i]); 5317b59b132SShreeya Patel 5327b59b132SShreeya Patel /* read out for debug */ 5337b59b132SShreeya Patel if (debug >= 2) { 5347b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, 5357b59b132SShreeya Patel EDID_READ_EN_MASK | 5367b59b132SShreeya Patel EDID_WRITE_EN_MASK, 5377b59b132SShreeya Patel EDID_READ_EN(1) | 5387b59b132SShreeya Patel EDID_WRITE_EN(0)); 5397b59b132SShreeya Patel 5407b59b132SShreeya Patel for (i = 0; i < edid_len; i++) 5417b59b132SShreeya Patel data[i] = hdmirx_readl(hdmirx_dev, DMA_STATUS14); 5427b59b132SShreeya Patel 5437b59b132SShreeya Patel print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, data, 5447b59b132SShreeya Patel edid_len, false); 5457b59b132SShreeya Patel } 5467b59b132SShreeya Patel 5477b59b132SShreeya Patel /* 5487b59b132SShreeya Patel * Must set EDID_READ_EN & EDID_WRITE_EN bit to 0, 5497b59b132SShreeya Patel * when the read/write edid operation is completed. Otherwise, it 5507b59b132SShreeya Patel * will affect the reading and writing of other registers. 5517b59b132SShreeya Patel */ 5527b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG11, 5537b59b132SShreeya Patel EDID_READ_EN_MASK | EDID_WRITE_EN_MASK, 5547b59b132SShreeya Patel EDID_READ_EN(0) | EDID_WRITE_EN(0)); 5557b59b132SShreeya Patel } 5567b59b132SShreeya Patel 5577b59b132SShreeya Patel static void hdmirx_write_edid(struct snps_hdmirx_dev *hdmirx_dev, 5587b59b132SShreeya Patel struct v4l2_edid *edid) 5597b59b132SShreeya Patel { 5607b59b132SShreeya Patel memset(edid->reserved, 0, sizeof(edid->reserved)); 5617b59b132SShreeya Patel memset(hdmirx_dev->edid, 0, sizeof(hdmirx_dev->edid)); 5627b59b132SShreeya Patel 5637b59b132SShreeya Patel hdmirx_write_edid_data(hdmirx_dev, edid->edid, edid->blocks); 5647b59b132SShreeya Patel 5657b59b132SShreeya Patel hdmirx_dev->edid_blocks_written = edid->blocks; 5667b59b132SShreeya Patel memcpy(hdmirx_dev->edid, edid->edid, edid->blocks * EDID_BLOCK_SIZE); 5677b59b132SShreeya Patel } 5687b59b132SShreeya Patel 5697b59b132SShreeya Patel /* 5707b59b132SShreeya Patel * Before clearing interrupt, we need to read the interrupt status. 5717b59b132SShreeya Patel */ 5727b59b132SShreeya Patel static inline void hdmirx_clear_interrupt(struct snps_hdmirx_dev *hdmirx_dev, 5737b59b132SShreeya Patel u32 reg, u32 val) 5747b59b132SShreeya Patel { 5757b59b132SShreeya Patel /* (interrupt status register) = (interrupt clear register) - 0x8 */ 5767b59b132SShreeya Patel hdmirx_readl(hdmirx_dev, reg - 0x8); 5777b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, reg, val); 5787b59b132SShreeya Patel } 5797b59b132SShreeya Patel 5807b59b132SShreeya Patel static void hdmirx_interrupts_setup(struct snps_hdmirx_dev *hdmirx_dev, bool en) 5817b59b132SShreeya Patel { 5827b59b132SShreeya Patel v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: %sable\n", 5837b59b132SShreeya Patel __func__, en ? "en" : "dis"); 5847b59b132SShreeya Patel 5857b59b132SShreeya Patel disable_irq(hdmirx_dev->hdmi_irq); 5867b59b132SShreeya Patel 5877b59b132SShreeya Patel /* Note: In DVI mode, it needs to be written twice to take effect. */ 5887b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); 5897b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); 5907b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); 5917b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); 5927b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); 5937b59b132SShreeya Patel 5947b59b132SShreeya Patel if (en) { 5957b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 5967b59b132SShreeya Patel TMDSQPCLK_OFF_CHG | TMDSQPCLK_LOCKED_CHG, 5977b59b132SShreeya Patel TMDSQPCLK_OFF_CHG | TMDSQPCLK_LOCKED_CHG); 5987b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 5997b59b132SShreeya Patel TMDSVALID_STABLE_CHG, TMDSVALID_STABLE_CHG); 6007b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, AVPUNIT_0_INT_MASK_N, 6017b59b132SShreeya Patel CED_DYN_CNT_CH2_IRQ | 6027b59b132SShreeya Patel CED_DYN_CNT_CH1_IRQ | 6037b59b132SShreeya Patel CED_DYN_CNT_CH0_IRQ, 6047b59b132SShreeya Patel CED_DYN_CNT_CH2_IRQ | 6057b59b132SShreeya Patel CED_DYN_CNT_CH1_IRQ | 6067b59b132SShreeya Patel CED_DYN_CNT_CH0_IRQ); 6077b59b132SShreeya Patel } else { 6087b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 0); 6097b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 0); 6107b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_MASK_N, 0); 6117b59b132SShreeya Patel } 6127b59b132SShreeya Patel 6137b59b132SShreeya Patel enable_irq(hdmirx_dev->hdmi_irq); 6147b59b132SShreeya Patel } 6157b59b132SShreeya Patel 6167b59b132SShreeya Patel static void hdmirx_plugout(struct snps_hdmirx_dev *hdmirx_dev) 6177b59b132SShreeya Patel { 6187b59b132SShreeya Patel if (!hdmirx_dev->plugged) 6197b59b132SShreeya Patel return; 6207b59b132SShreeya Patel 6217b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 0); 6227b59b132SShreeya Patel hdmirx_interrupts_setup(hdmirx_dev, false); 6237b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); 6247b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, 6257b59b132SShreeya Patel LINE_FLAG_INT_EN | 6267b59b132SShreeya Patel HDMIRX_DMA_IDLE_INT | 6277b59b132SShreeya Patel HDMIRX_LOCK_DISABLE_INT | 6287b59b132SShreeya Patel LAST_FRAME_AXI_UNFINISH_INT_EN | 6297b59b132SShreeya Patel FIFO_OVERFLOW_INT_EN | 6307b59b132SShreeya Patel FIFO_UNDERFLOW_INT_EN | 6317b59b132SShreeya Patel HDMIRX_AXI_ERROR_INT_EN, 0); 6327b59b132SShreeya Patel hdmirx_reset_dma(hdmirx_dev); 6337b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, HDMI_DISABLE | PHY_RESET | 6347b59b132SShreeya Patel PHY_PDDQ, HDMI_DISABLE); 6357b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG0, 0x0); 6367b59b132SShreeya Patel cancel_delayed_work(&hdmirx_dev->delayed_work_res_change); 6377b59b132SShreeya Patel 6387b59b132SShreeya Patel /* will be NULL on driver removal */ 6397b59b132SShreeya Patel if (hdmirx_dev->rgb_range) 6407b59b132SShreeya Patel v4l2_ctrl_s_ctrl(hdmirx_dev->rgb_range, V4L2_DV_RGB_RANGE_AUTO); 6417b59b132SShreeya Patel 6427b59b132SShreeya Patel if (hdmirx_dev->content_type) 6437b59b132SShreeya Patel v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, 6447b59b132SShreeya Patel V4L2_DV_IT_CONTENT_TYPE_NO_ITC); 6457b59b132SShreeya Patel 6467b59b132SShreeya Patel hdmirx_dev->plugged = false; 6477b59b132SShreeya Patel } 6487b59b132SShreeya Patel 6497b59b132SShreeya Patel static int hdmirx_set_edid(struct file *file, void *fh, struct v4l2_edid *edid) 6507b59b132SShreeya Patel { 6517b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 6527b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 6537b59b132SShreeya Patel u16 phys_addr; 6547b59b132SShreeya Patel int err; 6557b59b132SShreeya Patel 6567b59b132SShreeya Patel if (edid->pad) 6577b59b132SShreeya Patel return -EINVAL; 6587b59b132SShreeya Patel 6597b59b132SShreeya Patel if (edid->start_block) 6607b59b132SShreeya Patel return -EINVAL; 6617b59b132SShreeya Patel 6627b59b132SShreeya Patel if (edid->blocks > EDID_NUM_BLOCKS_MAX) { 6637b59b132SShreeya Patel edid->blocks = EDID_NUM_BLOCKS_MAX; 6647b59b132SShreeya Patel return -E2BIG; 6657b59b132SShreeya Patel } 6667b59b132SShreeya Patel 6677b59b132SShreeya Patel if (edid->blocks) { 6687b59b132SShreeya Patel phys_addr = cec_get_edid_phys_addr(edid->edid, 6697b59b132SShreeya Patel edid->blocks * EDID_BLOCK_SIZE, 6707b59b132SShreeya Patel NULL); 6717b59b132SShreeya Patel 6727b59b132SShreeya Patel err = v4l2_phys_addr_validate(phys_addr, &phys_addr, NULL); 6737b59b132SShreeya Patel if (err) 6747b59b132SShreeya Patel return err; 6757b59b132SShreeya Patel } 6767b59b132SShreeya Patel 6777b59b132SShreeya Patel /* 6787b59b132SShreeya Patel * Touching HW registers in parallel with plugin/out handlers 6797b59b132SShreeya Patel * will bring hardware into a bad state. 6807b59b132SShreeya Patel */ 6817b59b132SShreeya Patel mutex_lock(&hdmirx_dev->work_lock); 6827b59b132SShreeya Patel 6837b59b132SShreeya Patel hdmirx_hpd_ctrl(hdmirx_dev, false); 6847b59b132SShreeya Patel 6857b59b132SShreeya Patel if (edid->blocks) { 6867b59b132SShreeya Patel hdmirx_write_edid(hdmirx_dev, edid); 6877b59b132SShreeya Patel hdmirx_hpd_ctrl(hdmirx_dev, true); 6887b59b132SShreeya Patel } else { 6897b59b132SShreeya Patel cec_phys_addr_invalidate(hdmirx_dev->cec->adap); 6907b59b132SShreeya Patel hdmirx_dev->edid_blocks_written = 0; 6917b59b132SShreeya Patel } 6927b59b132SShreeya Patel 6937b59b132SShreeya Patel mutex_unlock(&hdmirx_dev->work_lock); 6947b59b132SShreeya Patel 6957b59b132SShreeya Patel return 0; 6967b59b132SShreeya Patel } 6977b59b132SShreeya Patel 6987b59b132SShreeya Patel static int hdmirx_get_edid(struct file *file, void *fh, struct v4l2_edid *edid) 6997b59b132SShreeya Patel { 7007b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 7017b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 7027b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 7037b59b132SShreeya Patel 7047b59b132SShreeya Patel memset(edid->reserved, 0, sizeof(edid->reserved)); 7057b59b132SShreeya Patel 7067b59b132SShreeya Patel if (edid->pad) 7077b59b132SShreeya Patel return -EINVAL; 7087b59b132SShreeya Patel 7097b59b132SShreeya Patel if (!edid->start_block && !edid->blocks) { 7107b59b132SShreeya Patel edid->blocks = hdmirx_dev->edid_blocks_written; 7117b59b132SShreeya Patel return 0; 7127b59b132SShreeya Patel } 7137b59b132SShreeya Patel 7147b59b132SShreeya Patel if (!hdmirx_dev->edid_blocks_written) 7157b59b132SShreeya Patel return -ENODATA; 7167b59b132SShreeya Patel 7177b59b132SShreeya Patel if (edid->start_block >= hdmirx_dev->edid_blocks_written || !edid->blocks) 7187b59b132SShreeya Patel return -EINVAL; 7197b59b132SShreeya Patel 7207b59b132SShreeya Patel if (edid->start_block + edid->blocks > hdmirx_dev->edid_blocks_written) 7217b59b132SShreeya Patel edid->blocks = hdmirx_dev->edid_blocks_written - edid->start_block; 7227b59b132SShreeya Patel 7237b59b132SShreeya Patel memcpy(edid->edid, hdmirx_dev->edid, edid->blocks * EDID_BLOCK_SIZE); 7247b59b132SShreeya Patel 7257b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: read EDID:\n", __func__); 7267b59b132SShreeya Patel if (debug > 0) 7277b59b132SShreeya Patel print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, 7287b59b132SShreeya Patel edid->edid, edid->blocks * EDID_BLOCK_SIZE, false); 7297b59b132SShreeya Patel 7307b59b132SShreeya Patel return 0; 7317b59b132SShreeya Patel } 7327b59b132SShreeya Patel 7337b59b132SShreeya Patel static int hdmirx_g_parm(struct file *file, void *priv, 7347b59b132SShreeya Patel struct v4l2_streamparm *parm) 7357b59b132SShreeya Patel { 7367b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 7377b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 7387b59b132SShreeya Patel 7397b59b132SShreeya Patel if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 7407b59b132SShreeya Patel return -EINVAL; 7417b59b132SShreeya Patel 7427b59b132SShreeya Patel parm->parm.capture.timeperframe = v4l2_calc_timeperframe(&hdmirx_dev->timings); 7437b59b132SShreeya Patel 7447b59b132SShreeya Patel return 0; 7457b59b132SShreeya Patel } 7467b59b132SShreeya Patel 7477b59b132SShreeya Patel static int hdmirx_dv_timings_cap(struct file *file, void *fh, 7487b59b132SShreeya Patel struct v4l2_dv_timings_cap *cap) 7497b59b132SShreeya Patel { 7507b59b132SShreeya Patel *cap = hdmirx_timings_cap; 7517b59b132SShreeya Patel return 0; 7527b59b132SShreeya Patel } 7537b59b132SShreeya Patel 7547b59b132SShreeya Patel static int hdmirx_enum_dv_timings(struct file *file, void *_fh, 7557b59b132SShreeya Patel struct v4l2_enum_dv_timings *timings) 7567b59b132SShreeya Patel { 7577b59b132SShreeya Patel return v4l2_enum_dv_timings_cap(timings, &hdmirx_timings_cap, NULL, NULL); 7587b59b132SShreeya Patel } 7597b59b132SShreeya Patel 7607b59b132SShreeya Patel static void hdmirx_scdc_init(struct snps_hdmirx_dev *hdmirx_dev) 7617b59b132SShreeya Patel { 7627b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, I2C_SLAVE_CONFIG1, 7637b59b132SShreeya Patel I2C_SDA_OUT_HOLD_VALUE_QST_MASK | 7647b59b132SShreeya Patel I2C_SDA_IN_HOLD_VALUE_QST_MASK, 7657b59b132SShreeya Patel I2C_SDA_OUT_HOLD_VALUE_QST(0x80) | 7667b59b132SShreeya Patel I2C_SDA_IN_HOLD_VALUE_QST(0x15)); 7677b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, SCDC_REGBANK_CONFIG0, 7687b59b132SShreeya Patel SCDC_SINKVERSION_QST_MASK, 7697b59b132SShreeya Patel SCDC_SINKVERSION_QST(1)); 7707b59b132SShreeya Patel } 7717b59b132SShreeya Patel 7727b59b132SShreeya Patel static int wait_reg_bit_status(struct snps_hdmirx_dev *hdmirx_dev, u32 reg, 7737b59b132SShreeya Patel u32 bit_mask, u32 expect_val, bool is_grf, 7747b59b132SShreeya Patel u32 ms) 7757b59b132SShreeya Patel { 7767b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 7777b59b132SShreeya Patel u32 i, val; 7787b59b132SShreeya Patel 7797b59b132SShreeya Patel for (i = 0; i < ms; i++) { 7807b59b132SShreeya Patel if (is_grf) 7817b59b132SShreeya Patel regmap_read(hdmirx_dev->grf, reg, &val); 7827b59b132SShreeya Patel else 7837b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, reg); 7847b59b132SShreeya Patel 7857b59b132SShreeya Patel if ((val & bit_mask) == expect_val) { 7867b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, 7877b59b132SShreeya Patel "%s: i:%d, time: %dms\n", __func__, i, ms); 7887b59b132SShreeya Patel break; 7897b59b132SShreeya Patel } 7907b59b132SShreeya Patel usleep_range(1000, 1010); 7917b59b132SShreeya Patel } 7927b59b132SShreeya Patel 7937b59b132SShreeya Patel if (i == ms) 7947b59b132SShreeya Patel return -1; 7957b59b132SShreeya Patel 7967b59b132SShreeya Patel return 0; 7977b59b132SShreeya Patel } 7987b59b132SShreeya Patel 7997b59b132SShreeya Patel static int hdmirx_phy_register_write(struct snps_hdmirx_dev *hdmirx_dev, 8007b59b132SShreeya Patel u32 phy_reg, u32 val) 8017b59b132SShreeya Patel { 8027b59b132SShreeya Patel struct device *dev = hdmirx_dev->dev; 8037b59b132SShreeya Patel 8047b59b132SShreeya Patel reinit_completion(&hdmirx_dev->cr_write_done); 8057b59b132SShreeya Patel /* clear irq status */ 8067b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); 8077b59b132SShreeya Patel /* en irq */ 8087b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 8097b59b132SShreeya Patel PHYCREG_CR_WRITE_DONE, PHYCREG_CR_WRITE_DONE); 8107b59b132SShreeya Patel /* write phy reg addr */ 8117b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG1, phy_reg); 8127b59b132SShreeya Patel /* write phy reg val */ 8137b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG2, val); 8147b59b132SShreeya Patel /* config write enable */ 8157b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PHYCREG_CONTROL, PHYCREG_CR_PARA_WRITE_P); 8167b59b132SShreeya Patel 8177b59b132SShreeya Patel if (!wait_for_completion_timeout(&hdmirx_dev->cr_write_done, 8187b59b132SShreeya Patel msecs_to_jiffies(20))) { 8197b59b132SShreeya Patel dev_err(dev, "%s wait cr write done failed\n", __func__); 8207b59b132SShreeya Patel return -1; 8217b59b132SShreeya Patel } 8227b59b132SShreeya Patel 8237b59b132SShreeya Patel return 0; 8247b59b132SShreeya Patel } 8257b59b132SShreeya Patel 8267b59b132SShreeya Patel static void hdmirx_tmds_clk_ratio_config(struct snps_hdmirx_dev *hdmirx_dev) 8277b59b132SShreeya Patel { 8287b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 8297b59b132SShreeya Patel u32 val; 8307b59b132SShreeya Patel 8317b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, SCDC_REGBANK_STATUS1); 8327b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, "%s: scdc_regbank_st:%#x\n", __func__, val); 8337b59b132SShreeya Patel hdmirx_dev->tmds_clk_ratio = (val & SCDC_TMDSBITCLKRATIO) > 0; 8347b59b132SShreeya Patel 8357b59b132SShreeya Patel if (hdmirx_dev->tmds_clk_ratio) { 8367b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, "%s: HDMITX greater than 3.4Gbps\n", __func__); 8377b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, 8387b59b132SShreeya Patel TMDS_CLOCK_RATIO, TMDS_CLOCK_RATIO); 8397b59b132SShreeya Patel } else { 8407b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, "%s: HDMITX less than 3.4Gbps\n", __func__); 8417b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, 8427b59b132SShreeya Patel TMDS_CLOCK_RATIO, 0); 8437b59b132SShreeya Patel } 8447b59b132SShreeya Patel } 8457b59b132SShreeya Patel 8467b59b132SShreeya Patel static void hdmirx_phy_config(struct snps_hdmirx_dev *hdmirx_dev) 8477b59b132SShreeya Patel { 8487b59b132SShreeya Patel struct device *dev = hdmirx_dev->dev; 8497b59b132SShreeya Patel 8507b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); 8517b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, SCDC_INT_MASK_N, SCDCTMDSCCFG_CHG, 8527b59b132SShreeya Patel SCDCTMDSCCFG_CHG); 8537b59b132SShreeya Patel /* cr_para_clk 24M */ 8547b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, REFFREQ_SEL_MASK, REFFREQ_SEL(0)); 8557b59b132SShreeya Patel /* rx data width 40bit valid */ 8567b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, RXDATA_WIDTH, RXDATA_WIDTH); 8577b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET, PHY_RESET); 8587b59b132SShreeya Patel usleep_range(100, 110); 8597b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET, 0); 8607b59b132SShreeya Patel usleep_range(100, 110); 8617b59b132SShreeya Patel /* select cr para interface */ 8627b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PHYCREG_CONFIG0, 0x3); 8637b59b132SShreeya Patel 8647b59b132SShreeya Patel if (wait_reg_bit_status(hdmirx_dev, SYS_GRF_SOC_STATUS1, 8657b59b132SShreeya Patel HDMIRXPHY_SRAM_INIT_DONE, 8667b59b132SShreeya Patel HDMIRXPHY_SRAM_INIT_DONE, true, 10)) 8677b59b132SShreeya Patel dev_err(dev, "%s: phy SRAM init failed\n", __func__); 8687b59b132SShreeya Patel 8697b59b132SShreeya Patel regmap_write(hdmirx_dev->grf, SYS_GRF_SOC_CON1, 8707b59b132SShreeya Patel (HDMIRXPHY_SRAM_EXT_LD_DONE << 16) | 8717b59b132SShreeya Patel HDMIRXPHY_SRAM_EXT_LD_DONE); 8727b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); 8737b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 3); 8747b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); 8757b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); 8767b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 3); 8777b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 2); 8787b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); 8797b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 1); 8807b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); 8817b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, SUP_DIG_ANA_CREGS_SUP_ANA_NC, 0); 8827b59b132SShreeya Patel 8837b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, 8847b59b132SShreeya Patel HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_3_REG, 8857b59b132SShreeya Patel CDR_SETTING_BOUNDARY_3_DEFAULT); 8867b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, 8877b59b132SShreeya Patel HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_4_REG, 8887b59b132SShreeya Patel CDR_SETTING_BOUNDARY_4_DEFAULT); 8897b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, 8907b59b132SShreeya Patel HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_5_REG, 8917b59b132SShreeya Patel CDR_SETTING_BOUNDARY_5_DEFAULT); 8927b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, 8937b59b132SShreeya Patel HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_6_REG, 8947b59b132SShreeya Patel CDR_SETTING_BOUNDARY_6_DEFAULT); 8957b59b132SShreeya Patel hdmirx_phy_register_write(hdmirx_dev, 8967b59b132SShreeya Patel HDMIPCS_DIG_CTRL_PATH_MAIN_FSM_RATE_CALC_HDMI14_CDR_SETTING_7_REG, 8977b59b132SShreeya Patel CDR_SETTING_BOUNDARY_7_DEFAULT); 8987b59b132SShreeya Patel 8997b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_PDDQ, 0); 9007b59b132SShreeya Patel if (wait_reg_bit_status(hdmirx_dev, PHY_STATUS, PDDQ_ACK, 0, false, 10)) 9017b59b132SShreeya Patel dev_err(dev, "%s: wait pddq ack failed\n", __func__); 9027b59b132SShreeya Patel 9037b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, HDMI_DISABLE, 0); 9047b59b132SShreeya Patel if (wait_reg_bit_status(hdmirx_dev, PHY_STATUS, HDMI_DISABLE_ACK, 0, 9057b59b132SShreeya Patel false, 50)) 9067b59b132SShreeya Patel dev_err(dev, "%s: wait hdmi disable ack failed\n", __func__); 9077b59b132SShreeya Patel 9087b59b132SShreeya Patel hdmirx_tmds_clk_ratio_config(hdmirx_dev); 9097b59b132SShreeya Patel } 9107b59b132SShreeya Patel 9117b59b132SShreeya Patel static void hdmirx_controller_init(struct snps_hdmirx_dev *hdmirx_dev) 9127b59b132SShreeya Patel { 9137b59b132SShreeya Patel const unsigned long iref_clk_freq_hz = 428571429; 9147b59b132SShreeya Patel struct device *dev = hdmirx_dev->dev; 9157b59b132SShreeya Patel 9167b59b132SShreeya Patel reinit_completion(&hdmirx_dev->timer_base_lock); 9177b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); 9187b59b132SShreeya Patel /* en irq */ 9197b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 9207b59b132SShreeya Patel TIMER_BASE_LOCKED_IRQ, TIMER_BASE_LOCKED_IRQ); 9217b59b132SShreeya Patel /* write irefclk freq */ 9227b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, GLOBAL_TIMER_REF_BASE, iref_clk_freq_hz); 9237b59b132SShreeya Patel 9247b59b132SShreeya Patel if (!wait_for_completion_timeout(&hdmirx_dev->timer_base_lock, 9257b59b132SShreeya Patel msecs_to_jiffies(20))) 9267b59b132SShreeya Patel dev_err(dev, "%s wait timer base lock failed\n", __func__); 9277b59b132SShreeya Patel 9287b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, CMU_CONFIG0, 9297b59b132SShreeya Patel TMDSQPCLK_STABLE_FREQ_MARGIN_MASK | 9307b59b132SShreeya Patel AUDCLK_STABLE_FREQ_MARGIN_MASK, 9317b59b132SShreeya Patel TMDSQPCLK_STABLE_FREQ_MARGIN(2) | 9327b59b132SShreeya Patel AUDCLK_STABLE_FREQ_MARGIN(1)); 9337b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DESCRAND_EN_CONTROL, 9347b59b132SShreeya Patel SCRAMB_EN_SEL_QST_MASK, SCRAMB_EN_SEL_QST(1)); 9357b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, CED_CONFIG, 9367b59b132SShreeya Patel CED_VIDDATACHECKEN_QST | 9377b59b132SShreeya Patel CED_DATAISCHECKEN_QST | 9387b59b132SShreeya Patel CED_GBCHECKEN_QST | 9397b59b132SShreeya Patel CED_CTRLCHECKEN_QST | 9407b59b132SShreeya Patel CED_CHLOCKMAXER_QST_MASK, 9417b59b132SShreeya Patel CED_VIDDATACHECKEN_QST | 9427b59b132SShreeya Patel CED_GBCHECKEN_QST | 9437b59b132SShreeya Patel CED_CTRLCHECKEN_QST | 9447b59b132SShreeya Patel CED_CHLOCKMAXER_QST(0x10)); 9457b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DEFRAMER_CONFIG0, 9467b59b132SShreeya Patel VS_REMAPFILTER_EN_QST | VS_FILTER_ORDER_QST_MASK, 9477b59b132SShreeya Patel VS_REMAPFILTER_EN_QST | VS_FILTER_ORDER_QST(0x3)); 9487b59b132SShreeya Patel } 9497b59b132SShreeya Patel 9507b59b132SShreeya Patel static void hdmirx_get_colordepth(struct snps_hdmirx_dev *hdmirx_dev) 9517b59b132SShreeya Patel { 9527b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 9537b59b132SShreeya Patel u32 val, color_depth_reg; 9547b59b132SShreeya Patel 9557b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); 9567b59b132SShreeya Patel color_depth_reg = (val & HDMIRX_COLOR_DEPTH_MASK) >> 3; 9577b59b132SShreeya Patel 9587b59b132SShreeya Patel switch (color_depth_reg) { 9597b59b132SShreeya Patel case 0x4: 9607b59b132SShreeya Patel hdmirx_dev->color_depth = 24; 9617b59b132SShreeya Patel break; 9627b59b132SShreeya Patel case 0x5: 9637b59b132SShreeya Patel hdmirx_dev->color_depth = 30; 9647b59b132SShreeya Patel break; 9657b59b132SShreeya Patel case 0x6: 9667b59b132SShreeya Patel hdmirx_dev->color_depth = 36; 9677b59b132SShreeya Patel break; 9687b59b132SShreeya Patel case 0x7: 9697b59b132SShreeya Patel hdmirx_dev->color_depth = 48; 9707b59b132SShreeya Patel break; 9717b59b132SShreeya Patel default: 9727b59b132SShreeya Patel hdmirx_dev->color_depth = 24; 9737b59b132SShreeya Patel break; 9747b59b132SShreeya Patel } 9757b59b132SShreeya Patel 9767b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: color_depth: %d, reg_val:%d\n", 9777b59b132SShreeya Patel __func__, hdmirx_dev->color_depth, color_depth_reg); 9787b59b132SShreeya Patel } 9797b59b132SShreeya Patel 9807b59b132SShreeya Patel static void hdmirx_get_pix_fmt(struct snps_hdmirx_dev *hdmirx_dev) 9817b59b132SShreeya Patel { 9827b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 9837b59b132SShreeya Patel u32 val; 9847b59b132SShreeya Patel 9857b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, DMA_STATUS11); 9867b59b132SShreeya Patel hdmirx_dev->pix_fmt = val & HDMIRX_FORMAT_MASK; 9877b59b132SShreeya Patel 9887b59b132SShreeya Patel switch (hdmirx_dev->pix_fmt) { 9897b59b132SShreeya Patel case HDMIRX_RGB888: 9907b59b132SShreeya Patel hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; 9917b59b132SShreeya Patel break; 9927b59b132SShreeya Patel case HDMIRX_YUV422: 9937b59b132SShreeya Patel hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV16; 9947b59b132SShreeya Patel break; 9957b59b132SShreeya Patel case HDMIRX_YUV444: 9967b59b132SShreeya Patel hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV24; 9977b59b132SShreeya Patel break; 9987b59b132SShreeya Patel case HDMIRX_YUV420: 9997b59b132SShreeya Patel hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_NV12; 10007b59b132SShreeya Patel break; 10017b59b132SShreeya Patel default: 10027b59b132SShreeya Patel v4l2_err(v4l2_dev, 10037b59b132SShreeya Patel "%s: err pix_fmt: %d, set RGB888 as default\n", 10047b59b132SShreeya Patel __func__, hdmirx_dev->pix_fmt); 10057b59b132SShreeya Patel hdmirx_dev->pix_fmt = HDMIRX_RGB888; 10067b59b132SShreeya Patel hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; 10077b59b132SShreeya Patel break; 10087b59b132SShreeya Patel } 10097b59b132SShreeya Patel 10107b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s\n", __func__, 10117b59b132SShreeya Patel pix_fmt_str[hdmirx_dev->pix_fmt]); 10127b59b132SShreeya Patel } 10137b59b132SShreeya Patel 10147b59b132SShreeya Patel static void hdmirx_read_avi_infoframe(struct snps_hdmirx_dev *hdmirx_dev, 10157b59b132SShreeya Patel u8 *aviif) 10167b59b132SShreeya Patel { 10177b59b132SShreeya Patel unsigned int i, b, itr = 0; 10187b59b132SShreeya Patel u32 val; 10197b59b132SShreeya Patel 10207b59b132SShreeya Patel aviif[itr++] = HDMI_INFOFRAME_TYPE_AVI; 10217b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PH2_1); 10227b59b132SShreeya Patel aviif[itr++] = val & 0xff; 10237b59b132SShreeya Patel aviif[itr++] = (val >> 8) & 0xff; 10247b59b132SShreeya Patel 10257b59b132SShreeya Patel for (i = 0; i < 7; i++) { 10267b59b132SShreeya Patel val = hdmirx_readl(hdmirx_dev, PKTDEC_AVIIF_PB3_0 + 4 * i); 10277b59b132SShreeya Patel 10287b59b132SShreeya Patel for (b = 0; b < 4; b++) 10297b59b132SShreeya Patel aviif[itr++] = (val >> (8 * b)) & 0xff; 10307b59b132SShreeya Patel } 10317b59b132SShreeya Patel } 10327b59b132SShreeya Patel 10337b59b132SShreeya Patel static void hdmirx_get_avi_infoframe(struct snps_hdmirx_dev *hdmirx_dev) 10347b59b132SShreeya Patel { 10357b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 10367b59b132SShreeya Patel union hdmi_infoframe frame = {}; 10377b59b132SShreeya Patel u8 aviif[3 + 7 * 4]; 10387b59b132SShreeya Patel int err; 10397b59b132SShreeya Patel 10407b59b132SShreeya Patel hdmirx_read_avi_infoframe(hdmirx_dev, aviif); 10417b59b132SShreeya Patel 10427b59b132SShreeya Patel err = hdmi_infoframe_unpack(&frame, aviif, sizeof(aviif)); 10437b59b132SShreeya Patel if (err) { 10447b59b132SShreeya Patel v4l2_err(v4l2_dev, "failed to unpack AVI infoframe\n"); 10457b59b132SShreeya Patel return; 10467b59b132SShreeya Patel } 10477b59b132SShreeya Patel 10487b59b132SShreeya Patel v4l2_ctrl_s_ctrl(hdmirx_dev->rgb_range, frame.avi.quantization_range); 10497b59b132SShreeya Patel 10507b59b132SShreeya Patel if (frame.avi.itc) 10517b59b132SShreeya Patel v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, 10527b59b132SShreeya Patel frame.avi.content_type); 10537b59b132SShreeya Patel else 10547b59b132SShreeya Patel v4l2_ctrl_s_ctrl(hdmirx_dev->content_type, 10557b59b132SShreeya Patel V4L2_DV_IT_CONTENT_TYPE_NO_ITC); 10567b59b132SShreeya Patel } 10577b59b132SShreeya Patel 10587b59b132SShreeya Patel static ssize_t 10597b59b132SShreeya Patel hdmirx_debugfs_if_read(u32 type, void *priv, struct file *filp, 10607b59b132SShreeya Patel char __user *ubuf, size_t count, loff_t *ppos) 10617b59b132SShreeya Patel { 10627b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = priv; 10637b59b132SShreeya Patel u8 aviif[V4L2_DEBUGFS_IF_MAX_LEN] = {}; 10647b59b132SShreeya Patel int len; 10657b59b132SShreeya Patel 10667b59b132SShreeya Patel if (type != V4L2_DEBUGFS_IF_AVI) 10677b59b132SShreeya Patel return 0; 10687b59b132SShreeya Patel 10697b59b132SShreeya Patel hdmirx_read_avi_infoframe(hdmirx_dev, aviif); 10707b59b132SShreeya Patel 10717b59b132SShreeya Patel len = aviif[2] + 4; 10727b59b132SShreeya Patel if (len > V4L2_DEBUGFS_IF_MAX_LEN) 10737b59b132SShreeya Patel len = -ENOENT; 10747b59b132SShreeya Patel else 10757b59b132SShreeya Patel len = simple_read_from_buffer(ubuf, count, ppos, aviif, len); 10767b59b132SShreeya Patel 10777b59b132SShreeya Patel return len < 0 ? 0 : len; 10787b59b132SShreeya Patel } 10797b59b132SShreeya Patel 10807b59b132SShreeya Patel static void hdmirx_format_change(struct snps_hdmirx_dev *hdmirx_dev) 10817b59b132SShreeya Patel { 10827b59b132SShreeya Patel struct hdmirx_stream *stream = &hdmirx_dev->stream; 10837b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 10847b59b132SShreeya Patel static const struct v4l2_event ev_src_chg = { 10857b59b132SShreeya Patel .type = V4L2_EVENT_SOURCE_CHANGE, 10867b59b132SShreeya Patel .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 10877b59b132SShreeya Patel }; 10887b59b132SShreeya Patel 10897b59b132SShreeya Patel hdmirx_get_pix_fmt(hdmirx_dev); 10907b59b132SShreeya Patel hdmirx_get_colordepth(hdmirx_dev); 10917b59b132SShreeya Patel hdmirx_get_avi_infoframe(hdmirx_dev); 10927b59b132SShreeya Patel 10937b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: queue res_chg_event\n", __func__); 10947b59b132SShreeya Patel v4l2_event_queue(&stream->vdev, &ev_src_chg); 10957b59b132SShreeya Patel } 10967b59b132SShreeya Patel 10977b59b132SShreeya Patel static void hdmirx_set_ddr_store_fmt(struct snps_hdmirx_dev *hdmirx_dev) 10987b59b132SShreeya Patel { 10997b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 11007b59b132SShreeya Patel enum ddr_store_fmt store_fmt; 11017b59b132SShreeya Patel u32 dma_cfg1; 11027b59b132SShreeya Patel 11037b59b132SShreeya Patel switch (hdmirx_dev->pix_fmt) { 11047b59b132SShreeya Patel case HDMIRX_RGB888: 11057b59b132SShreeya Patel store_fmt = STORE_RGB888; 11067b59b132SShreeya Patel break; 11077b59b132SShreeya Patel case HDMIRX_YUV444: 11087b59b132SShreeya Patel store_fmt = STORE_YUV444_8BIT; 11097b59b132SShreeya Patel break; 11107b59b132SShreeya Patel case HDMIRX_YUV422: 11117b59b132SShreeya Patel store_fmt = STORE_YUV422_8BIT; 11127b59b132SShreeya Patel break; 11137b59b132SShreeya Patel case HDMIRX_YUV420: 11147b59b132SShreeya Patel store_fmt = STORE_YUV420_8BIT; 11157b59b132SShreeya Patel break; 11167b59b132SShreeya Patel default: 11177b59b132SShreeya Patel store_fmt = STORE_RGB888; 11187b59b132SShreeya Patel break; 11197b59b132SShreeya Patel } 11207b59b132SShreeya Patel 11217b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG1, 11227b59b132SShreeya Patel DDR_STORE_FORMAT_MASK, DDR_STORE_FORMAT(store_fmt)); 11237b59b132SShreeya Patel dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1); 11247b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s, DMA_CONFIG1:%#x\n", 11257b59b132SShreeya Patel __func__, pix_fmt_str[hdmirx_dev->pix_fmt], dma_cfg1); 11267b59b132SShreeya Patel } 11277b59b132SShreeya Patel 11287b59b132SShreeya Patel static void hdmirx_dma_config(struct snps_hdmirx_dev *hdmirx_dev) 11297b59b132SShreeya Patel { 11307b59b132SShreeya Patel hdmirx_set_ddr_store_fmt(hdmirx_dev); 11317b59b132SShreeya Patel 11327b59b132SShreeya Patel /* Note: uv_swap, rb can not swap, doc err */ 11337b59b132SShreeya Patel if (hdmirx_dev->cur_fmt_fourcc != V4L2_PIX_FMT_NV16) 11347b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, RB_SWAP_EN, RB_SWAP_EN); 11357b59b132SShreeya Patel else 11367b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, RB_SWAP_EN, 0); 11377b59b132SShreeya Patel 11387b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, 11397b59b132SShreeya Patel LOCK_FRAME_NUM_MASK, 11407b59b132SShreeya Patel LOCK_FRAME_NUM(2)); 11417b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG1, 11427b59b132SShreeya Patel UV_WID_MASK | Y_WID_MASK | ABANDON_EN, 11437b59b132SShreeya Patel UV_WID(1) | Y_WID(2) | ABANDON_EN); 11447b59b132SShreeya Patel } 11457b59b132SShreeya Patel 11467b59b132SShreeya Patel static void hdmirx_submodule_init(struct snps_hdmirx_dev *hdmirx_dev) 11477b59b132SShreeya Patel { 11487b59b132SShreeya Patel /* Note: if not config HDCP2_CONFIG, there will be some errors; */ 11497b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, HDCP2_CONFIG, 11507b59b132SShreeya Patel HDCP2_SWITCH_OVR_VALUE | 11517b59b132SShreeya Patel HDCP2_SWITCH_OVR_EN, 11527b59b132SShreeya Patel HDCP2_SWITCH_OVR_EN); 11537b59b132SShreeya Patel hdmirx_scdc_init(hdmirx_dev); 11547b59b132SShreeya Patel hdmirx_controller_init(hdmirx_dev); 11557b59b132SShreeya Patel } 11567b59b132SShreeya Patel 11577b59b132SShreeya Patel static int hdmirx_enum_input(struct file *file, void *priv, 11587b59b132SShreeya Patel struct v4l2_input *input) 11597b59b132SShreeya Patel { 11607b59b132SShreeya Patel if (input->index > 0) 11617b59b132SShreeya Patel return -EINVAL; 11627b59b132SShreeya Patel 11637b59b132SShreeya Patel input->type = V4L2_INPUT_TYPE_CAMERA; 11647b59b132SShreeya Patel input->std = 0; 11657b59b132SShreeya Patel strscpy(input->name, "HDMI IN", sizeof(input->name)); 11667b59b132SShreeya Patel input->capabilities = V4L2_IN_CAP_DV_TIMINGS; 11677b59b132SShreeya Patel 11687b59b132SShreeya Patel return 0; 11697b59b132SShreeya Patel } 11707b59b132SShreeya Patel 11717b59b132SShreeya Patel static int hdmirx_get_input(struct file *file, void *priv, unsigned int *i) 11727b59b132SShreeya Patel { 11737b59b132SShreeya Patel *i = 0; 11747b59b132SShreeya Patel return 0; 11757b59b132SShreeya Patel } 11767b59b132SShreeya Patel 11777b59b132SShreeya Patel static int hdmirx_set_input(struct file *file, void *priv, unsigned int i) 11787b59b132SShreeya Patel { 11797b59b132SShreeya Patel if (i) 11807b59b132SShreeya Patel return -EINVAL; 11817b59b132SShreeya Patel return 0; 11827b59b132SShreeya Patel } 11837b59b132SShreeya Patel 11847b59b132SShreeya Patel static void hdmirx_set_fmt(struct hdmirx_stream *stream, 11857b59b132SShreeya Patel struct v4l2_pix_format_mplane *pixm, bool try) 11867b59b132SShreeya Patel { 11877b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 11887b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 11897b59b132SShreeya Patel struct v4l2_bt_timings *bt = &hdmirx_dev->timings.bt; 11907b59b132SShreeya Patel const struct v4l2_format_info *finfo; 11917b59b132SShreeya Patel unsigned int imagesize = 0; 11927b59b132SShreeya Patel unsigned int i; 11937b59b132SShreeya Patel 11947b59b132SShreeya Patel memset(&pixm->plane_fmt[0], 0, sizeof(struct v4l2_plane_pix_format)); 11957b59b132SShreeya Patel finfo = v4l2_format_info(pixm->pixelformat); 11967b59b132SShreeya Patel if (!finfo) { 11977b59b132SShreeya Patel finfo = v4l2_format_info(V4L2_PIX_FMT_BGR24); 11987b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 11997b59b132SShreeya Patel "%s: set_fmt:%#x not supported, use def_fmt:%x\n", 12007b59b132SShreeya Patel __func__, pixm->pixelformat, finfo->format); 12017b59b132SShreeya Patel } 12027b59b132SShreeya Patel 12037b59b132SShreeya Patel if (!bt->width || !bt->height) 12047b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: invalid resolution:%#xx%#x\n", 12057b59b132SShreeya Patel __func__, bt->width, bt->height); 12067b59b132SShreeya Patel 12077b59b132SShreeya Patel pixm->pixelformat = finfo->format; 12087b59b132SShreeya Patel pixm->width = bt->width; 12097b59b132SShreeya Patel pixm->height = bt->height; 12107b59b132SShreeya Patel pixm->num_planes = finfo->mem_planes; 12117b59b132SShreeya Patel pixm->quantization = V4L2_QUANTIZATION_DEFAULT; 12127b59b132SShreeya Patel pixm->colorspace = V4L2_COLORSPACE_SRGB; 12137b59b132SShreeya Patel pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 12147b59b132SShreeya Patel 12157b59b132SShreeya Patel if (bt->interlaced == V4L2_DV_INTERLACED) 12167b59b132SShreeya Patel pixm->field = V4L2_FIELD_INTERLACED_TB; 12177b59b132SShreeya Patel else 12187b59b132SShreeya Patel pixm->field = V4L2_FIELD_NONE; 12197b59b132SShreeya Patel 12207b59b132SShreeya Patel memset(pixm->reserved, 0, sizeof(pixm->reserved)); 12217b59b132SShreeya Patel 12227b59b132SShreeya Patel v4l2_fill_pixfmt_mp(pixm, finfo->format, pixm->width, pixm->height); 12237b59b132SShreeya Patel 12247b59b132SShreeya Patel for (i = 0; i < finfo->comp_planes; i++) { 12257b59b132SShreeya Patel struct v4l2_plane_pix_format *plane_fmt; 12267b59b132SShreeya Patel int width, height, bpl, size, bpp = 0; 12277b59b132SShreeya Patel const unsigned int hw_align = 64; 12287b59b132SShreeya Patel 12297b59b132SShreeya Patel if (!i) { 12307b59b132SShreeya Patel width = pixm->width; 12317b59b132SShreeya Patel height = pixm->height; 12327b59b132SShreeya Patel } else { 12337b59b132SShreeya Patel width = pixm->width / finfo->hdiv; 12347b59b132SShreeya Patel height = pixm->height / finfo->vdiv; 12357b59b132SShreeya Patel } 12367b59b132SShreeya Patel 12377b59b132SShreeya Patel switch (finfo->format) { 12387b59b132SShreeya Patel case V4L2_PIX_FMT_NV24: 12397b59b132SShreeya Patel case V4L2_PIX_FMT_NV16: 12407b59b132SShreeya Patel case V4L2_PIX_FMT_NV12: 12417b59b132SShreeya Patel case V4L2_PIX_FMT_BGR24: 12427b59b132SShreeya Patel bpp = finfo->bpp[i]; 12437b59b132SShreeya Patel break; 12447b59b132SShreeya Patel default: 12457b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 12467b59b132SShreeya Patel "fourcc: %#x is not supported\n", 12477b59b132SShreeya Patel finfo->format); 12487b59b132SShreeya Patel break; 12497b59b132SShreeya Patel } 12507b59b132SShreeya Patel 12517b59b132SShreeya Patel bpl = ALIGN(width * bpp, hw_align); 12527b59b132SShreeya Patel size = bpl * height; 12537b59b132SShreeya Patel imagesize += size; 12547b59b132SShreeya Patel 12557b59b132SShreeya Patel if (finfo->mem_planes > i) { 12567b59b132SShreeya Patel /* Set bpl and size for each mplane */ 12577b59b132SShreeya Patel plane_fmt = pixm->plane_fmt + i; 12587b59b132SShreeya Patel plane_fmt->bytesperline = bpl; 12597b59b132SShreeya Patel plane_fmt->sizeimage = size; 12607b59b132SShreeya Patel } 12617b59b132SShreeya Patel 12627b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 12637b59b132SShreeya Patel "C-Plane %u size: %d, Total imagesize: %d\n", 12647b59b132SShreeya Patel i, size, imagesize); 12657b59b132SShreeya Patel } 12667b59b132SShreeya Patel 12677b59b132SShreeya Patel /* Convert to non-MPLANE format as we want to unify non-MPLANE and MPLANE */ 12687b59b132SShreeya Patel if (finfo->mem_planes == 1) 12697b59b132SShreeya Patel pixm->plane_fmt[0].sizeimage = imagesize; 12707b59b132SShreeya Patel 12717b59b132SShreeya Patel if (!try) { 12727b59b132SShreeya Patel stream->out_finfo = finfo; 12737b59b132SShreeya Patel stream->pixm = *pixm; 12747b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 12757b59b132SShreeya Patel "%s: req(%d, %d), out(%d, %d), fmt:%#x\n", __func__, 12767b59b132SShreeya Patel pixm->width, pixm->height, stream->pixm.width, 12777b59b132SShreeya Patel stream->pixm.height, finfo->format); 12787b59b132SShreeya Patel } 12797b59b132SShreeya Patel } 12807b59b132SShreeya Patel 12817b59b132SShreeya Patel static int hdmirx_enum_fmt_vid_cap_mplane(struct file *file, void *priv, 12827b59b132SShreeya Patel struct v4l2_fmtdesc *f) 12837b59b132SShreeya Patel { 12847b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 12857b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 12867b59b132SShreeya Patel 12877b59b132SShreeya Patel if (f->index >= 1) 12887b59b132SShreeya Patel return -EINVAL; 12897b59b132SShreeya Patel 12907b59b132SShreeya Patel f->pixelformat = hdmirx_dev->cur_fmt_fourcc; 12917b59b132SShreeya Patel 12927b59b132SShreeya Patel return 0; 12937b59b132SShreeya Patel } 12947b59b132SShreeya Patel 12957b59b132SShreeya Patel static int hdmirx_s_fmt_vid_cap_mplane(struct file *file, 12967b59b132SShreeya Patel void *priv, struct v4l2_format *f) 12977b59b132SShreeya Patel { 12987b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 12997b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 13007b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 13017b59b132SShreeya Patel 13027b59b132SShreeya Patel if (vb2_is_busy(&stream->buf_queue)) { 13037b59b132SShreeya Patel v4l2_err(v4l2_dev, "%s: queue busy\n", __func__); 13047b59b132SShreeya Patel return -EBUSY; 13057b59b132SShreeya Patel } 13067b59b132SShreeya Patel 13077b59b132SShreeya Patel hdmirx_set_fmt(stream, &f->fmt.pix_mp, false); 13087b59b132SShreeya Patel 13097b59b132SShreeya Patel return 0; 13107b59b132SShreeya Patel } 13117b59b132SShreeya Patel 13127b59b132SShreeya Patel static int hdmirx_g_fmt_vid_cap_mplane(struct file *file, void *fh, 13137b59b132SShreeya Patel struct v4l2_format *f) 13147b59b132SShreeya Patel { 13157b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 13167b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 13177b59b132SShreeya Patel struct v4l2_pix_format_mplane pixm = {}; 13187b59b132SShreeya Patel 13197b59b132SShreeya Patel pixm.pixelformat = hdmirx_dev->cur_fmt_fourcc; 13207b59b132SShreeya Patel hdmirx_set_fmt(stream, &pixm, true); 13217b59b132SShreeya Patel f->fmt.pix_mp = pixm; 13227b59b132SShreeya Patel 13237b59b132SShreeya Patel return 0; 13247b59b132SShreeya Patel } 13257b59b132SShreeya Patel 13267b59b132SShreeya Patel static int hdmirx_g_dv_timings(struct file *file, void *_fh, 13277b59b132SShreeya Patel struct v4l2_dv_timings *timings) 13287b59b132SShreeya Patel { 13297b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 13307b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 13317b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 13327b59b132SShreeya Patel u32 dma_cfg1; 13337b59b132SShreeya Patel 13347b59b132SShreeya Patel *timings = hdmirx_dev->timings; 13357b59b132SShreeya Patel dma_cfg1 = hdmirx_readl(hdmirx_dev, DMA_CONFIG1); 13367b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: pix_fmt: %s, DMA_CONFIG1:%#x\n", 13377b59b132SShreeya Patel __func__, pix_fmt_str[hdmirx_dev->pix_fmt], dma_cfg1); 13387b59b132SShreeya Patel 13397b59b132SShreeya Patel return 0; 13407b59b132SShreeya Patel } 13417b59b132SShreeya Patel 13427b59b132SShreeya Patel static int hdmirx_s_dv_timings(struct file *file, void *_fh, 13437b59b132SShreeya Patel struct v4l2_dv_timings *timings) 13447b59b132SShreeya Patel { 13457b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 13467b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 13477b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 13487b59b132SShreeya Patel 13497b59b132SShreeya Patel if (!timings) 13507b59b132SShreeya Patel return -EINVAL; 13517b59b132SShreeya Patel 13527b59b132SShreeya Patel if (debug) 13537b59b132SShreeya Patel v4l2_print_dv_timings(hdmirx_dev->v4l2_dev.name, 13547b59b132SShreeya Patel "s_dv_timings: ", timings, false); 13557b59b132SShreeya Patel 13567b59b132SShreeya Patel if (!v4l2_valid_dv_timings(timings, &hdmirx_timings_cap, NULL, NULL)) { 13577b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 13587b59b132SShreeya Patel "%s: timings out of range\n", __func__); 13597b59b132SShreeya Patel return -ERANGE; 13607b59b132SShreeya Patel } 13617b59b132SShreeya Patel 13627b59b132SShreeya Patel /* Check if the timings are part of the CEA-861 timings. */ 13637b59b132SShreeya Patel v4l2_find_dv_timings_cap(timings, &hdmirx_timings_cap, 0, NULL, NULL); 13647b59b132SShreeya Patel 13657b59b132SShreeya Patel if (v4l2_match_dv_timings(&hdmirx_dev->timings, timings, 0, false)) { 13667b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: no change\n", __func__); 13677b59b132SShreeya Patel return 0; 13687b59b132SShreeya Patel } 13697b59b132SShreeya Patel 13707b59b132SShreeya Patel /* 13717b59b132SShreeya Patel * Changing the timings implies a format change, which is not allowed 13727b59b132SShreeya Patel * while buffers for use with streaming have already been allocated. 13737b59b132SShreeya Patel */ 13747b59b132SShreeya Patel if (vb2_is_busy(&stream->buf_queue)) 13757b59b132SShreeya Patel return -EBUSY; 13767b59b132SShreeya Patel 13777b59b132SShreeya Patel hdmirx_dev->timings = *timings; 13787b59b132SShreeya Patel /* Update the internal format */ 13797b59b132SShreeya Patel hdmirx_set_fmt(stream, &stream->pixm, false); 13807b59b132SShreeya Patel 13817b59b132SShreeya Patel return 0; 13827b59b132SShreeya Patel } 13837b59b132SShreeya Patel 13847b59b132SShreeya Patel static int hdmirx_querycap(struct file *file, void *priv, 13857b59b132SShreeya Patel struct v4l2_capability *cap) 13867b59b132SShreeya Patel { 13877b59b132SShreeya Patel struct hdmirx_stream *stream = video_drvdata(file); 13887b59b132SShreeya Patel struct device *dev = stream->hdmirx_dev->dev; 13897b59b132SShreeya Patel 13907b59b132SShreeya Patel strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); 13917b59b132SShreeya Patel strscpy(cap->card, dev->driver->name, sizeof(cap->card)); 13927b59b132SShreeya Patel 13937b59b132SShreeya Patel return 0; 13947b59b132SShreeya Patel } 13957b59b132SShreeya Patel 13967b59b132SShreeya Patel static int hdmirx_queue_setup(struct vb2_queue *queue, 13977b59b132SShreeya Patel unsigned int *num_buffers, 13987b59b132SShreeya Patel unsigned int *num_planes, 13997b59b132SShreeya Patel unsigned int sizes[], 14007b59b132SShreeya Patel struct device *alloc_ctxs[]) 14017b59b132SShreeya Patel { 14027b59b132SShreeya Patel struct hdmirx_stream *stream = vb2_get_drv_priv(queue); 14037b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 14047b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 14057b59b132SShreeya Patel const struct v4l2_pix_format_mplane *pixm = NULL; 14067b59b132SShreeya Patel const struct v4l2_format_info *out_finfo; 14077b59b132SShreeya Patel u32 i; 14087b59b132SShreeya Patel 14097b59b132SShreeya Patel pixm = &stream->pixm; 14107b59b132SShreeya Patel out_finfo = stream->out_finfo; 14117b59b132SShreeya Patel 14127b59b132SShreeya Patel if (!out_finfo) { 14137b59b132SShreeya Patel v4l2_err(v4l2_dev, "%s: out_fmt not set\n", __func__); 14147b59b132SShreeya Patel return -EINVAL; 14157b59b132SShreeya Patel } 14167b59b132SShreeya Patel 14177b59b132SShreeya Patel if (*num_planes) { 14187b59b132SShreeya Patel if (*num_planes != pixm->num_planes) 14197b59b132SShreeya Patel return -EINVAL; 14207b59b132SShreeya Patel 14217b59b132SShreeya Patel for (i = 0; i < *num_planes; i++) 14227b59b132SShreeya Patel if (sizes[i] < pixm->plane_fmt[i].sizeimage) 14237b59b132SShreeya Patel return -EINVAL; 14247b59b132SShreeya Patel return 0; 14257b59b132SShreeya Patel } 14267b59b132SShreeya Patel 14277b59b132SShreeya Patel *num_planes = out_finfo->mem_planes; 14287b59b132SShreeya Patel 14297b59b132SShreeya Patel for (i = 0; i < out_finfo->mem_planes; i++) 14307b59b132SShreeya Patel sizes[i] = pixm->plane_fmt[i].sizeimage; 14317b59b132SShreeya Patel 14327b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: count %d, size %d\n", 14337b59b132SShreeya Patel v4l2_type_names[queue->type], *num_buffers, sizes[0]); 14347b59b132SShreeya Patel 14357b59b132SShreeya Patel return 0; 14367b59b132SShreeya Patel } 14377b59b132SShreeya Patel 14387b59b132SShreeya Patel /* 14397b59b132SShreeya Patel * The vb2_buffer are stored in hdmirx_buffer, in order to unify 14407b59b132SShreeya Patel * mplane buffer and none-mplane buffer. 14417b59b132SShreeya Patel */ 14427b59b132SShreeya Patel static void hdmirx_buf_queue(struct vb2_buffer *vb) 14437b59b132SShreeya Patel { 14447b59b132SShreeya Patel const struct v4l2_pix_format_mplane *pixm; 14457b59b132SShreeya Patel const struct v4l2_format_info *out_finfo; 14467b59b132SShreeya Patel struct hdmirx_buffer *hdmirx_buf; 14477b59b132SShreeya Patel struct vb2_v4l2_buffer *vbuf; 14487b59b132SShreeya Patel struct hdmirx_stream *stream; 14497b59b132SShreeya Patel struct vb2_queue *queue; 14507b59b132SShreeya Patel unsigned long flags; 14517b59b132SShreeya Patel unsigned int i; 14527b59b132SShreeya Patel 14537b59b132SShreeya Patel vbuf = to_vb2_v4l2_buffer(vb); 14547b59b132SShreeya Patel hdmirx_buf = container_of(vbuf, struct hdmirx_buffer, vb); 14557b59b132SShreeya Patel queue = vb->vb2_queue; 14567b59b132SShreeya Patel stream = vb2_get_drv_priv(queue); 14577b59b132SShreeya Patel pixm = &stream->pixm; 14587b59b132SShreeya Patel out_finfo = stream->out_finfo; 14597b59b132SShreeya Patel 14607b59b132SShreeya Patel memset(hdmirx_buf->buff_addr, 0, sizeof(hdmirx_buf->buff_addr)); 14617b59b132SShreeya Patel 14627b59b132SShreeya Patel /* 14637b59b132SShreeya Patel * If mplanes > 1, every c-plane has its own m-plane, 14647b59b132SShreeya Patel * otherwise, multiple c-planes are in the same m-plane 14657b59b132SShreeya Patel */ 14667b59b132SShreeya Patel for (i = 0; i < out_finfo->mem_planes; i++) 14677b59b132SShreeya Patel hdmirx_buf->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); 14687b59b132SShreeya Patel 14697b59b132SShreeya Patel if (out_finfo->mem_planes == 1) { 14707b59b132SShreeya Patel if (out_finfo->comp_planes == 1) { 14717b59b132SShreeya Patel hdmirx_buf->buff_addr[HDMIRX_PLANE_CBCR] = 14727b59b132SShreeya Patel hdmirx_buf->buff_addr[HDMIRX_PLANE_Y]; 14737b59b132SShreeya Patel } else { 14747b59b132SShreeya Patel for (i = 0; i < out_finfo->comp_planes - 1; i++) 14757b59b132SShreeya Patel hdmirx_buf->buff_addr[i + 1] = 14767b59b132SShreeya Patel hdmirx_buf->buff_addr[i] + 14777b59b132SShreeya Patel pixm->plane_fmt[i].bytesperline * 14787b59b132SShreeya Patel pixm->height; 14797b59b132SShreeya Patel } 14807b59b132SShreeya Patel } 14817b59b132SShreeya Patel 14827b59b132SShreeya Patel spin_lock_irqsave(&stream->vbq_lock, flags); 14837b59b132SShreeya Patel list_add_tail(&hdmirx_buf->queue, &stream->buf_head); 14847b59b132SShreeya Patel spin_unlock_irqrestore(&stream->vbq_lock, flags); 14857b59b132SShreeya Patel } 14867b59b132SShreeya Patel 14877b59b132SShreeya Patel static void return_all_buffers(struct hdmirx_stream *stream, 14887b59b132SShreeya Patel enum vb2_buffer_state state) 14897b59b132SShreeya Patel { 14907b59b132SShreeya Patel struct hdmirx_buffer *buf, *tmp; 14917b59b132SShreeya Patel unsigned long flags; 14927b59b132SShreeya Patel 14937b59b132SShreeya Patel spin_lock_irqsave(&stream->vbq_lock, flags); 14947b59b132SShreeya Patel if (stream->curr_buf) 14957b59b132SShreeya Patel list_add_tail(&stream->curr_buf->queue, &stream->buf_head); 14967b59b132SShreeya Patel if (stream->next_buf && stream->next_buf != stream->curr_buf) 14977b59b132SShreeya Patel list_add_tail(&stream->next_buf->queue, &stream->buf_head); 14987b59b132SShreeya Patel stream->curr_buf = NULL; 14997b59b132SShreeya Patel stream->next_buf = NULL; 15007b59b132SShreeya Patel 15017b59b132SShreeya Patel list_for_each_entry_safe(buf, tmp, &stream->buf_head, queue) { 15027b59b132SShreeya Patel list_del(&buf->queue); 15037b59b132SShreeya Patel vb2_buffer_done(&buf->vb.vb2_buf, state); 15047b59b132SShreeya Patel } 15057b59b132SShreeya Patel spin_unlock_irqrestore(&stream->vbq_lock, flags); 15067b59b132SShreeya Patel } 15077b59b132SShreeya Patel 15087b59b132SShreeya Patel static void hdmirx_stop_streaming(struct vb2_queue *queue) 15097b59b132SShreeya Patel { 15107b59b132SShreeya Patel struct hdmirx_stream *stream = vb2_get_drv_priv(queue); 15117b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 15127b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 15137b59b132SShreeya Patel int ret; 15147b59b132SShreeya Patel 15157b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "stream start stopping\n"); 15167b59b132SShreeya Patel mutex_lock(&hdmirx_dev->stream_lock); 15177b59b132SShreeya Patel WRITE_ONCE(stream->stopping, true); 15187b59b132SShreeya Patel 15197b59b132SShreeya Patel /* wait last irq to return the buffer */ 15207b59b132SShreeya Patel ret = wait_event_timeout(stream->wq_stopped, !stream->stopping, 15217b59b132SShreeya Patel msecs_to_jiffies(500)); 15227b59b132SShreeya Patel if (!ret) 15237b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: timeout waiting last irq\n", 15247b59b132SShreeya Patel __func__); 15257b59b132SShreeya Patel 15267b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); 15277b59b132SShreeya Patel return_all_buffers(stream, VB2_BUF_STATE_ERROR); 15287b59b132SShreeya Patel mutex_unlock(&hdmirx_dev->stream_lock); 15297b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "stream stopping finished\n"); 15307b59b132SShreeya Patel } 15317b59b132SShreeya Patel 15327b59b132SShreeya Patel static int hdmirx_start_streaming(struct vb2_queue *queue, unsigned int count) 15337b59b132SShreeya Patel { 15347b59b132SShreeya Patel struct hdmirx_stream *stream = vb2_get_drv_priv(queue); 15357b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 15367b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 15377b59b132SShreeya Patel struct v4l2_dv_timings timings = hdmirx_dev->timings; 15387b59b132SShreeya Patel struct v4l2_bt_timings *bt = &timings.bt; 15397b59b132SShreeya Patel unsigned long lock_flags = 0; 15407b59b132SShreeya Patel int line_flag; 15417b59b132SShreeya Patel 15427b59b132SShreeya Patel mutex_lock(&hdmirx_dev->stream_lock); 15430400bee6SNicolas Dufresne stream->sequence = 0; 15447b59b132SShreeya Patel stream->line_flag_int_cnt = 0; 15457b59b132SShreeya Patel stream->curr_buf = NULL; 15467b59b132SShreeya Patel stream->next_buf = NULL; 15477b59b132SShreeya Patel stream->irq_stat = 0; 15487b59b132SShreeya Patel 15497b59b132SShreeya Patel WRITE_ONCE(stream->stopping, false); 15507b59b132SShreeya Patel 15517b59b132SShreeya Patel spin_lock_irqsave(&stream->vbq_lock, lock_flags); 15527b59b132SShreeya Patel if (!stream->curr_buf) { 15537b59b132SShreeya Patel if (!list_empty(&stream->buf_head)) { 15547b59b132SShreeya Patel stream->curr_buf = list_first_entry(&stream->buf_head, 15557b59b132SShreeya Patel struct hdmirx_buffer, 15567b59b132SShreeya Patel queue); 15577b59b132SShreeya Patel list_del(&stream->curr_buf->queue); 15587b59b132SShreeya Patel } else { 15597b59b132SShreeya Patel stream->curr_buf = NULL; 15607b59b132SShreeya Patel } 15617b59b132SShreeya Patel } 15627b59b132SShreeya Patel spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); 15637b59b132SShreeya Patel 15647b59b132SShreeya Patel if (!stream->curr_buf) { 15657b59b132SShreeya Patel mutex_unlock(&hdmirx_dev->stream_lock); 15667b59b132SShreeya Patel return -ENOMEM; 15677b59b132SShreeya Patel } 15687b59b132SShreeya Patel 15697b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, 15707b59b132SShreeya Patel "%s: start_stream cur_buf y_addr:%#x, uv_addr:%#x\n", 15717b59b132SShreeya Patel __func__, stream->curr_buf->buff_addr[HDMIRX_PLANE_Y], 15727b59b132SShreeya Patel stream->curr_buf->buff_addr[HDMIRX_PLANE_CBCR]); 15737b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG2, 15747b59b132SShreeya Patel stream->curr_buf->buff_addr[HDMIRX_PLANE_Y]); 15757b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG3, 15767b59b132SShreeya Patel stream->curr_buf->buff_addr[HDMIRX_PLANE_CBCR]); 15777b59b132SShreeya Patel 15787b59b132SShreeya Patel if (bt->height) { 15797b59b132SShreeya Patel if (bt->interlaced == V4L2_DV_INTERLACED) 15807b59b132SShreeya Patel line_flag = bt->height / 4; 15817b59b132SShreeya Patel else 15827b59b132SShreeya Patel line_flag = bt->height / 2; 15837b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG7, 15847b59b132SShreeya Patel LINE_FLAG_NUM_MASK, 15857b59b132SShreeya Patel LINE_FLAG_NUM(line_flag)); 15867b59b132SShreeya Patel } else { 15877b59b132SShreeya Patel v4l2_err(v4l2_dev, "invalid BT timing height=%d\n", bt->height); 15887b59b132SShreeya Patel } 15897b59b132SShreeya Patel 15907b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); 15917b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, CED_DYN_CONTROL, 0x1); 15927b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, 15937b59b132SShreeya Patel LINE_FLAG_INT_EN | 15947b59b132SShreeya Patel HDMIRX_DMA_IDLE_INT | 15957b59b132SShreeya Patel HDMIRX_LOCK_DISABLE_INT | 15967b59b132SShreeya Patel LAST_FRAME_AXI_UNFINISH_INT_EN | 15977b59b132SShreeya Patel FIFO_OVERFLOW_INT_EN | 15987b59b132SShreeya Patel FIFO_UNDERFLOW_INT_EN | 15997b59b132SShreeya Patel HDMIRX_AXI_ERROR_INT_EN, 16007b59b132SShreeya Patel LINE_FLAG_INT_EN | 16017b59b132SShreeya Patel HDMIRX_DMA_IDLE_INT | 16027b59b132SShreeya Patel HDMIRX_LOCK_DISABLE_INT | 16037b59b132SShreeya Patel LAST_FRAME_AXI_UNFINISH_INT_EN | 16047b59b132SShreeya Patel FIFO_OVERFLOW_INT_EN | 16057b59b132SShreeya Patel FIFO_UNDERFLOW_INT_EN | 16067b59b132SShreeya Patel HDMIRX_AXI_ERROR_INT_EN); 16077b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, HDMIRX_DMA_EN); 16087b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: enable dma", __func__); 16097b59b132SShreeya Patel mutex_unlock(&hdmirx_dev->stream_lock); 16107b59b132SShreeya Patel 16117b59b132SShreeya Patel return 0; 16127b59b132SShreeya Patel } 16137b59b132SShreeya Patel 16147b59b132SShreeya Patel /* vb2 queue */ 16157b59b132SShreeya Patel static const struct vb2_ops hdmirx_vb2_ops = { 16167b59b132SShreeya Patel .queue_setup = hdmirx_queue_setup, 16177b59b132SShreeya Patel .buf_queue = hdmirx_buf_queue, 16187b59b132SShreeya Patel .stop_streaming = hdmirx_stop_streaming, 16197b59b132SShreeya Patel .start_streaming = hdmirx_start_streaming, 16207b59b132SShreeya Patel }; 16217b59b132SShreeya Patel 16227b59b132SShreeya Patel static int hdmirx_init_vb2_queue(struct vb2_queue *q, 16237b59b132SShreeya Patel struct hdmirx_stream *stream, 16247b59b132SShreeya Patel enum v4l2_buf_type buf_type) 16257b59b132SShreeya Patel { 16267b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 16277b59b132SShreeya Patel 16287b59b132SShreeya Patel q->type = buf_type; 16297b59b132SShreeya Patel q->io_modes = VB2_MMAP | VB2_DMABUF; 16307b59b132SShreeya Patel q->drv_priv = stream; 16317b59b132SShreeya Patel q->ops = &hdmirx_vb2_ops; 16327b59b132SShreeya Patel q->mem_ops = &vb2_dma_contig_memops; 16337b59b132SShreeya Patel q->buf_struct_size = sizeof(struct hdmirx_buffer); 16347b59b132SShreeya Patel q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 16357b59b132SShreeya Patel q->lock = &stream->vlock; 16367b59b132SShreeya Patel q->dev = hdmirx_dev->dev; 16377b59b132SShreeya Patel q->min_queued_buffers = 1; 16387b59b132SShreeya Patel 16397b59b132SShreeya Patel return vb2_queue_init(q); 16407b59b132SShreeya Patel } 16417b59b132SShreeya Patel 16427b59b132SShreeya Patel /* video device */ 16437b59b132SShreeya Patel static const struct v4l2_ioctl_ops hdmirx_v4l2_ioctl_ops = { 16447b59b132SShreeya Patel .vidioc_querycap = hdmirx_querycap, 16457b59b132SShreeya Patel .vidioc_try_fmt_vid_cap_mplane = hdmirx_g_fmt_vid_cap_mplane, 16467b59b132SShreeya Patel .vidioc_s_fmt_vid_cap_mplane = hdmirx_s_fmt_vid_cap_mplane, 16477b59b132SShreeya Patel .vidioc_g_fmt_vid_cap_mplane = hdmirx_g_fmt_vid_cap_mplane, 16487b59b132SShreeya Patel .vidioc_enum_fmt_vid_cap = hdmirx_enum_fmt_vid_cap_mplane, 16497b59b132SShreeya Patel 16507b59b132SShreeya Patel .vidioc_s_dv_timings = hdmirx_s_dv_timings, 16517b59b132SShreeya Patel .vidioc_g_dv_timings = hdmirx_g_dv_timings, 16527b59b132SShreeya Patel .vidioc_enum_dv_timings = hdmirx_enum_dv_timings, 16537b59b132SShreeya Patel .vidioc_query_dv_timings = hdmirx_query_dv_timings, 16547b59b132SShreeya Patel .vidioc_dv_timings_cap = hdmirx_dv_timings_cap, 16557b59b132SShreeya Patel .vidioc_enum_input = hdmirx_enum_input, 16567b59b132SShreeya Patel .vidioc_g_input = hdmirx_get_input, 16577b59b132SShreeya Patel .vidioc_s_input = hdmirx_set_input, 16587b59b132SShreeya Patel .vidioc_g_edid = hdmirx_get_edid, 16597b59b132SShreeya Patel .vidioc_s_edid = hdmirx_set_edid, 16607b59b132SShreeya Patel .vidioc_g_parm = hdmirx_g_parm, 16617b59b132SShreeya Patel 16627b59b132SShreeya Patel .vidioc_reqbufs = vb2_ioctl_reqbufs, 16637b59b132SShreeya Patel .vidioc_querybuf = vb2_ioctl_querybuf, 16647b59b132SShreeya Patel .vidioc_create_bufs = vb2_ioctl_create_bufs, 16657b59b132SShreeya Patel .vidioc_qbuf = vb2_ioctl_qbuf, 16667b59b132SShreeya Patel .vidioc_expbuf = vb2_ioctl_expbuf, 16677b59b132SShreeya Patel .vidioc_dqbuf = vb2_ioctl_dqbuf, 16687b59b132SShreeya Patel .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 16697b59b132SShreeya Patel .vidioc_streamon = vb2_ioctl_streamon, 16707b59b132SShreeya Patel .vidioc_streamoff = vb2_ioctl_streamoff, 16717b59b132SShreeya Patel 16727b59b132SShreeya Patel .vidioc_log_status = v4l2_ctrl_log_status, 16737b59b132SShreeya Patel .vidioc_subscribe_event = hdmirx_subscribe_event, 16747b59b132SShreeya Patel .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 16757b59b132SShreeya Patel }; 16767b59b132SShreeya Patel 16777b59b132SShreeya Patel static const struct v4l2_file_operations hdmirx_fops = { 16787b59b132SShreeya Patel .owner = THIS_MODULE, 16797b59b132SShreeya Patel .open = v4l2_fh_open, 16807b59b132SShreeya Patel .release = vb2_fop_release, 16817b59b132SShreeya Patel .unlocked_ioctl = video_ioctl2, 16827b59b132SShreeya Patel .poll = vb2_fop_poll, 16837b59b132SShreeya Patel .mmap = vb2_fop_mmap, 16847b59b132SShreeya Patel }; 16857b59b132SShreeya Patel 16867b59b132SShreeya Patel static int hdmirx_register_stream_vdev(struct hdmirx_stream *stream) 16877b59b132SShreeya Patel { 16887b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = stream->hdmirx_dev; 16897b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 16907b59b132SShreeya Patel struct video_device *vdev = &stream->vdev; 16917b59b132SShreeya Patel int ret; 16927b59b132SShreeya Patel 16937b59b132SShreeya Patel strscpy(vdev->name, "stream_hdmirx", sizeof(vdev->name)); 16947b59b132SShreeya Patel INIT_LIST_HEAD(&stream->buf_head); 16957b59b132SShreeya Patel spin_lock_init(&stream->vbq_lock); 16967b59b132SShreeya Patel mutex_init(&stream->vlock); 16977b59b132SShreeya Patel init_waitqueue_head(&stream->wq_stopped); 16987b59b132SShreeya Patel stream->curr_buf = NULL; 16997b59b132SShreeya Patel stream->next_buf = NULL; 17007b59b132SShreeya Patel 17017b59b132SShreeya Patel vdev->ioctl_ops = &hdmirx_v4l2_ioctl_ops; 17027b59b132SShreeya Patel vdev->release = video_device_release_empty; 17037b59b132SShreeya Patel vdev->fops = &hdmirx_fops; 17047b59b132SShreeya Patel vdev->minor = -1; 17057b59b132SShreeya Patel vdev->v4l2_dev = v4l2_dev; 17067b59b132SShreeya Patel vdev->lock = &stream->vlock; 17077b59b132SShreeya Patel vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | 17087b59b132SShreeya Patel V4L2_CAP_STREAMING; 17097b59b132SShreeya Patel vdev->vfl_dir = VFL_DIR_RX; 17107b59b132SShreeya Patel 17117b59b132SShreeya Patel video_set_drvdata(vdev, stream); 17127b59b132SShreeya Patel 17137b59b132SShreeya Patel hdmirx_init_vb2_queue(&stream->buf_queue, stream, 17147b59b132SShreeya Patel V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 17157b59b132SShreeya Patel vdev->queue = &stream->buf_queue; 17167b59b132SShreeya Patel 17177b59b132SShreeya Patel ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 17187b59b132SShreeya Patel if (ret < 0) { 17197b59b132SShreeya Patel v4l2_err(v4l2_dev, "video_register_device failed: %d\n", ret); 17207b59b132SShreeya Patel return ret; 17217b59b132SShreeya Patel } 17227b59b132SShreeya Patel 17237b59b132SShreeya Patel return 0; 17247b59b132SShreeya Patel } 17257b59b132SShreeya Patel 17267b59b132SShreeya Patel static void process_signal_change(struct snps_hdmirx_dev *hdmirx_dev) 17277b59b132SShreeya Patel { 17287b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG6, HDMIRX_DMA_EN, 0); 17297b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, 17307b59b132SShreeya Patel LINE_FLAG_INT_EN | 17317b59b132SShreeya Patel HDMIRX_DMA_IDLE_INT | 17327b59b132SShreeya Patel HDMIRX_LOCK_DISABLE_INT | 17337b59b132SShreeya Patel LAST_FRAME_AXI_UNFINISH_INT_EN | 17347b59b132SShreeya Patel FIFO_OVERFLOW_INT_EN | 17357b59b132SShreeya Patel FIFO_UNDERFLOW_INT_EN | 17367b59b132SShreeya Patel HDMIRX_AXI_ERROR_INT_EN, 0); 17377b59b132SShreeya Patel hdmirx_reset_dma(hdmirx_dev); 17387b59b132SShreeya Patel queue_delayed_work(system_unbound_wq, 17397b59b132SShreeya Patel &hdmirx_dev->delayed_work_res_change, 17407b59b132SShreeya Patel msecs_to_jiffies(50)); 17417b59b132SShreeya Patel } 17427b59b132SShreeya Patel 17437b59b132SShreeya Patel static void avpunit_0_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 17447b59b132SShreeya Patel int status, bool *handled) 17457b59b132SShreeya Patel { 17467b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 17477b59b132SShreeya Patel 17487b59b132SShreeya Patel if (status & (CED_DYN_CNT_CH2_IRQ | 17497b59b132SShreeya Patel CED_DYN_CNT_CH1_IRQ | 17507b59b132SShreeya Patel CED_DYN_CNT_CH0_IRQ)) { 17517b59b132SShreeya Patel process_signal_change(hdmirx_dev); 17527b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: avp0_st:%#x\n", 17537b59b132SShreeya Patel __func__, status); 17547b59b132SShreeya Patel *handled = true; 17557b59b132SShreeya Patel } 17567b59b132SShreeya Patel 17577b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); 17587b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_FORCE, 0x0); 17597b59b132SShreeya Patel } 17607b59b132SShreeya Patel 17617b59b132SShreeya Patel static void avpunit_1_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 17627b59b132SShreeya Patel int status, bool *handled) 17637b59b132SShreeya Patel { 17647b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 17657b59b132SShreeya Patel 17667b59b132SShreeya Patel if (status & DEFRAMER_VSYNC_THR_REACHED_IRQ) { 17677b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, 17687b59b132SShreeya Patel "Vertical Sync threshold reached interrupt %#x", status); 17697b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, AVPUNIT_1_INT_MASK_N, 17707b59b132SShreeya Patel DEFRAMER_VSYNC_THR_REACHED_MASK_N, 0); 17717b59b132SShreeya Patel *handled = true; 17727b59b132SShreeya Patel } 17737b59b132SShreeya Patel } 17747b59b132SShreeya Patel 17757b59b132SShreeya Patel static void mainunit_0_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 17767b59b132SShreeya Patel int status, bool *handled) 17777b59b132SShreeya Patel { 17787b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 17797b59b132SShreeya Patel 17807b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "mu0_st:%#x\n", status); 17817b59b132SShreeya Patel if (status & TIMER_BASE_LOCKED_IRQ) { 17827b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 17837b59b132SShreeya Patel TIMER_BASE_LOCKED_IRQ, 0); 17847b59b132SShreeya Patel complete(&hdmirx_dev->timer_base_lock); 17857b59b132SShreeya Patel *handled = true; 17867b59b132SShreeya Patel } 17877b59b132SShreeya Patel 17887b59b132SShreeya Patel if (status & TMDSQPCLK_OFF_CHG) { 17897b59b132SShreeya Patel process_signal_change(hdmirx_dev); 17907b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSQPCLK_OFF_CHG\n", __func__); 17917b59b132SShreeya Patel *handled = true; 17927b59b132SShreeya Patel } 17937b59b132SShreeya Patel 17947b59b132SShreeya Patel if (status & TMDSQPCLK_LOCKED_CHG) { 17957b59b132SShreeya Patel process_signal_change(hdmirx_dev); 17967b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSQPCLK_LOCKED_CHG\n", __func__); 17977b59b132SShreeya Patel *handled = true; 17987b59b132SShreeya Patel } 17997b59b132SShreeya Patel 18007b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); 18017b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_FORCE, 0x0); 18027b59b132SShreeya Patel } 18037b59b132SShreeya Patel 18047b59b132SShreeya Patel static void mainunit_2_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 18057b59b132SShreeya Patel int status, bool *handled) 18067b59b132SShreeya Patel { 18077b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 18087b59b132SShreeya Patel 18097b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "mu2_st:%#x\n", status); 18107b59b132SShreeya Patel if (status & PHYCREG_CR_WRITE_DONE) { 18117b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 18127b59b132SShreeya Patel PHYCREG_CR_WRITE_DONE, 0); 18137b59b132SShreeya Patel complete(&hdmirx_dev->cr_write_done); 18147b59b132SShreeya Patel *handled = true; 18157b59b132SShreeya Patel } 18167b59b132SShreeya Patel 18177b59b132SShreeya Patel if (status & TMDSVALID_STABLE_CHG) { 18187b59b132SShreeya Patel process_signal_change(hdmirx_dev); 18197b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: TMDSVALID_STABLE_CHG\n", __func__); 18207b59b132SShreeya Patel *handled = true; 18217b59b132SShreeya Patel } 18227b59b132SShreeya Patel 18237b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); 18247b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_FORCE, 0x0); 18257b59b132SShreeya Patel } 18267b59b132SShreeya Patel 18277b59b132SShreeya Patel static void pkt_2_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 18287b59b132SShreeya Patel int status, bool *handled) 18297b59b132SShreeya Patel { 18307b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 18317b59b132SShreeya Patel 18327b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: pk2_st:%#x\n", __func__, status); 18337b59b132SShreeya Patel if (status & PKTDEC_AVIIF_RCV_IRQ) { 18347b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, 18357b59b132SShreeya Patel PKTDEC_AVIIF_RCV_IRQ, 0); 18367b59b132SShreeya Patel complete(&hdmirx_dev->avi_pkt_rcv); 18377b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: AVIIF_RCV_IRQ\n", __func__); 18387b59b132SShreeya Patel *handled = true; 18397b59b132SShreeya Patel } 18407b59b132SShreeya Patel 18417b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); 18427b59b132SShreeya Patel } 18437b59b132SShreeya Patel 18447b59b132SShreeya Patel static void scdc_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 18457b59b132SShreeya Patel int status, bool *handled) 18467b59b132SShreeya Patel { 18477b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 18487b59b132SShreeya Patel 18497b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: scdc_st:%#x\n", __func__, status); 18507b59b132SShreeya Patel if (status & SCDCTMDSCCFG_CHG) { 18517b59b132SShreeya Patel hdmirx_tmds_clk_ratio_config(hdmirx_dev); 18527b59b132SShreeya Patel *handled = true; 18537b59b132SShreeya Patel } 18547b59b132SShreeya Patel 18557b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); 18567b59b132SShreeya Patel } 18577b59b132SShreeya Patel 18587b59b132SShreeya Patel static irqreturn_t hdmirx_hdmi_irq_handler(int irq, void *dev_id) 18597b59b132SShreeya Patel { 18607b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_id; 18617b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 18627b59b132SShreeya Patel u32 mu0_st, mu2_st, pk2_st, scdc_st, avp1_st, avp0_st; 18637b59b132SShreeya Patel u32 mu0_mask, mu2_mask, pk2_mask, scdc_mask, avp1_msk, avp0_msk; 18647b59b132SShreeya Patel bool handled = false; 18657b59b132SShreeya Patel 18667b59b132SShreeya Patel mu0_mask = hdmirx_readl(hdmirx_dev, MAINUNIT_0_INT_MASK_N); 18677b59b132SShreeya Patel mu2_mask = hdmirx_readl(hdmirx_dev, MAINUNIT_2_INT_MASK_N); 18687b59b132SShreeya Patel pk2_mask = hdmirx_readl(hdmirx_dev, PKT_2_INT_MASK_N); 18697b59b132SShreeya Patel scdc_mask = hdmirx_readl(hdmirx_dev, SCDC_INT_MASK_N); 18707b59b132SShreeya Patel mu0_st = hdmirx_readl(hdmirx_dev, MAINUNIT_0_INT_STATUS); 18717b59b132SShreeya Patel mu2_st = hdmirx_readl(hdmirx_dev, MAINUNIT_2_INT_STATUS); 18727b59b132SShreeya Patel pk2_st = hdmirx_readl(hdmirx_dev, PKT_2_INT_STATUS); 18737b59b132SShreeya Patel scdc_st = hdmirx_readl(hdmirx_dev, SCDC_INT_STATUS); 18747b59b132SShreeya Patel avp0_st = hdmirx_readl(hdmirx_dev, AVPUNIT_0_INT_STATUS); 18757b59b132SShreeya Patel avp1_st = hdmirx_readl(hdmirx_dev, AVPUNIT_1_INT_STATUS); 18767b59b132SShreeya Patel avp0_msk = hdmirx_readl(hdmirx_dev, AVPUNIT_0_INT_MASK_N); 18777b59b132SShreeya Patel avp1_msk = hdmirx_readl(hdmirx_dev, AVPUNIT_1_INT_MASK_N); 18787b59b132SShreeya Patel mu0_st &= mu0_mask; 18797b59b132SShreeya Patel mu2_st &= mu2_mask; 18807b59b132SShreeya Patel pk2_st &= pk2_mask; 18817b59b132SShreeya Patel avp1_st &= avp1_msk; 18827b59b132SShreeya Patel avp0_st &= avp0_msk; 18837b59b132SShreeya Patel scdc_st &= scdc_mask; 18847b59b132SShreeya Patel 18857b59b132SShreeya Patel if (avp0_st) 18867b59b132SShreeya Patel avpunit_0_int_handler(hdmirx_dev, avp0_st, &handled); 18877b59b132SShreeya Patel if (avp1_st) 18887b59b132SShreeya Patel avpunit_1_int_handler(hdmirx_dev, avp1_st, &handled); 18897b59b132SShreeya Patel if (mu0_st) 18907b59b132SShreeya Patel mainunit_0_int_handler(hdmirx_dev, mu0_st, &handled); 18917b59b132SShreeya Patel if (mu2_st) 18927b59b132SShreeya Patel mainunit_2_int_handler(hdmirx_dev, mu2_st, &handled); 18937b59b132SShreeya Patel if (pk2_st) 18947b59b132SShreeya Patel pkt_2_int_handler(hdmirx_dev, pk2_st, &handled); 18957b59b132SShreeya Patel if (scdc_st) 18967b59b132SShreeya Patel scdc_int_handler(hdmirx_dev, scdc_st, &handled); 18977b59b132SShreeya Patel 18987b59b132SShreeya Patel if (!handled) { 18997b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: hdmi irq not handled", __func__); 19007b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, 19017b59b132SShreeya Patel "avp0:%#x, avp1:%#x, mu0:%#x, mu2:%#x, pk2:%#x, scdc:%#x\n", 19027b59b132SShreeya Patel avp0_st, avp1_st, mu0_st, mu2_st, pk2_st, scdc_st); 19037b59b132SShreeya Patel } 19047b59b132SShreeya Patel 19057b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: en_fiq", __func__); 19067b59b132SShreeya Patel 19077b59b132SShreeya Patel return handled ? IRQ_HANDLED : IRQ_NONE; 19087b59b132SShreeya Patel } 19097b59b132SShreeya Patel 19107b59b132SShreeya Patel static void hdmirx_vb_done(struct hdmirx_stream *stream, 19117b59b132SShreeya Patel struct vb2_v4l2_buffer *vb_done) 19127b59b132SShreeya Patel { 19137b59b132SShreeya Patel const struct v4l2_format_info *finfo = stream->out_finfo; 19147b59b132SShreeya Patel u32 i; 19157b59b132SShreeya Patel 19167b59b132SShreeya Patel /* Dequeue a filled buffer */ 19177b59b132SShreeya Patel for (i = 0; i < finfo->mem_planes; i++) { 19187b59b132SShreeya Patel vb2_set_plane_payload(&vb_done->vb2_buf, i, 19197b59b132SShreeya Patel stream->pixm.plane_fmt[i].sizeimage); 19207b59b132SShreeya Patel } 19217b59b132SShreeya Patel 19227b59b132SShreeya Patel vb_done->vb2_buf.timestamp = ktime_get_ns(); 19237b59b132SShreeya Patel vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); 19247b59b132SShreeya Patel } 19257b59b132SShreeya Patel 19267b59b132SShreeya Patel static void dma_idle_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 19277b59b132SShreeya Patel bool *handled) 19287b59b132SShreeya Patel { 19297b59b132SShreeya Patel struct hdmirx_stream *stream = &hdmirx_dev->stream; 19307b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 19317b59b132SShreeya Patel struct v4l2_dv_timings timings = hdmirx_dev->timings; 19327b59b132SShreeya Patel struct v4l2_bt_timings *bt = &timings.bt; 19337b59b132SShreeya Patel struct vb2_v4l2_buffer *vb_done = NULL; 19347b59b132SShreeya Patel 19357b59b132SShreeya Patel if (!(stream->irq_stat) && !(stream->irq_stat & LINE_FLAG_INT_EN)) 19367b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 19377b59b132SShreeya Patel "%s: last time have no line_flag_irq\n", __func__); 19387b59b132SShreeya Patel 19397b59b132SShreeya Patel /* skip first frames that are expected to come out zeroed from DMA */ 19407b59b132SShreeya Patel if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) 19417b59b132SShreeya Patel goto DMA_IDLE_OUT; 19427b59b132SShreeya Patel 19437b59b132SShreeya Patel if (bt->interlaced != V4L2_DV_INTERLACED || 19447b59b132SShreeya Patel !(stream->line_flag_int_cnt % 2)) { 19457b59b132SShreeya Patel if (stream->next_buf) { 19467b59b132SShreeya Patel if (stream->curr_buf) 19477b59b132SShreeya Patel vb_done = &stream->curr_buf->vb; 19487b59b132SShreeya Patel 19497b59b132SShreeya Patel if (vb_done) { 19507b59b132SShreeya Patel vb_done->vb2_buf.timestamp = ktime_get_ns(); 19510400bee6SNicolas Dufresne vb_done->sequence = stream->sequence; 19527b59b132SShreeya Patel 19537b59b132SShreeya Patel if (bt->interlaced) 19547b59b132SShreeya Patel vb_done->field = V4L2_FIELD_INTERLACED_TB; 19557b59b132SShreeya Patel else 19567b59b132SShreeya Patel vb_done->field = V4L2_FIELD_NONE; 19577b59b132SShreeya Patel 19587b59b132SShreeya Patel hdmirx_vb_done(stream, vb_done); 19597b59b132SShreeya Patel } 19607b59b132SShreeya Patel 19617b59b132SShreeya Patel stream->curr_buf = NULL; 19627b59b132SShreeya Patel if (stream->next_buf) { 19637b59b132SShreeya Patel stream->curr_buf = stream->next_buf; 19647b59b132SShreeya Patel stream->next_buf = NULL; 19657b59b132SShreeya Patel } 19667b59b132SShreeya Patel } else { 19677b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, 19687b59b132SShreeya Patel "%s: next_buf NULL, skip vb_done\n", __func__); 19697b59b132SShreeya Patel } 1970*57c8d79aSNicolas Dufresne 1971*57c8d79aSNicolas Dufresne stream->sequence++; 1972*57c8d79aSNicolas Dufresne if (stream->sequence == 30) 1973*57c8d79aSNicolas Dufresne v4l2_dbg(1, debug, v4l2_dev, "rcv frames\n"); 19747b59b132SShreeya Patel } 19757b59b132SShreeya Patel 19767b59b132SShreeya Patel DMA_IDLE_OUT: 19777b59b132SShreeya Patel *handled = true; 19787b59b132SShreeya Patel } 19797b59b132SShreeya Patel 19807b59b132SShreeya Patel static void line_flag_int_handler(struct snps_hdmirx_dev *hdmirx_dev, 19817b59b132SShreeya Patel bool *handled) 19827b59b132SShreeya Patel { 19837b59b132SShreeya Patel struct hdmirx_stream *stream = &hdmirx_dev->stream; 19847b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 19857b59b132SShreeya Patel struct v4l2_dv_timings timings = hdmirx_dev->timings; 19867b59b132SShreeya Patel struct v4l2_bt_timings *bt = &timings.bt; 19877b59b132SShreeya Patel u32 dma_cfg6; 19887b59b132SShreeya Patel 19897b59b132SShreeya Patel stream->line_flag_int_cnt++; 19907b59b132SShreeya Patel if (!(stream->irq_stat) && !(stream->irq_stat & HDMIRX_DMA_IDLE_INT)) 19917b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 19927b59b132SShreeya Patel "%s: last have no dma_idle_irq\n", __func__); 19937b59b132SShreeya Patel dma_cfg6 = hdmirx_readl(hdmirx_dev, DMA_CONFIG6); 19947b59b132SShreeya Patel if (!(dma_cfg6 & HDMIRX_DMA_EN)) { 19957b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: dma not on\n", __func__); 19967b59b132SShreeya Patel goto LINE_FLAG_OUT; 19977b59b132SShreeya Patel } 19987b59b132SShreeya Patel 19997b59b132SShreeya Patel if (stream->line_flag_int_cnt <= FILTER_FRAME_CNT) 20007b59b132SShreeya Patel goto LINE_FLAG_OUT; 20017b59b132SShreeya Patel 20027b59b132SShreeya Patel if (bt->interlaced != V4L2_DV_INTERLACED || 20037b59b132SShreeya Patel !(stream->line_flag_int_cnt % 2)) { 20047b59b132SShreeya Patel if (!stream->next_buf) { 20057b59b132SShreeya Patel spin_lock(&stream->vbq_lock); 20067b59b132SShreeya Patel if (!list_empty(&stream->buf_head)) { 20077b59b132SShreeya Patel stream->next_buf = list_first_entry(&stream->buf_head, 20087b59b132SShreeya Patel struct hdmirx_buffer, 20097b59b132SShreeya Patel queue); 20107b59b132SShreeya Patel list_del(&stream->next_buf->queue); 20117b59b132SShreeya Patel } else { 20127b59b132SShreeya Patel stream->next_buf = NULL; 20137b59b132SShreeya Patel } 20147b59b132SShreeya Patel spin_unlock(&stream->vbq_lock); 20157b59b132SShreeya Patel 20167b59b132SShreeya Patel if (stream->next_buf) { 20177b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG2, 20187b59b132SShreeya Patel stream->next_buf->buff_addr[HDMIRX_PLANE_Y]); 20197b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG3, 20207b59b132SShreeya Patel stream->next_buf->buff_addr[HDMIRX_PLANE_CBCR]); 20217b59b132SShreeya Patel } else { 20227b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, 20237b59b132SShreeya Patel "%s: no buffer is available\n", __func__); 20247b59b132SShreeya Patel } 20257b59b132SShreeya Patel } 20267b59b132SShreeya Patel } else { 20277b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, "%s: interlace:%d, line_flag_int_cnt:%d\n", 20287b59b132SShreeya Patel __func__, bt->interlaced, stream->line_flag_int_cnt); 20297b59b132SShreeya Patel } 20307b59b132SShreeya Patel 20317b59b132SShreeya Patel LINE_FLAG_OUT: 20327b59b132SShreeya Patel *handled = true; 20337b59b132SShreeya Patel } 20347b59b132SShreeya Patel 20357b59b132SShreeya Patel static irqreturn_t hdmirx_dma_irq_handler(int irq, void *dev_id) 20367b59b132SShreeya Patel { 20377b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_id; 20387b59b132SShreeya Patel struct hdmirx_stream *stream = &hdmirx_dev->stream; 20397b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 20407b59b132SShreeya Patel u32 dma_stat1, dma_stat13; 20417b59b132SShreeya Patel bool handled = false; 20427b59b132SShreeya Patel 20437b59b132SShreeya Patel dma_stat1 = hdmirx_readl(hdmirx_dev, DMA_STATUS1); 20447b59b132SShreeya Patel dma_stat13 = hdmirx_readl(hdmirx_dev, DMA_STATUS13); 20457b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, "dma_irq st1:%#x, st13:%d\n", 20467b59b132SShreeya Patel dma_stat1, dma_stat13); 20477b59b132SShreeya Patel 20487b59b132SShreeya Patel if (READ_ONCE(stream->stopping)) { 20497b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: stop stream\n", __func__); 20507b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); 20517b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, DMA_CONFIG4, 20527b59b132SShreeya Patel LINE_FLAG_INT_EN | 20537b59b132SShreeya Patel HDMIRX_DMA_IDLE_INT | 20547b59b132SShreeya Patel HDMIRX_LOCK_DISABLE_INT | 20557b59b132SShreeya Patel LAST_FRAME_AXI_UNFINISH_INT_EN | 20567b59b132SShreeya Patel FIFO_OVERFLOW_INT_EN | 20577b59b132SShreeya Patel FIFO_UNDERFLOW_INT_EN | 20587b59b132SShreeya Patel HDMIRX_AXI_ERROR_INT_EN, 0); 20597b59b132SShreeya Patel WRITE_ONCE(stream->stopping, false); 20607b59b132SShreeya Patel wake_up(&stream->wq_stopped); 20617b59b132SShreeya Patel return IRQ_HANDLED; 20627b59b132SShreeya Patel } 20637b59b132SShreeya Patel 20647b59b132SShreeya Patel if (dma_stat1 & HDMIRX_DMA_IDLE_INT) 20657b59b132SShreeya Patel dma_idle_int_handler(hdmirx_dev, &handled); 20667b59b132SShreeya Patel 20677b59b132SShreeya Patel if (dma_stat1 & LINE_FLAG_INT_EN) 20687b59b132SShreeya Patel line_flag_int_handler(hdmirx_dev, &handled); 20697b59b132SShreeya Patel 20707b59b132SShreeya Patel if (!handled) 20717b59b132SShreeya Patel v4l2_dbg(3, debug, v4l2_dev, 20727b59b132SShreeya Patel "%s: dma irq not handled, dma_stat1:%#x\n", 20737b59b132SShreeya Patel __func__, dma_stat1); 20747b59b132SShreeya Patel 20757b59b132SShreeya Patel stream->irq_stat = dma_stat1; 20767b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, DMA_CONFIG5, 0xffffffff); 20777b59b132SShreeya Patel 20787b59b132SShreeya Patel return IRQ_HANDLED; 20797b59b132SShreeya Patel } 20807b59b132SShreeya Patel 20817b59b132SShreeya Patel static int hdmirx_wait_signal_lock(struct snps_hdmirx_dev *hdmirx_dev) 20827b59b132SShreeya Patel { 20837b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 20847b59b132SShreeya Patel u32 mu_status, scdc_status, dma_st10, cmu_st; 20857b59b132SShreeya Patel u32 i; 20867b59b132SShreeya Patel 20877b59b132SShreeya Patel for (i = 0; i < 300; i++) { 20887b59b132SShreeya Patel mu_status = hdmirx_readl(hdmirx_dev, MAINUNIT_STATUS); 20897b59b132SShreeya Patel scdc_status = hdmirx_readl(hdmirx_dev, SCDC_REGBANK_STATUS3); 20907b59b132SShreeya Patel dma_st10 = hdmirx_readl(hdmirx_dev, DMA_STATUS10); 20917b59b132SShreeya Patel cmu_st = hdmirx_readl(hdmirx_dev, CMU_STATUS); 20927b59b132SShreeya Patel 20937b59b132SShreeya Patel if ((mu_status & TMDSVALID_STABLE_ST) && 20947b59b132SShreeya Patel (dma_st10 & HDMIRX_LOCK) && 20957b59b132SShreeya Patel (cmu_st & TMDSQPCLK_LOCKED_ST)) 20967b59b132SShreeya Patel break; 20977b59b132SShreeya Patel 20987b59b132SShreeya Patel if (!tx_5v_power_present(hdmirx_dev)) { 20997b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, 21007b59b132SShreeya Patel "%s: HDMI pull out, return\n", __func__); 21017b59b132SShreeya Patel return -1; 21027b59b132SShreeya Patel } 21037b59b132SShreeya Patel 21047b59b132SShreeya Patel hdmirx_tmds_clk_ratio_config(hdmirx_dev); 21057b59b132SShreeya Patel } 21067b59b132SShreeya Patel 21077b59b132SShreeya Patel if (i == 300) { 21087b59b132SShreeya Patel v4l2_err(v4l2_dev, "%s: signal not lock, tmds_clk_ratio:%d\n", 21097b59b132SShreeya Patel __func__, hdmirx_dev->tmds_clk_ratio); 21107b59b132SShreeya Patel v4l2_err(v4l2_dev, "%s: mu_st:%#x, scdc_st:%#x, dma_st10:%#x\n", 21117b59b132SShreeya Patel __func__, mu_status, scdc_status, dma_st10); 21127b59b132SShreeya Patel return -1; 21137b59b132SShreeya Patel } 21147b59b132SShreeya Patel 21157b59b132SShreeya Patel v4l2_dbg(1, debug, v4l2_dev, "%s: signal lock ok, i:%d\n", __func__, i); 21167b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, GLOBAL_SWRESET_REQUEST, DATAPATH_SWRESETREQ); 21177b59b132SShreeya Patel 21187b59b132SShreeya Patel reinit_completion(&hdmirx_dev->avi_pkt_rcv); 21197b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); 21207b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, 21217b59b132SShreeya Patel PKTDEC_AVIIF_RCV_IRQ, PKTDEC_AVIIF_RCV_IRQ); 21227b59b132SShreeya Patel 21237b59b132SShreeya Patel if (!wait_for_completion_timeout(&hdmirx_dev->avi_pkt_rcv, 21247b59b132SShreeya Patel msecs_to_jiffies(300))) { 21257b59b132SShreeya Patel v4l2_err(v4l2_dev, "%s wait avi_pkt_rcv failed\n", __func__); 21267b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PKT_2_INT_MASK_N, 21277b59b132SShreeya Patel PKTDEC_AVIIF_RCV_IRQ, 0); 21287b59b132SShreeya Patel } 21297b59b132SShreeya Patel 21307b59b132SShreeya Patel msleep(50); 21317b59b132SShreeya Patel hdmirx_format_change(hdmirx_dev); 21327b59b132SShreeya Patel 21337b59b132SShreeya Patel return 0; 21347b59b132SShreeya Patel } 21357b59b132SShreeya Patel 21367b59b132SShreeya Patel static void hdmirx_plugin(struct snps_hdmirx_dev *hdmirx_dev) 21377b59b132SShreeya Patel { 21387b59b132SShreeya Patel if (hdmirx_dev->plugged) 21397b59b132SShreeya Patel return; 21407b59b132SShreeya Patel 21417b59b132SShreeya Patel hdmirx_submodule_init(hdmirx_dev); 21427b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 21437b59b132SShreeya Patel POWERPROVIDED); 21447b59b132SShreeya Patel hdmirx_phy_config(hdmirx_dev); 21457b59b132SShreeya Patel hdmirx_interrupts_setup(hdmirx_dev, true); 21467b59b132SShreeya Patel 21477b59b132SShreeya Patel hdmirx_dev->plugged = true; 21487b59b132SShreeya Patel } 21497b59b132SShreeya Patel 21507b59b132SShreeya Patel static void hdmirx_delayed_work_hotplug(struct work_struct *work) 21517b59b132SShreeya Patel { 21527b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev; 21537b59b132SShreeya Patel bool plugin; 21547b59b132SShreeya Patel 21557b59b132SShreeya Patel hdmirx_dev = container_of(work, struct snps_hdmirx_dev, 21567b59b132SShreeya Patel delayed_work_hotplug.work); 21577b59b132SShreeya Patel 21587b59b132SShreeya Patel mutex_lock(&hdmirx_dev->work_lock); 21597b59b132SShreeya Patel plugin = tx_5v_power_present(hdmirx_dev); 21607b59b132SShreeya Patel v4l2_ctrl_s_ctrl(hdmirx_dev->detect_tx_5v_ctrl, plugin); 21617b59b132SShreeya Patel v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: plugin:%d\n", 21627b59b132SShreeya Patel __func__, plugin); 21637b59b132SShreeya Patel 21647b59b132SShreeya Patel hdmirx_plugout(hdmirx_dev); 21657b59b132SShreeya Patel 21667b59b132SShreeya Patel if (plugin) 21677b59b132SShreeya Patel hdmirx_plugin(hdmirx_dev); 21687b59b132SShreeya Patel 21697b59b132SShreeya Patel mutex_unlock(&hdmirx_dev->work_lock); 21707b59b132SShreeya Patel } 21717b59b132SShreeya Patel 21727b59b132SShreeya Patel static void hdmirx_delayed_work_res_change(struct work_struct *work) 21737b59b132SShreeya Patel { 21747b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev; 21757b59b132SShreeya Patel bool plugin; 21767b59b132SShreeya Patel 21777b59b132SShreeya Patel hdmirx_dev = container_of(work, struct snps_hdmirx_dev, 21787b59b132SShreeya Patel delayed_work_res_change.work); 21797b59b132SShreeya Patel 21807b59b132SShreeya Patel mutex_lock(&hdmirx_dev->work_lock); 21817b59b132SShreeya Patel plugin = tx_5v_power_present(hdmirx_dev); 21827b59b132SShreeya Patel v4l2_dbg(1, debug, &hdmirx_dev->v4l2_dev, "%s: plugin:%d\n", 21837b59b132SShreeya Patel __func__, plugin); 21847b59b132SShreeya Patel if (plugin) { 21857b59b132SShreeya Patel hdmirx_interrupts_setup(hdmirx_dev, false); 21867b59b132SShreeya Patel hdmirx_submodule_init(hdmirx_dev); 21877b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, SCDC_CONFIG, POWERPROVIDED, 21887b59b132SShreeya Patel POWERPROVIDED); 21897b59b132SShreeya Patel hdmirx_phy_config(hdmirx_dev); 21907b59b132SShreeya Patel 21917b59b132SShreeya Patel if (hdmirx_wait_signal_lock(hdmirx_dev)) { 21927b59b132SShreeya Patel hdmirx_plugout(hdmirx_dev); 21937b59b132SShreeya Patel queue_delayed_work(system_unbound_wq, 21947b59b132SShreeya Patel &hdmirx_dev->delayed_work_hotplug, 21957b59b132SShreeya Patel msecs_to_jiffies(200)); 21967b59b132SShreeya Patel } else { 21977b59b132SShreeya Patel hdmirx_dma_config(hdmirx_dev); 21987b59b132SShreeya Patel hdmirx_interrupts_setup(hdmirx_dev, true); 21997b59b132SShreeya Patel } 22007b59b132SShreeya Patel } 22017b59b132SShreeya Patel mutex_unlock(&hdmirx_dev->work_lock); 22027b59b132SShreeya Patel } 22037b59b132SShreeya Patel 22047b59b132SShreeya Patel static irqreturn_t hdmirx_5v_det_irq_handler(int irq, void *dev_id) 22057b59b132SShreeya Patel { 22067b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_id; 22077b59b132SShreeya Patel u32 val; 22087b59b132SShreeya Patel 22097b59b132SShreeya Patel val = gpiod_get_value(hdmirx_dev->detect_5v_gpio); 22107b59b132SShreeya Patel v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: 5v:%d\n", __func__, val); 22117b59b132SShreeya Patel 22127b59b132SShreeya Patel queue_delayed_work(system_unbound_wq, 22137b59b132SShreeya Patel &hdmirx_dev->delayed_work_hotplug, 22147b59b132SShreeya Patel msecs_to_jiffies(10)); 22157b59b132SShreeya Patel 22167b59b132SShreeya Patel return IRQ_HANDLED; 22177b59b132SShreeya Patel } 22187b59b132SShreeya Patel 22197b59b132SShreeya Patel static const struct hdmirx_cec_ops hdmirx_cec_ops = { 22207b59b132SShreeya Patel .write = hdmirx_writel, 22217b59b132SShreeya Patel .read = hdmirx_readl, 22227b59b132SShreeya Patel }; 22237b59b132SShreeya Patel 22247b59b132SShreeya Patel static void devm_hdmirx_of_reserved_mem_device_release(void *dev) 22257b59b132SShreeya Patel { 22267b59b132SShreeya Patel of_reserved_mem_device_release(dev); 22277b59b132SShreeya Patel } 22287b59b132SShreeya Patel 22297b59b132SShreeya Patel static int hdmirx_parse_dt(struct snps_hdmirx_dev *hdmirx_dev) 22307b59b132SShreeya Patel { 22317b59b132SShreeya Patel struct device *dev = hdmirx_dev->dev; 22327b59b132SShreeya Patel int ret; 22337b59b132SShreeya Patel 22347b59b132SShreeya Patel hdmirx_dev->num_clks = devm_clk_bulk_get_all(dev, &hdmirx_dev->clks); 22357b59b132SShreeya Patel if (hdmirx_dev->num_clks < 1) 22367b59b132SShreeya Patel return -ENODEV; 22377b59b132SShreeya Patel 22387b59b132SShreeya Patel hdmirx_dev->resets[HDMIRX_RST_A].id = "axi"; 22397b59b132SShreeya Patel hdmirx_dev->resets[HDMIRX_RST_P].id = "apb"; 22407b59b132SShreeya Patel hdmirx_dev->resets[HDMIRX_RST_REF].id = "ref"; 22417b59b132SShreeya Patel hdmirx_dev->resets[HDMIRX_RST_BIU].id = "biu"; 22427b59b132SShreeya Patel 22437b59b132SShreeya Patel ret = devm_reset_control_bulk_get_exclusive(dev, HDMIRX_NUM_RST, 22447b59b132SShreeya Patel hdmirx_dev->resets); 22457b59b132SShreeya Patel if (ret < 0) { 22467b59b132SShreeya Patel dev_err(dev, "failed to get reset controls\n"); 22477b59b132SShreeya Patel return ret; 22487b59b132SShreeya Patel } 22497b59b132SShreeya Patel 22507b59b132SShreeya Patel hdmirx_dev->detect_5v_gpio = 22517b59b132SShreeya Patel devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); 22527b59b132SShreeya Patel 22537b59b132SShreeya Patel if (IS_ERR(hdmirx_dev->detect_5v_gpio)) { 22547b59b132SShreeya Patel dev_err(dev, "failed to get hdmirx hot plug detection gpio\n"); 22557b59b132SShreeya Patel return PTR_ERR(hdmirx_dev->detect_5v_gpio); 22567b59b132SShreeya Patel } 22577b59b132SShreeya Patel 22587b59b132SShreeya Patel hdmirx_dev->grf = syscon_regmap_lookup_by_phandle(dev->of_node, 22597b59b132SShreeya Patel "rockchip,grf"); 22607b59b132SShreeya Patel if (IS_ERR(hdmirx_dev->grf)) { 22617b59b132SShreeya Patel dev_err(dev, "failed to get rockchip,grf\n"); 22627b59b132SShreeya Patel return PTR_ERR(hdmirx_dev->grf); 22637b59b132SShreeya Patel } 22647b59b132SShreeya Patel 22657b59b132SShreeya Patel hdmirx_dev->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, 22667b59b132SShreeya Patel "rockchip,vo1-grf"); 22677b59b132SShreeya Patel if (IS_ERR(hdmirx_dev->vo1_grf)) { 22687b59b132SShreeya Patel dev_err(dev, "failed to get rockchip,vo1-grf\n"); 22697b59b132SShreeya Patel return PTR_ERR(hdmirx_dev->vo1_grf); 22707b59b132SShreeya Patel } 22717b59b132SShreeya Patel 22727b59b132SShreeya Patel if (!device_property_read_bool(dev, "hpd-is-active-low")) 22737b59b132SShreeya Patel hdmirx_dev->hpd_trigger_level_high = true; 22747b59b132SShreeya Patel 22757b59b132SShreeya Patel ret = of_reserved_mem_device_init(dev); 22767b59b132SShreeya Patel if (ret) { 22777b59b132SShreeya Patel dev_warn(dev, "no reserved memory for HDMIRX, use default CMA\n"); 22787b59b132SShreeya Patel } else { 22797b59b132SShreeya Patel ret = devm_add_action_or_reset(dev, 22807b59b132SShreeya Patel devm_hdmirx_of_reserved_mem_device_release, 22817b59b132SShreeya Patel dev); 22827b59b132SShreeya Patel if (ret) 22837b59b132SShreeya Patel return ret; 22847b59b132SShreeya Patel } 22857b59b132SShreeya Patel 22867b59b132SShreeya Patel return 0; 22877b59b132SShreeya Patel } 22887b59b132SShreeya Patel 22897b59b132SShreeya Patel static void hdmirx_disable_all_interrupts(struct snps_hdmirx_dev *hdmirx_dev) 22907b59b132SShreeya Patel { 22917b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, MAINUNIT_0_INT_MASK_N, 0); 22927b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, MAINUNIT_1_INT_MASK_N, 0); 22937b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, MAINUNIT_2_INT_MASK_N, 0); 22947b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, AVPUNIT_0_INT_MASK_N, 0); 22957b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, AVPUNIT_1_INT_MASK_N, 0); 22967b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PKT_0_INT_MASK_N, 0); 22977b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PKT_1_INT_MASK_N, 0); 22987b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, PKT_2_INT_MASK_N, 0); 22997b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, SCDC_INT_MASK_N, 0); 23007b59b132SShreeya Patel hdmirx_writel(hdmirx_dev, CEC_INT_MASK_N, 0); 23017b59b132SShreeya Patel 23027b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_0_INT_CLEAR, 0xffffffff); 23037b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_1_INT_CLEAR, 0xffffffff); 23047b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, MAINUNIT_2_INT_CLEAR, 0xffffffff); 23057b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_0_INT_CLEAR, 0xffffffff); 23067b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, AVPUNIT_1_INT_CLEAR, 0xffffffff); 23077b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, PKT_0_INT_CLEAR, 0xffffffff); 23087b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, PKT_1_INT_CLEAR, 0xffffffff); 23097b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, PKT_2_INT_CLEAR, 0xffffffff); 23107b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, SCDC_INT_CLEAR, 0xffffffff); 23117b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, HDCP_INT_CLEAR, 0xffffffff); 23127b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, HDCP_1_INT_CLEAR, 0xffffffff); 23137b59b132SShreeya Patel hdmirx_clear_interrupt(hdmirx_dev, CEC_INT_CLEAR, 0xffffffff); 23147b59b132SShreeya Patel } 23157b59b132SShreeya Patel 23167b59b132SShreeya Patel static void hdmirx_init(struct snps_hdmirx_dev *hdmirx_dev) 23177b59b132SShreeya Patel { 23187b59b132SShreeya Patel hdmirx_update_bits(hdmirx_dev, PHY_CONFIG, PHY_RESET | PHY_PDDQ, 0); 23197b59b132SShreeya Patel 23207b59b132SShreeya Patel regmap_write(hdmirx_dev->vo1_grf, VO1_GRF_VO1_CON2, 23217b59b132SShreeya Patel (HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) | 23227b59b132SShreeya Patel ((HDMIRX_SDAIN_MSK | HDMIRX_SCLIN_MSK) << 16)); 23237b59b132SShreeya Patel /* 23247b59b132SShreeya Patel * Some interrupts are enabled by default, so we disable 23257b59b132SShreeya Patel * all interrupts and clear interrupts status first. 23267b59b132SShreeya Patel */ 23277b59b132SShreeya Patel hdmirx_disable_all_interrupts(hdmirx_dev); 23287b59b132SShreeya Patel } 23297b59b132SShreeya Patel 23307b59b132SShreeya Patel /* hdmi-4k-300mhz EDID produced by v4l2-ctl tool */ 23317b59b132SShreeya Patel static u8 __maybe_unused edid_default[] = { 23327b59b132SShreeya Patel 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 23337b59b132SShreeya Patel 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 23347b59b132SShreeya Patel 0x22, 0x1a, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78, 23357b59b132SShreeya Patel 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 23367b59b132SShreeya Patel 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59, 23377b59b132SShreeya Patel 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40, 23387b59b132SShreeya Patel 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x04, 0x74, 23397b59b132SShreeya Patel 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58, 23407b59b132SShreeya Patel 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e, 23417b59b132SShreeya Patel 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, 23427b59b132SShreeya Patel 0x87, 0x1e, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 23437b59b132SShreeya Patel 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x68, 23447b59b132SShreeya Patel 0x64, 0x6d, 0x69, 0x2d, 0x34, 0x6b, 0x2d, 0x33, 23457b59b132SShreeya Patel 0x30, 0x30, 0x0a, 0x20, 0x00, 0x00, 0x00, 0x10, 23467b59b132SShreeya Patel 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23477b59b132SShreeya Patel 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc5, 23487b59b132SShreeya Patel 23497b59b132SShreeya Patel 0x02, 0x03, 0x40, 0xf1, 0x4f, 0x5f, 0x5e, 0x5d, 23507b59b132SShreeya Patel 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, 0x20, 0x05, 23517b59b132SShreeya Patel 0x14, 0x02, 0x11, 0x01, 0x23, 0x09, 0x07, 0x07, 23527b59b132SShreeya Patel 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03, 0x0c, 0x00, 23537b59b132SShreeya Patel 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00, 0x60, 0x01, 23547b59b132SShreeya Patel 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 23557b59b132SShreeya Patel 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x05, 0x00, 23567b59b132SShreeya Patel 0x00, 0xe3, 0x06, 0x01, 0x00, 0xe2, 0x0d, 0x5f, 23577b59b132SShreeya Patel 0xa3, 0x66, 0x00, 0xa0, 0xf0, 0x70, 0x1f, 0x80, 23587b59b132SShreeya Patel 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 23597b59b132SShreeya Patel 0x00, 0x1e, 0x1a, 0x36, 0x80, 0xa0, 0x70, 0x38, 23607b59b132SShreeya Patel 0x1f, 0x40, 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c, 23617b59b132SShreeya Patel 0x32, 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 23627b59b132SShreeya Patel 0x51, 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 23637b59b132SShreeya Patel 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 23647b59b132SShreeya Patel 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 23657b59b132SShreeya Patel }; 23667b59b132SShreeya Patel 23677b59b132SShreeya Patel static void hdmirx_load_default_edid(struct snps_hdmirx_dev *hdmirx_dev) 23687b59b132SShreeya Patel { 23697b59b132SShreeya Patel struct v4l2_edid def_edid = {}; 23707b59b132SShreeya Patel 23717b59b132SShreeya Patel hdmirx_hpd_ctrl(hdmirx_dev, false); 23727b59b132SShreeya Patel 23737b59b132SShreeya Patel if (!IS_ENABLED(CONFIG_VIDEO_SYNOPSYS_HDMIRX_LOAD_DEFAULT_EDID)) 23747b59b132SShreeya Patel return; 23757b59b132SShreeya Patel 23767b59b132SShreeya Patel /* disable hpd and write edid */ 23777b59b132SShreeya Patel def_edid.blocks = sizeof(edid_default) / EDID_BLOCK_SIZE; 23787b59b132SShreeya Patel def_edid.edid = edid_default; 23797b59b132SShreeya Patel 23807b59b132SShreeya Patel hdmirx_write_edid(hdmirx_dev, &def_edid); 23817b59b132SShreeya Patel hdmirx_hpd_ctrl(hdmirx_dev, true); 23827b59b132SShreeya Patel } 23837b59b132SShreeya Patel 23847b59b132SShreeya Patel static int hdmirx_disable(struct device *dev) 23857b59b132SShreeya Patel { 23867b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); 23877b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 23887b59b132SShreeya Patel 23897b59b132SShreeya Patel hdmirx_plugout(hdmirx_dev); 23907b59b132SShreeya Patel hdmirx_hpd_ctrl(hdmirx_dev, false); 23917b59b132SShreeya Patel 23927b59b132SShreeya Patel clk_bulk_disable_unprepare(hdmirx_dev->num_clks, hdmirx_dev->clks); 23937b59b132SShreeya Patel 23947b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: suspend\n", __func__); 23957b59b132SShreeya Patel 23967b59b132SShreeya Patel return pinctrl_pm_select_sleep_state(dev); 23977b59b132SShreeya Patel } 23987b59b132SShreeya Patel 23997b59b132SShreeya Patel static int hdmirx_enable(struct device *dev) 24007b59b132SShreeya Patel { 24017b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); 24027b59b132SShreeya Patel struct v4l2_device *v4l2_dev = &hdmirx_dev->v4l2_dev; 24037b59b132SShreeya Patel int ret; 24047b59b132SShreeya Patel 24057b59b132SShreeya Patel v4l2_dbg(2, debug, v4l2_dev, "%s: resume\n", __func__); 24067b59b132SShreeya Patel ret = pinctrl_pm_select_default_state(dev); 24077b59b132SShreeya Patel if (ret < 0) 24087b59b132SShreeya Patel return ret; 24097b59b132SShreeya Patel 24107b59b132SShreeya Patel ret = clk_bulk_prepare_enable(hdmirx_dev->num_clks, hdmirx_dev->clks); 24117b59b132SShreeya Patel if (ret) { 24127b59b132SShreeya Patel dev_err(dev, "failed to enable hdmirx bulk clks: %d\n", ret); 24137b59b132SShreeya Patel return ret; 24147b59b132SShreeya Patel } 24157b59b132SShreeya Patel 24167b59b132SShreeya Patel reset_control_bulk_assert(HDMIRX_NUM_RST, hdmirx_dev->resets); 24177b59b132SShreeya Patel usleep_range(150, 160); 24187b59b132SShreeya Patel reset_control_bulk_deassert(HDMIRX_NUM_RST, hdmirx_dev->resets); 24197b59b132SShreeya Patel usleep_range(150, 160); 24207b59b132SShreeya Patel 24217b59b132SShreeya Patel return 0; 24227b59b132SShreeya Patel } 24237b59b132SShreeya Patel 24247b59b132SShreeya Patel static void hdmirx_disable_irq(struct device *dev) 24257b59b132SShreeya Patel { 24267b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); 24277b59b132SShreeya Patel 24287b59b132SShreeya Patel disable_irq(hdmirx_dev->det_irq); 24297b59b132SShreeya Patel disable_irq(hdmirx_dev->dma_irq); 24307b59b132SShreeya Patel disable_irq(hdmirx_dev->hdmi_irq); 24317b59b132SShreeya Patel 24327b59b132SShreeya Patel cancel_delayed_work_sync(&hdmirx_dev->delayed_work_hotplug); 24337b59b132SShreeya Patel cancel_delayed_work_sync(&hdmirx_dev->delayed_work_res_change); 24347b59b132SShreeya Patel } 24357b59b132SShreeya Patel 24367b59b132SShreeya Patel static void hdmirx_enable_irq(struct device *dev) 24377b59b132SShreeya Patel { 24387b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); 24397b59b132SShreeya Patel 24407b59b132SShreeya Patel enable_irq(hdmirx_dev->hdmi_irq); 24417b59b132SShreeya Patel enable_irq(hdmirx_dev->dma_irq); 24427b59b132SShreeya Patel enable_irq(hdmirx_dev->det_irq); 24437b59b132SShreeya Patel 24447b59b132SShreeya Patel queue_delayed_work(system_unbound_wq, 24457b59b132SShreeya Patel &hdmirx_dev->delayed_work_hotplug, 24467b59b132SShreeya Patel msecs_to_jiffies(110)); 24477b59b132SShreeya Patel } 24487b59b132SShreeya Patel 24497b59b132SShreeya Patel static __maybe_unused int hdmirx_suspend(struct device *dev) 24507b59b132SShreeya Patel { 24517b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); 24527b59b132SShreeya Patel 24537b59b132SShreeya Patel hdmirx_disable_irq(dev); 24547b59b132SShreeya Patel 24557b59b132SShreeya Patel /* TODO store CEC HW state */ 24567b59b132SShreeya Patel disable_irq(hdmirx_dev->cec->irq); 24577b59b132SShreeya Patel 24587b59b132SShreeya Patel return hdmirx_disable(dev); 24597b59b132SShreeya Patel } 24607b59b132SShreeya Patel 24617b59b132SShreeya Patel static __maybe_unused int hdmirx_resume(struct device *dev) 24627b59b132SShreeya Patel { 24637b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); 24647b59b132SShreeya Patel int ret = hdmirx_enable(dev); 24657b59b132SShreeya Patel 24667b59b132SShreeya Patel if (ret) 24677b59b132SShreeya Patel return ret; 24687b59b132SShreeya Patel 24697b59b132SShreeya Patel if (hdmirx_dev->edid_blocks_written) { 24707b59b132SShreeya Patel hdmirx_write_edid_data(hdmirx_dev, hdmirx_dev->edid, 24717b59b132SShreeya Patel hdmirx_dev->edid_blocks_written); 24727b59b132SShreeya Patel hdmirx_hpd_ctrl(hdmirx_dev, true); 24737b59b132SShreeya Patel } 24747b59b132SShreeya Patel 24757b59b132SShreeya Patel /* TODO restore CEC HW state */ 24767b59b132SShreeya Patel enable_irq(hdmirx_dev->cec->irq); 24777b59b132SShreeya Patel 24787b59b132SShreeya Patel hdmirx_enable_irq(dev); 24797b59b132SShreeya Patel 24807b59b132SShreeya Patel return 0; 24817b59b132SShreeya Patel } 24827b59b132SShreeya Patel 24837b59b132SShreeya Patel static const struct dev_pm_ops snps_hdmirx_pm_ops = { 24847b59b132SShreeya Patel SET_SYSTEM_SLEEP_PM_OPS(hdmirx_suspend, hdmirx_resume) 24857b59b132SShreeya Patel }; 24867b59b132SShreeya Patel 24877b59b132SShreeya Patel static int hdmirx_setup_irq(struct snps_hdmirx_dev *hdmirx_dev, 24887b59b132SShreeya Patel struct platform_device *pdev) 24897b59b132SShreeya Patel { 24907b59b132SShreeya Patel struct device *dev = hdmirx_dev->dev; 24917b59b132SShreeya Patel int ret, irq; 24927b59b132SShreeya Patel 24937b59b132SShreeya Patel irq = platform_get_irq_byname(pdev, "hdmi"); 24947b59b132SShreeya Patel if (irq < 0) { 24957b59b132SShreeya Patel dev_err_probe(dev, irq, "failed to get hdmi irq\n"); 24967b59b132SShreeya Patel return irq; 24977b59b132SShreeya Patel } 24987b59b132SShreeya Patel 24997b59b132SShreeya Patel irq_set_status_flags(irq, IRQ_NOAUTOEN); 25007b59b132SShreeya Patel 25017b59b132SShreeya Patel hdmirx_dev->hdmi_irq = irq; 25027b59b132SShreeya Patel ret = devm_request_irq(dev, irq, hdmirx_hdmi_irq_handler, 0, 25037b59b132SShreeya Patel "rk_hdmirx-hdmi", hdmirx_dev); 25047b59b132SShreeya Patel if (ret) { 25057b59b132SShreeya Patel dev_err_probe(dev, ret, "failed to request hdmi irq\n"); 25067b59b132SShreeya Patel return ret; 25077b59b132SShreeya Patel } 25087b59b132SShreeya Patel 25097b59b132SShreeya Patel irq = platform_get_irq_byname(pdev, "dma"); 25107b59b132SShreeya Patel if (irq < 0) { 25117b59b132SShreeya Patel dev_err_probe(dev, irq, "failed to get dma irq\n"); 25127b59b132SShreeya Patel return irq; 25137b59b132SShreeya Patel } 25147b59b132SShreeya Patel 25157b59b132SShreeya Patel irq_set_status_flags(irq, IRQ_NOAUTOEN); 25167b59b132SShreeya Patel 25177b59b132SShreeya Patel hdmirx_dev->dma_irq = irq; 25187b59b132SShreeya Patel ret = devm_request_threaded_irq(dev, irq, NULL, hdmirx_dma_irq_handler, 25197b59b132SShreeya Patel IRQF_ONESHOT, "rk_hdmirx-dma", 25207b59b132SShreeya Patel hdmirx_dev); 25217b59b132SShreeya Patel if (ret) { 25227b59b132SShreeya Patel dev_err_probe(dev, ret, "failed to request dma irq\n"); 25237b59b132SShreeya Patel return ret; 25247b59b132SShreeya Patel } 25257b59b132SShreeya Patel 25267b59b132SShreeya Patel irq = gpiod_to_irq(hdmirx_dev->detect_5v_gpio); 25277b59b132SShreeya Patel if (irq < 0) { 25287b59b132SShreeya Patel dev_err_probe(dev, irq, "failed to get hdmirx-5v irq\n"); 25297b59b132SShreeya Patel return irq; 25307b59b132SShreeya Patel } 25317b59b132SShreeya Patel 25327b59b132SShreeya Patel irq_set_status_flags(irq, IRQ_NOAUTOEN); 25337b59b132SShreeya Patel 25347b59b132SShreeya Patel hdmirx_dev->det_irq = irq; 25357b59b132SShreeya Patel ret = devm_request_irq(dev, irq, hdmirx_5v_det_irq_handler, 25367b59b132SShreeya Patel IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 25377b59b132SShreeya Patel "rk_hdmirx-5v", hdmirx_dev); 25387b59b132SShreeya Patel if (ret) { 25397b59b132SShreeya Patel dev_err_probe(dev, ret, "failed to request hdmirx-5v irq\n"); 25407b59b132SShreeya Patel return ret; 25417b59b132SShreeya Patel } 25427b59b132SShreeya Patel 25437b59b132SShreeya Patel return 0; 25447b59b132SShreeya Patel } 25457b59b132SShreeya Patel 25467b59b132SShreeya Patel static int hdmirx_register_cec(struct snps_hdmirx_dev *hdmirx_dev, 25477b59b132SShreeya Patel struct platform_device *pdev) 25487b59b132SShreeya Patel { 25497b59b132SShreeya Patel struct device *dev = hdmirx_dev->dev; 25507b59b132SShreeya Patel struct hdmirx_cec_data cec_data; 25517b59b132SShreeya Patel int irq; 25527b59b132SShreeya Patel 25537b59b132SShreeya Patel irq = platform_get_irq_byname(pdev, "cec"); 25547b59b132SShreeya Patel if (irq < 0) { 25557b59b132SShreeya Patel dev_err_probe(dev, irq, "failed to get cec irq\n"); 25567b59b132SShreeya Patel return irq; 25577b59b132SShreeya Patel } 25587b59b132SShreeya Patel 25597b59b132SShreeya Patel cec_data.hdmirx = hdmirx_dev; 25607b59b132SShreeya Patel cec_data.dev = hdmirx_dev->dev; 25617b59b132SShreeya Patel cec_data.ops = &hdmirx_cec_ops; 25627b59b132SShreeya Patel cec_data.irq = irq; 25637b59b132SShreeya Patel 25647b59b132SShreeya Patel hdmirx_dev->cec = snps_hdmirx_cec_register(&cec_data); 25657b59b132SShreeya Patel if (IS_ERR(hdmirx_dev->cec)) 25667b59b132SShreeya Patel return dev_err_probe(dev, PTR_ERR(hdmirx_dev->cec), 25677b59b132SShreeya Patel "failed to register cec\n"); 25687b59b132SShreeya Patel 25697b59b132SShreeya Patel return 0; 25707b59b132SShreeya Patel } 25717b59b132SShreeya Patel 25727b59b132SShreeya Patel static int hdmirx_probe(struct platform_device *pdev) 25737b59b132SShreeya Patel { 25747b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev; 25757b59b132SShreeya Patel struct device *dev = &pdev->dev; 25767b59b132SShreeya Patel struct v4l2_ctrl_handler *hdl; 25777b59b132SShreeya Patel struct hdmirx_stream *stream; 25787b59b132SShreeya Patel struct v4l2_device *v4l2_dev; 25797b59b132SShreeya Patel int ret; 25807b59b132SShreeya Patel 25817b59b132SShreeya Patel hdmirx_dev = devm_kzalloc(dev, sizeof(*hdmirx_dev), GFP_KERNEL); 25827b59b132SShreeya Patel if (!hdmirx_dev) 25837b59b132SShreeya Patel return -ENOMEM; 25847b59b132SShreeya Patel 25857b59b132SShreeya Patel /* 25867b59b132SShreeya Patel * RK3588 HDMIRX SoC integration doesn't use IOMMU and can 25877b59b132SShreeya Patel * address only first 32bit of the physical address space. 25887b59b132SShreeya Patel */ 25897b59b132SShreeya Patel ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 25907b59b132SShreeya Patel if (ret) 25917b59b132SShreeya Patel return ret; 25927b59b132SShreeya Patel 25937b59b132SShreeya Patel hdmirx_dev->dev = dev; 25947b59b132SShreeya Patel dev_set_drvdata(dev, hdmirx_dev); 25957b59b132SShreeya Patel 25967b59b132SShreeya Patel ret = hdmirx_parse_dt(hdmirx_dev); 25977b59b132SShreeya Patel if (ret) 25987b59b132SShreeya Patel return ret; 25997b59b132SShreeya Patel 26007b59b132SShreeya Patel ret = hdmirx_setup_irq(hdmirx_dev, pdev); 26017b59b132SShreeya Patel if (ret) 26027b59b132SShreeya Patel return ret; 26037b59b132SShreeya Patel 26047b59b132SShreeya Patel hdmirx_dev->regs = devm_platform_ioremap_resource(pdev, 0); 26057b59b132SShreeya Patel if (IS_ERR(hdmirx_dev->regs)) 26067b59b132SShreeya Patel return dev_err_probe(dev, PTR_ERR(hdmirx_dev->regs), 26077b59b132SShreeya Patel "failed to remap regs resource\n"); 26087b59b132SShreeya Patel 26097b59b132SShreeya Patel mutex_init(&hdmirx_dev->stream_lock); 26107b59b132SShreeya Patel mutex_init(&hdmirx_dev->work_lock); 26117b59b132SShreeya Patel spin_lock_init(&hdmirx_dev->rst_lock); 26127b59b132SShreeya Patel 26137b59b132SShreeya Patel init_completion(&hdmirx_dev->cr_write_done); 26147b59b132SShreeya Patel init_completion(&hdmirx_dev->timer_base_lock); 26157b59b132SShreeya Patel init_completion(&hdmirx_dev->avi_pkt_rcv); 26167b59b132SShreeya Patel 26177b59b132SShreeya Patel INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_hotplug, 26187b59b132SShreeya Patel hdmirx_delayed_work_hotplug); 26197b59b132SShreeya Patel INIT_DELAYED_WORK(&hdmirx_dev->delayed_work_res_change, 26207b59b132SShreeya Patel hdmirx_delayed_work_res_change); 26217b59b132SShreeya Patel 26227b59b132SShreeya Patel hdmirx_dev->cur_fmt_fourcc = V4L2_PIX_FMT_BGR24; 26237b59b132SShreeya Patel hdmirx_dev->timings = cea640x480; 26247b59b132SShreeya Patel 26257b59b132SShreeya Patel hdmirx_enable(dev); 26267b59b132SShreeya Patel hdmirx_init(hdmirx_dev); 26277b59b132SShreeya Patel 26287b59b132SShreeya Patel v4l2_dev = &hdmirx_dev->v4l2_dev; 26297b59b132SShreeya Patel strscpy(v4l2_dev->name, dev_name(dev), sizeof(v4l2_dev->name)); 26307b59b132SShreeya Patel 26317b59b132SShreeya Patel hdl = &hdmirx_dev->hdl; 26327b59b132SShreeya Patel v4l2_ctrl_handler_init(hdl, 3); 26337b59b132SShreeya Patel 26347b59b132SShreeya Patel hdmirx_dev->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, 26357b59b132SShreeya Patel V4L2_CID_DV_RX_POWER_PRESENT, 26367b59b132SShreeya Patel 0, 1, 0, 0); 26377b59b132SShreeya Patel 26387b59b132SShreeya Patel hdmirx_dev->rgb_range = v4l2_ctrl_new_std_menu(hdl, NULL, 26397b59b132SShreeya Patel V4L2_CID_DV_RX_RGB_RANGE, 26407b59b132SShreeya Patel V4L2_DV_RGB_RANGE_FULL, 0, 26417b59b132SShreeya Patel V4L2_DV_RGB_RANGE_AUTO); 26427b59b132SShreeya Patel 26437b59b132SShreeya Patel hdmirx_dev->rgb_range->flags |= V4L2_CTRL_FLAG_READ_ONLY; 26447b59b132SShreeya Patel 26457b59b132SShreeya Patel hdmirx_dev->content_type = 26467b59b132SShreeya Patel v4l2_ctrl_new_std_menu(hdl, NULL, V4L2_CID_DV_RX_IT_CONTENT_TYPE, 26477b59b132SShreeya Patel V4L2_DV_IT_CONTENT_TYPE_NO_ITC, 0, 26487b59b132SShreeya Patel V4L2_DV_IT_CONTENT_TYPE_NO_ITC); 26497b59b132SShreeya Patel 26507b59b132SShreeya Patel if (hdl->error) { 26517b59b132SShreeya Patel ret = hdl->error; 26527b59b132SShreeya Patel dev_err_probe(dev, ret, "v4l2 ctrl handler init failed\n"); 26537b59b132SShreeya Patel goto err_pm; 26547b59b132SShreeya Patel } 26557b59b132SShreeya Patel hdmirx_dev->v4l2_dev.ctrl_handler = hdl; 26567b59b132SShreeya Patel 26577b59b132SShreeya Patel ret = v4l2_device_register(dev, &hdmirx_dev->v4l2_dev); 26587b59b132SShreeya Patel if (ret < 0) { 26597b59b132SShreeya Patel dev_err_probe(dev, ret, "v4l2 device registration failed\n"); 26607b59b132SShreeya Patel goto err_hdl; 26617b59b132SShreeya Patel } 26627b59b132SShreeya Patel 26637b59b132SShreeya Patel stream = &hdmirx_dev->stream; 26647b59b132SShreeya Patel stream->hdmirx_dev = hdmirx_dev; 26657b59b132SShreeya Patel ret = hdmirx_register_stream_vdev(stream); 26667b59b132SShreeya Patel if (ret < 0) { 26677b59b132SShreeya Patel dev_err_probe(dev, ret, "video device registration failed\n"); 26687b59b132SShreeya Patel goto err_unreg_v4l2_dev; 26697b59b132SShreeya Patel } 26707b59b132SShreeya Patel 26717b59b132SShreeya Patel ret = hdmirx_register_cec(hdmirx_dev, pdev); 26727b59b132SShreeya Patel if (ret) 26737b59b132SShreeya Patel goto err_unreg_video_dev; 26747b59b132SShreeya Patel 26757b59b132SShreeya Patel hdmirx_load_default_edid(hdmirx_dev); 26767b59b132SShreeya Patel 26777b59b132SShreeya Patel hdmirx_enable_irq(dev); 26787b59b132SShreeya Patel 26797b59b132SShreeya Patel hdmirx_dev->debugfs_dir = debugfs_create_dir(hdmirx_dev->v4l2_dev.name, 26807b59b132SShreeya Patel v4l2_debugfs_root()); 26817b59b132SShreeya Patel 26827b59b132SShreeya Patel hdmirx_dev->infoframes = v4l2_debugfs_if_alloc(hdmirx_dev->debugfs_dir, 26837b59b132SShreeya Patel V4L2_DEBUGFS_IF_AVI, hdmirx_dev, 26847b59b132SShreeya Patel hdmirx_debugfs_if_read); 26857b59b132SShreeya Patel 26867b59b132SShreeya Patel return 0; 26877b59b132SShreeya Patel 26887b59b132SShreeya Patel err_unreg_video_dev: 26897b59b132SShreeya Patel vb2_video_unregister_device(&hdmirx_dev->stream.vdev); 26907b59b132SShreeya Patel err_unreg_v4l2_dev: 26917b59b132SShreeya Patel v4l2_device_unregister(&hdmirx_dev->v4l2_dev); 26927b59b132SShreeya Patel err_hdl: 26937b59b132SShreeya Patel v4l2_ctrl_handler_free(&hdmirx_dev->hdl); 26947b59b132SShreeya Patel err_pm: 26957b59b132SShreeya Patel hdmirx_disable(dev); 26967b59b132SShreeya Patel 26977b59b132SShreeya Patel return ret; 26987b59b132SShreeya Patel } 26997b59b132SShreeya Patel 27007b59b132SShreeya Patel static void hdmirx_remove(struct platform_device *pdev) 27017b59b132SShreeya Patel { 27027b59b132SShreeya Patel struct device *dev = &pdev->dev; 27037b59b132SShreeya Patel struct snps_hdmirx_dev *hdmirx_dev = dev_get_drvdata(dev); 27047b59b132SShreeya Patel 27057b59b132SShreeya Patel v4l2_debugfs_if_free(hdmirx_dev->infoframes); 27067b59b132SShreeya Patel debugfs_remove_recursive(hdmirx_dev->debugfs_dir); 27077b59b132SShreeya Patel 27087b59b132SShreeya Patel snps_hdmirx_cec_unregister(hdmirx_dev->cec); 27097b59b132SShreeya Patel 27107b59b132SShreeya Patel hdmirx_disable_irq(dev); 27117b59b132SShreeya Patel 27127b59b132SShreeya Patel vb2_video_unregister_device(&hdmirx_dev->stream.vdev); 27137b59b132SShreeya Patel v4l2_ctrl_handler_free(&hdmirx_dev->hdl); 27147b59b132SShreeya Patel v4l2_device_unregister(&hdmirx_dev->v4l2_dev); 27157b59b132SShreeya Patel 27167b59b132SShreeya Patel /* touched by hdmirx_disable()->hdmirx_plugout() */ 27177b59b132SShreeya Patel hdmirx_dev->rgb_range = NULL; 27187b59b132SShreeya Patel hdmirx_dev->content_type = NULL; 27197b59b132SShreeya Patel 27207b59b132SShreeya Patel hdmirx_disable(dev); 27217b59b132SShreeya Patel 27227b59b132SShreeya Patel reset_control_bulk_assert(HDMIRX_NUM_RST, hdmirx_dev->resets); 27237b59b132SShreeya Patel } 27247b59b132SShreeya Patel 27257b59b132SShreeya Patel static const struct of_device_id hdmirx_id[] = { 27267b59b132SShreeya Patel { .compatible = "rockchip,rk3588-hdmirx-ctrler" }, 27277b59b132SShreeya Patel { } 27287b59b132SShreeya Patel }; 27297b59b132SShreeya Patel MODULE_DEVICE_TABLE(of, hdmirx_id); 27307b59b132SShreeya Patel 27317b59b132SShreeya Patel static struct platform_driver hdmirx_driver = { 27327b59b132SShreeya Patel .probe = hdmirx_probe, 27337b59b132SShreeya Patel .remove = hdmirx_remove, 27347b59b132SShreeya Patel .driver = { 27357b59b132SShreeya Patel .name = "snps_hdmirx", 27367b59b132SShreeya Patel .of_match_table = hdmirx_id, 27377b59b132SShreeya Patel .pm = &snps_hdmirx_pm_ops, 27387b59b132SShreeya Patel } 27397b59b132SShreeya Patel }; 27407b59b132SShreeya Patel module_platform_driver(hdmirx_driver); 27417b59b132SShreeya Patel 27427b59b132SShreeya Patel MODULE_DESCRIPTION("Synopsys HDMI Receiver Driver"); 27437b59b132SShreeya Patel MODULE_AUTHOR("Dingxian Wen <shawn.wen@rock-chips.com>"); 27447b59b132SShreeya Patel MODULE_AUTHOR("Shreeya Patel <shreeya.patel@collabora.com>"); 27457b59b132SShreeya Patel MODULE_AUTHOR("Dmitry Osipenko <dmitry.osipenko@collabora.com>"); 27467b59b132SShreeya Patel MODULE_LICENSE("GPL"); 2747