From b65bb3bb00d6912ac6c1ad07f920621d7b5b48ec Mon Sep 17 00:00:00 2001 From: Wangqiang Guo Date: Sun, 4 Feb 2024 12:48:34 +0000 Subject: [PATCH] media: i2c: rk628: add private interface, compatible with hdmirx. Change-Id: I737dcb068bc830baccb932d985bdbede56b5d490 Signed-off-by: Wangqiang Guo --- drivers/media/i2c/rk628/rk628_csi_v4l2.c | 156 ++++++++++++++++++++++- drivers/media/i2c/rk628/rk628_hdmirx.c | 11 ++ drivers/media/i2c/rk628/rk628_hdmirx.h | 2 + include/uapi/linux/rk_hdmirx_config.h | 25 ++++ 4 files changed, 187 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index f3746c8538d9..bf0a32710aee 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -105,6 +105,7 @@ struct rk628_csi { u32 stream_state; int hdmirx_irq; int plugin_irq; + int avi_rdy; bool nosignal; bool rxphy_pwron; bool txphy_pwron; @@ -116,6 +117,7 @@ struct rk628_csi { bool continues_clk; bool cec_enable; struct rk628_hdmirx_cec *cec; + bool is_dvi; struct rk628_hdcp hdcp; bool i2s_enable_default; HAUDINFO audio_info; @@ -719,10 +721,9 @@ static void rk628_dsi_set_scs(struct rk628_csi *csi) { u8 video_fmt; u32 val; - int avi_rdy; mutex_lock(&csi->confctl_mutex); - avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); + csi->avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); mutex_unlock(&csi->confctl_mutex); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_AVI_PB, &val); @@ -751,7 +752,7 @@ static void rk628_dsi_set_scs(struct rk628_csi *csi) } /* if avi packet is not stable, reset ctrl*/ - if (!avi_rdy) { + if (!csi->avi_rdy) { csi->nosignal = true; schedule_delayed_work(&csi->delayed_work_enable_hotplug, HZ / 20); } @@ -919,7 +920,6 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) u8 lanes = csi->csi_lanes_in_use; u8 lane_num; u32 wc_usrdef, val; - int avi_rdy; lane_num = lanes - 1; csi->rk628->dphy_lane_en = (1 << (lanes + 1)) - 1; @@ -1077,7 +1077,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) } mutex_lock(&csi->confctl_mutex); - avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); + csi->avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); mutex_unlock(&csi->confctl_mutex); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_AVI_PB, &val); @@ -1101,7 +1101,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) rk628_post_process_csc_en(csi->rk628); } /* if avi packet is not stable, reset ctrl*/ - if (!avi_rdy) { + if (!csi->avi_rdy) { csi->nosignal = true; schedule_delayed_work(&csi->delayed_work_enable_hotplug, HZ / 20); } @@ -1242,8 +1242,12 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd) __func__, width, height, frame_width, frame_height, status, cnt); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_STS, &val); - if (csi->rk628->version < RK628F_VERSION && (val & DVI_DET)) + if (csi->rk628->version < RK628F_VERSION && (val & DVI_DET)) { + csi->is_dvi = true; dev_info(csi->dev, "DVI mode detected\n"); + } else { + csi->is_dvi = false; + } if (!tx_5v_power_present(sd)) { v4l2_info(sd, "HDMI pull out, return!\n"); @@ -2226,6 +2230,32 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) else *(int *)arg = RKMODULE_CSI_INPUT; break; + case RK_HDMIRX_CMD_GET_FPS: + *(int *)arg = fps_calc(&csi->timings.bt); + break; + case RK_HDMIRX_CMD_GET_HDCP_ENC_STATUS: + *(int *)arg = rk628_hdmirx_get_hdcp_enc_status(csi->rk628); + break; + case RK_HDMIRX_CMD_GET_INPUT_MODE: + *(int *)arg = csi->is_dvi; + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + *(int *)arg = csi->avi_rdy; + break; + case RK_HDMIRX_CMD_GET_SCAN_MODE: + if (csi->timings.bt.interlaced == V4L2_DV_INTERLACED) + *(int *)arg = HDMIRX_INTERLACED; + else + *(int *)arg = HDMIRX_PROGRESSIVE; + break; + case RK_HDMIRX_CMD_GET_EDID_MODE: + *(int *)arg = HDMIRX_EDID_4K60HZ_YUV444; + break; + case RK_HDMIRX_CMD_SET_EDID_MODE: + break; + case RK_HDMIRX_CMD_GET_COLOR_RANGE: + *(int *)arg = rk628_hdmirx_get_range(csi->rk628); + break; default: ret = -ENOIOCTLCMD; break; @@ -2398,6 +2428,118 @@ static long rk628_csi_compat_ioctl32(struct v4l2_subdev *sd, } kfree(seq); break; + case RK_HDMIRX_CMD_GET_FPS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_HDCP_ENC_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_INPUT_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_SCAN_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_EDID_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_SET_EDID_MODE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; + case RK_HDMIRX_CMD_GET_COLOR_RANGE: + seq = kzalloc(sizeof(*seq), GFP_KERNEL); + if (!seq) { + ret = -ENOMEM; + return ret; + } + ret = rk628_csi_ioctl(sd, cmd, seq); + if (!ret) { + ret = copy_to_user(up, seq, sizeof(*seq)); + if (ret) + ret = -EFAULT; + } + kfree(seq); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 9ead0fbfd1b8..8348067ebc68 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -213,6 +213,17 @@ void rk628_hdmirx_controller_setup(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_controller_setup); +int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628) +{ + u32 val; + + rk628_i2c_read(rk628, HDMI_RX_HDCP_STS, &val); + val &= HDCP_ENC_STATE; + + return val ? 1 : 0; +} +EXPORT_SYMBOL(rk628_hdmirx_get_hdcp_enc_status); + static bool is_validfs(int fs) { int i = 0; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 9dce977b2369..774b72caf4f0 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -121,6 +121,7 @@ #define HDMI_RX_HDCP_DBG (HDMI_RX_BASE + 0x00e0) #define HDMI_RX_HDCP_AN0 (HDMI_RX_BASE + 0x00f0) #define HDMI_RX_HDCP_STS (HDMI_RX_BASE + 0x00fc) +#define HDCP_ENC_STATE BIT(9) #define HDMI_RX_MD_HCTRL1 (HDMI_RX_BASE + 0x0140) #define HACT_PIX_ITH(x) UPDATE(x, 10, 8) #define HACT_PIX_SRC(x) UPDATE(x, 5, 5) @@ -516,6 +517,7 @@ u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628); int rk628_hdmirx_get_timings(struct rk628 *rk628, struct v4l2_dv_timings *timings); u8 rk628_hdmirx_get_range(struct rk628 *rk628); +int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628); void rk628_hdmirx_controller_reset(struct rk628 *rk628); bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628); bool rk628_hdmirx_is_signal_change_ists(struct rk628 *rk628); diff --git a/include/uapi/linux/rk_hdmirx_config.h b/include/uapi/linux/rk_hdmirx_config.h index 26dcea790013..afa7b2104a81 100644 --- a/include/uapi/linux/rk_hdmirx_config.h +++ b/include/uapi/linux/rk_hdmirx_config.h @@ -44,6 +44,19 @@ enum hdmirx_color_space { HDMIRX_BT2020_RGB_OR_YCC = 6, }; +/* hdmirx scan mode */ +enum hdmirx_scan_mode { + HDMIRX_PROGRESSIVE = 0, + HDMIRX_INTERLACED = 1, +}; + +enum hdmirx_edid_mode { + HDMIRX_EDID_2K60HZ_YUV444, + HDMIRX_EDID_4K30HZ_YUV444, + HDMIRX_EDID_4K60HZ_YUV444, + HDMIRX_EDID_4K60HZ_YUV420, +}; + /* Private v4l2 ioctl */ #define RK_HDMIRX_CMD_GET_FPS \ _IOR('V', BASE_VIDIOC_PRIVATE + 0, int) @@ -78,6 +91,18 @@ enum hdmirx_color_space { #define RK_HDMIRX_CMD_GET_COLOR_SPACE \ _IOR('V', BASE_VIDIOC_PRIVATE + 10, int) +#define RK_HDMIRX_CMD_GET_SCAN_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 11, __u8) + +#define RK_HDMIRX_CMD_GET_EDID_MODE \ + _IOR('V', BASE_VIDIOC_PRIVATE + 12, __u8) + +#define RK_HDMIRX_CMD_SET_EDID_MODE \ + _IOW('V', BASE_VIDIOC_PRIVATE + 13, __u8) + +#define RK_HDMIRX_CMD_GET_HDCP_ENC_STATUS \ + _IOR('V', BASE_VIDIOC_PRIVATE + 14, __u8) + /* Private v4l2 event */ #define RK_HDMIRX_V4L2_EVENT_SIGNAL_LOST \ (V4L2_EVENT_PRIVATE_START + 1)