diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 54b1a0c1243b..5deb8465411e 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -106,7 +106,6 @@ struct rk628_csi { u32 stream_state; int hdmirx_irq; int plugin_irq; - int avi_rdy; bool nosignal; bool rxphy_pwron; bool txphy_pwron; @@ -118,7 +117,6 @@ 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; @@ -731,11 +729,9 @@ static void rk628_dsi_set_scs(struct rk628_csi *csi) { u8 video_fmt; u32 val; + int avi_rdy; - mutex_lock(&csi->confctl_mutex); - csi->avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); - mutex_unlock(&csi->confctl_mutex); - + avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_AVI_PB, &val); video_fmt = (val & VIDEO_FORMAT_MASK) >> 5; v4l2_info(&csi->sd, "%s PDEC_AVI_PB:%#x, video format:%d\n", @@ -762,7 +758,7 @@ static void rk628_dsi_set_scs(struct rk628_csi *csi) } /* if avi packet is not stable, reset ctrl*/ - if (!csi->avi_rdy) { + if (!avi_rdy) { csi->nosignal = true; schedule_delayed_work(&csi->delayed_work_enable_hotplug, HZ / 20); } @@ -930,6 +926,7 @@ 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; @@ -1086,9 +1083,7 @@ static void rk628_csi_set_csi(struct v4l2_subdev *sd) v4l2_dbg(1, debug, sd, "%s csi1 config done\n", __func__); } - mutex_lock(&csi->confctl_mutex); - csi->avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); - mutex_unlock(&csi->confctl_mutex); + avi_rdy = rk628_is_avi_ready(csi->rk628, csi->avi_rcv_rdy); rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_AVI_PB, &val); video_fmt = (val & VIDEO_FORMAT_MASK) >> 5; @@ -1111,7 +1106,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 (!csi->avi_rdy) { + if (!avi_rdy) { csi->nosignal = true; schedule_delayed_work(&csi->delayed_work_enable_hotplug, HZ / 20); } @@ -1252,12 +1247,8 @@ 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)) { - csi->is_dvi = true; + if (csi->rk628->version < RK628F_VERSION && (val & DVI_DET)) 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"); @@ -2188,6 +2179,7 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) long ret = 0; struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; + u32 val; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2234,10 +2226,11 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) *(int *)arg = rk628_hdmirx_get_hdcp_enc_status(csi->rk628); break; case RK_HDMIRX_CMD_GET_INPUT_MODE: - *(int *)arg = csi->is_dvi; + rk628_i2c_read(csi->rk628, HDMI_RX_PDEC_STS, &val); + *(int *)arg = val & DVI_DET; break; case RK_HDMIRX_CMD_GET_SIGNAL_STABLE_STATUS: - *(int *)arg = csi->avi_rdy; + *(int *)arg = !csi->nosignal; break; case RK_HDMIRX_CMD_GET_SCAN_MODE: if (csi->timings.bt.interlaced == V4L2_DV_INTERLACED) @@ -2253,6 +2246,9 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) case RK_HDMIRX_CMD_GET_COLOR_RANGE: *(int *)arg = rk628_hdmirx_get_range(csi->rk628); break; + case RK_HDMIRX_CMD_GET_COLOR_SPACE: + *(int *)arg = rk628_hdmirx_get_color_space(csi->rk628); + break; default: ret = -ENOIOCTLCMD; break; @@ -2537,6 +2533,20 @@ static long rk628_csi_compat_ioctl32(struct v4l2_subdev *sd, } kfree(seq); break; + case RK_HDMIRX_CMD_GET_COLOR_SPACE: + 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 8348067ebc68..03beaa2b3cba 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "rk628.h" #include "rk628_combrxphy.h" @@ -49,6 +50,30 @@ struct hdmirx_tmdsclk_cnt { u8 cnt; }; +enum hdmirx_pix_fmt { + HDMIRX_RGB888 = 0, + HDMIRX_YUV422 = 1, + HDMIRX_YUV444 = 2, + HDMIRX_YUV420 = 3, +}; + +static const char * const bus_format_str[] = { + "RGB", + "YUV422", + "YUV444", + "YUV420", + "UNKNOWN", +}; + +static const char *bus_color_range_str[3] = { + "Default", "Limited", "Full" +}; + +static const char *bus_color_space_str[8] = { + "xvYCC601", "xvYCC709", "sYCC601", "Adobe_YCC601", + "Adobe_RGB", "BT2020_YcCbcCrc", "BT2020_RGB_OR_YCbCr" +}; + #define HDMIRX_GET_TMDSCLK_TIME 21 static int supported_fs[] = { @@ -1185,14 +1210,6 @@ void rk628_hdmirx_phy_prepclk_cfg(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_phy_prepclk_cfg); -static const char * const bus_format_str[] = { - "RGB", - "YUV422", - "YUV444", - "YUV420", - "UNKNOWN", -}; - u8 rk628_hdmirx_get_format(struct rk628 *rk628) { u32 val; @@ -1280,7 +1297,7 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, u32 hofs_pix, hbp, hfp, vbp, vfp; u32 tmds_clk, tmdsclk_cnt; u64 tmp_data; - u8 video_fmt; + u8 video_fmt, vic, color_range, color_space; memset(timings, 0, sizeof(struct v4l2_dv_timings)); timings->type = V4L2_DV_BT_656_1120; @@ -1341,7 +1358,11 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, hfp = htotal - hact - hofs_pix; vfp = vtotal - vact - vs - vbp; + rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val); + vic = (val & VID_IDENT_CODE_MASK) >> 24; video_fmt = rk628_hdmirx_get_format(rk628); + color_range = rk628_hdmirx_get_range(rk628); + color_space = rk628_hdmirx_get_color_space(rk628); if (video_fmt == BUS_FMT_YUV420) { htotal *= 2; hact *= 2; @@ -1352,6 +1373,8 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, dev_info(rk628->dev, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n", HDMIRX_MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, modetclk_cnt_vs, hofs_pix); + dev_info(rk628->dev, "get current aviif: vic:%d, color_range: %s, color_space %s", + vic, bus_color_range_str[color_range], bus_color_space_str[color_space]); bt->width = hact; bt->height = vact; @@ -1490,20 +1513,57 @@ EXPORT_SYMBOL(rk628_hdmirx_get_timings); u8 rk628_hdmirx_get_range(struct rk628 *rk628) { - u32 val; u8 color_range; + u32 val, vic, fmt; rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val); color_range = (val & RGB_COLORRANGE_MASK) >> 18; - if (color_range == 0x1) - color_range = CSC_LIMIT_RANGE; - else - color_range = CSC_FULL_RANGE; + vic = (val & VID_IDENT_CODE_MASK) >> 24; + fmt = (val & VIDEO_FORMAT_MASK) >> 5; + if (fmt == HDMIRX_RGB888 && color_range == HDMIRX_DEFAULT_RANGE) { + (vic) ? + (color_range = HDMIRX_LIMIT_RANGE) : + (color_range = HDMIRX_FULL_RANGE); + } return color_range; } EXPORT_SYMBOL(rk628_hdmirx_get_range); +u8 rk628_hdmirx_get_color_space(struct rk628 *rk628) +{ + u32 val, EC2_0, C1_C0, fmt; + u8 color_space; + + rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val); + EC2_0 = (val & EXT_COLORIMETRY_MASK) >> 20; + C1_C0 = (val & COLORIMETRY_MASK) >> 14; + fmt = (val & VIDEO_FORMAT_MASK) >> 5; + if (fmt == HDMIRX_RGB888) { + (C1_C0 == 0) ? + (color_space = HDMIRX_RGB) : + (color_space = EC2_0); + } else { + switch (C1_C0) { + case 0: + color_space = HDMIRX_XVYCC709; + break; + case 1: + color_space = HDMIRX_XVYCC601; + break; + case 2: + color_space = HDMIRX_XVYCC709; + break; + default: + color_space = EC2_0; + break; + } + } + + return color_space; +} +EXPORT_SYMBOL(rk628_hdmirx_get_color_space); + void rk628_hdmirx_controller_reset(struct rk628 *rk628) { mutex_lock(&rk628->rst_lock); diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 774b72caf4f0..31f026ef9e4c 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -255,7 +255,12 @@ #define DVI_DET BIT(28) #define HDMI_RX_PDEC_GCP_AVMUTE (HDMI_RX_BASE + 0x0380) #define PKTDEC_GCP_CD_MASK GENMASK(7, 4) +#define HDMI_RX_PDEC_AVI_HB (HDMI_RX_BASE + 0x03a0) #define HDMI_RX_PDEC_AVI_PB (HDMI_RX_BASE + 0x03a4) +#define VID_IDENT_CODE_VIC7 BIT(31) +#define VID_IDENT_CODE_MASK GENMASK(30, 24) +#define EXT_COLORIMETRY_MASK GENMASK(22, 20) +#define COLORIMETRY_MASK GENMASK(15, 14) #define VIDEO_FORMAT_MASK GENMASK(6, 5) #define VIDEO_FORMAT(x) UPDATE(x, 6, 5) #define RGB_COLORRANGE_MASK GENMASK(19, 18) @@ -517,6 +522,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); +u8 rk628_hdmirx_get_color_space(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); diff --git a/include/uapi/linux/rk_hdmirx_config.h b/include/uapi/linux/rk_hdmirx_config.h index afa7b2104a81..c4fb3c9c5ca8 100644 --- a/include/uapi/linux/rk_hdmirx_config.h +++ b/include/uapi/linux/rk_hdmirx_config.h @@ -42,6 +42,7 @@ enum hdmirx_color_space { HDMIRX_ADOBE_RGB = 4, HDMIRX_BT2020_YCC_CONST_LUM = 5, HDMIRX_BT2020_RGB_OR_YCC = 6, + HDMIRX_RGB = 7, }; /* hdmirx scan mode */