summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Zhang <kenz@codeaurora.org>2015-01-21 15:02:27 -0500
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:11:41 -0700
commit849559ffdc3be07810e32842dc3ef353d31fd098 (patch)
treeefa31352786565aa88d4fd04db3152b252465a35
parent197399a2dace7275d94cfb7b5c38bc12839e451f (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.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c135
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.h6
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)