diff options
| author | Ken Zhang <kenz@codeaurora.org> | 2015-01-21 15:02:27 -0500 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:11:41 -0700 |
| commit | 849559ffdc3be07810e32842dc3ef353d31fd098 (patch) | |
| tree | efa31352786565aa88d4fd04db3152b252465a35 | |
| parent | 197399a2dace7275d94cfb7b5c38bc12839e451f (diff) | |
msm: mdss: hdmi: s3d mode support
Add sysfs node s3d_mode for stereo 3d support,
configure vendor info frame when 3d mode is set and
current video mode can support it. Output edid_3d_modes
in sysfs node in correct format.
Set 1 to s3d_mode will enable side by side, 2 for top
bottom, 3 for framepacking, 0 for 2d.
Change-Id: I634da4ffbd4e7994113d805c3c8facef3c9a5a25
Signed-off-by: Ken Zhang <kenz@codeaurora.org>
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_edid.c | 33 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_edid.h | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 135 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_util.h | 6 |
5 files changed, 143 insertions, 34 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 0eb5869bdfe3..e6dee010ba05 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -91,7 +91,7 @@ enum extended_data_block_types { struct disp_mode_info { u32 video_format; - u32 video_3d_format; + u32 video_3d_format; /* Flags like SIDE_BY_SIDE_HALF*/ bool rgb_support; bool y420_support; }; @@ -615,7 +615,9 @@ static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev, edid_ctrl->sink_data.disp_mode_list; for (i = 0; i < edid_ctrl->sink_data.num_of_elements; i++) { - ret = hdmi_get_video_3d_fmt_2string( + if (!video_mode[i].video_3d_format) + continue; + hdmi_get_video_3d_fmt_2string( video_mode[i].video_3d_format, buff_3d, sizeof(buff_3d)); @@ -628,9 +630,6 @@ static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev, "%d=%s", video_mode[i].video_format, buff_3d); } - } else { - ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d", - edid_ctrl->video_resolution); } DEV_DBG("%s: '%s'\n", __func__, buf); @@ -2254,6 +2253,30 @@ u32 hdmi_edid_get_sink_mode(void *input) return edid_ctrl->sink_mode; } /* hdmi_edid_get_sink_mode */ +bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode) +{ + int i; + bool ret = false; + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + struct hdmi_edid_sink_data *sink_data; + + sink_data = &edid_ctrl->sink_data; + for (i = 0; i < sink_data->num_of_elements; ++i) { + if (sink_data->disp_mode_list[i].video_format != video_mode) + continue; + if (sink_data->disp_mode_list[i].video_3d_format & + (1 << s3d_mode)) + ret = true; + else + DEV_DBG("%s: return false: vic=%d caps=%x s3d=%d\n", + __func__, video_mode, + sink_data->disp_mode_list[i].video_3d_format, + s3d_mode); + break; + } + return ret; +} + bool hdmi_edid_get_scdc_support(void *input) { struct hdmi_edid_ctrl *edid_ctrl = input; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index 989b8c267349..9dc9dbd9400b 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -40,5 +40,7 @@ void hdmi_edid_set_video_resolution(void *edid_ctrl, u32 resolution, bool reset); void hdmi_edid_deinit(void *edid_ctrl); void *hdmi_edid_init(struct hdmi_edid_init_data *init_data); +bool hdmi_edid_is_s3d_mode_supported(void *input, + u32 video_mode, u32 s3d_mode); #endif /* __HDMI_EDID_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 7d8925fc6267..329db7c00786 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -199,6 +199,8 @@ static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl, enum hdmi_tx_power_module_type module, int enable); static int hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl); static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl); +static void hdmi_tx_set_vendor_specific_infoframe( + struct hdmi_tx_ctrl *hdmi_ctrl); static struct mdss_hw hdmi_tx_hw = { .hw_ndx = MDSS_HW_HDMI, @@ -1059,6 +1061,66 @@ static ssize_t hdmi_tx_sysfs_wta_avi_cn_bits(struct device *dev, return ret; } /* hdmi_tx_sysfs_wta_cn_bits */ +static ssize_t hdmi_tx_sysfs_wta_s3d_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc, s3d_mode; + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct hdmi_tx_ctrl *hdmi_ctrl = NULL; + + hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev); + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &s3d_mode); + if (rc) { + DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return rc; + } + + if (s3d_mode < HDMI_S3D_NONE || s3d_mode >= HDMI_S3D_MAX) { + DEV_ERR("%s: invalid s3d mode = %d\n", __func__, s3d_mode); + return -EINVAL; + } + + if (s3d_mode > HDMI_S3D_NONE && + !hdmi_edid_is_s3d_mode_supported( + hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], + hdmi_ctrl->vid_cfg.vic, + s3d_mode)) { + DEV_ERR("%s: s3d mode not supported in current video mode\n", + __func__); + return -EPERM; + } + + hdmi_ctrl->s3d_mode = s3d_mode; + hdmi_tx_set_vendor_specific_infoframe(hdmi_ctrl); + + DEV_DBG("%s: %d\n", __func__, hdmi_ctrl->s3d_mode); + return ret; +} + +static ssize_t hdmi_tx_sysfs_rda_s3d_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct hdmi_tx_ctrl *hdmi_ctrl = + hdmi_tx_get_drvdata_from_sysfs_dev(dev); + + if (!hdmi_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->s3d_mode); + DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->s3d_mode); + + return ret; +} + static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL); static DEVICE_ATTR(hdmi_audio_cb, S_IWUSR, NULL, hdmi_tx_sysfs_wta_audio_cb); static DEVICE_ATTR(video_mode, S_IRUGO, hdmi_tx_sysfs_rda_video_mode, NULL); @@ -1071,6 +1133,8 @@ static DEVICE_ATTR(product_description, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_wta_product_description); static DEVICE_ATTR(avi_itc, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_itc); static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn_bits); +static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_s3d_mode, + hdmi_tx_sysfs_wta_s3d_mode); static struct attribute *hdmi_tx_fs_attrs[] = { &dev_attr_connected.attr, @@ -1081,6 +1145,7 @@ static struct attribute *hdmi_tx_fs_attrs[] = { &dev_attr_product_description.attr, &dev_attr_avi_itc.attr, &dev_attr_avi_cn0_1.attr, + &dev_attr_s3d_mode.attr, NULL, }; static struct attribute_group hdmi_tx_fs_attrs_group = { @@ -2075,14 +2140,13 @@ static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl) DSS_REG_W(io, HDMI_INFOFRAME_CTRL1, reg_val); } /* hdmi_tx_set_avi_infoframe */ -/* todo: add 3D support */ -void hdmi_tx_set_vendor_specific_infoframe( - struct hdmi_tx_ctrl *hdmi_ctrl) +static void hdmi_tx_set_vendor_specific_infoframe( + struct hdmi_tx_ctrl *hdmi_ctrl) { int i; u8 vs_iframe[9]; /* two header + length + 6 data */ u32 sum, reg_val; - u32 hdmi_vic, hdmi_video_format; + u32 hdmi_vic, hdmi_video_format, s3d_struct = 0; struct dss_io_data *io = NULL; if (!hdmi_ctrl) { @@ -2108,31 +2172,50 @@ void hdmi_tx_set_vendor_specific_infoframe( vs_iframe[5] = 0x0C; vs_iframe[6] = 0x00; - hdmi_video_format = 0x1; - switch (hdmi_ctrl->vid_cfg.vic) { - case HDMI_EVFRMT_3840x2160p30_16_9: - hdmi_vic = 0x1; - break; - case HDMI_EVFRMT_3840x2160p25_16_9: - hdmi_vic = 0x2; - break; - case HDMI_EVFRMT_3840x2160p24_16_9: - hdmi_vic = 0x3; - break; - case HDMI_EVFRMT_4096x2160p24_16_9: - hdmi_vic = 0x4; - break; - default: - hdmi_video_format = 0x0; - hdmi_vic = 0x0; + if ((hdmi_ctrl->s3d_mode != HDMI_S3D_NONE) && + hdmi_edid_is_s3d_mode_supported( + hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID], + hdmi_ctrl->vid_cfg.vic, + hdmi_ctrl->s3d_mode)) { + switch (hdmi_ctrl->s3d_mode) { + case HDMI_S3D_SIDE_BY_SIDE: + s3d_struct = 0x8; + break; + case HDMI_S3D_TOP_AND_BOTTOM: + s3d_struct = 0x6; + break; + default: + s3d_struct = 0; + } + hdmi_video_format = 0x2; + hdmi_vic = 0; + /* PB5: 3D_Structure[7:4], Reserved[3:0] */ + vs_iframe[8] = s3d_struct << 4; + } else { + hdmi_video_format = 0x1; + switch (hdmi_ctrl->vid_cfg.vic) { + case HDMI_EVFRMT_3840x2160p30_16_9: + hdmi_vic = 0x1; + break; + case HDMI_EVFRMT_3840x2160p25_16_9: + hdmi_vic = 0x2; + break; + case HDMI_EVFRMT_3840x2160p24_16_9: + hdmi_vic = 0x3; + break; + case HDMI_EVFRMT_4096x2160p24_16_9: + hdmi_vic = 0x4; + break; + default: + hdmi_video_format = 0x0; + hdmi_vic = 0x0; + } + /* PB5: HDMI_VIC */ + vs_iframe[8] = hdmi_vic; } - /* PB4: HDMI Video Format[7:5], Reserved[4:0] */ vs_iframe[7] = (hdmi_video_format << 5) & 0xE0; - /* PB5: HDMI_VIC or 3D_Structure[7:4], Reserved[3:0] */ - vs_iframe[8] = hdmi_vic; - /* compute checksum */ sum = 0; for (i = 0; i < 9; i++) @@ -2142,7 +2225,7 @@ void hdmi_tx_set_vendor_specific_infoframe( sum = 256 - sum; vs_iframe[3] = (u8)sum; - reg_val = (hdmi_vic << 16) | (vs_iframe[3] << 8) | + reg_val = (s3d_struct << 24) | (hdmi_vic << 16) | (vs_iframe[3] << 8) | (hdmi_video_format << 5) | vs_iframe[2]; DSS_REG_W(io, HDMI_VENSPEC_INFO0, reg_val); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index 7be6a926d929..1604692269fa 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -189,6 +189,7 @@ struct hdmi_tx_ctrl { u8 *edid_buf; u32 edid_buf_size; + u32 s3d_mode; }; #endif /* __MDSS_HDMI_TX_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h index e0b5d45774f4..4c5f8bc09bec 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_util.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h @@ -258,9 +258,9 @@ /* SEC_CTRL version that supports HDCP SEL */ #define HDCP_SEL_MIN_SEC_VERSION (0x50010000) -#define TOP_AND_BOTTOM 0x10 -#define FRAME_PACKING 0x20 -#define SIDE_BY_SIDE_HALF 0x40 +#define TOP_AND_BOTTOM (1 << HDMI_S3D_TOP_AND_BOTTOM) +#define FRAME_PACKING (1 << HDMI_S3D_FRAME_PACKING) +#define SIDE_BY_SIDE_HALF (1 << HDMI_S3D_SIDE_BY_SIDE) #define LPASS_LPAIF_RDDMA_CTL0 (0xFE152000) #define LPASS_LPAIF_RDDMA_PER_CNT0 (0x00000014) |
