Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e67a5af6 authored by Ken Zhang's avatar Ken Zhang Committed by Gerrit - the friendly Code Review server
Browse files

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.

Change-Id: I634da4ffbd4e7994113d805c3c8facef3c9a5a25
Signed-off-by: default avatarKen Zhang <kenz@codeaurora.org>
parent b6d89b7b
Loading
Loading
Loading
Loading
+33 −6
Original line number Diff line number Diff line
@@ -402,11 +402,15 @@ static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,
	if (edid_ctrl->sink_data.num_of_elements) {
		u32 *video_mode = edid_ctrl->sink_data.disp_mode_list;
		u32 *video_3d_mode = edid_ctrl->sink_data.disp_3d_mode_list;

		for (i = 0; i < edid_ctrl->sink_data.num_of_elements; ++i) {
			ret = hdmi_get_video_3d_fmt_2string(*video_3d_mode++,
			if (*video_3d_mode == 0) {
				video_3d_mode++;
				video_mode++;
				continue;
			}
			hdmi_get_video_3d_fmt_2string(*video_3d_mode++,
				buff_3d, sizeof(buff_3d));
			if (ret > 0)
			if (ret)
				ret += scnprintf(buf + ret, PAGE_SIZE - ret,
					",%d=%s", *video_mode++,
					buff_3d);
@@ -415,9 +419,6 @@ static ssize_t hdmi_edid_sysfs_rda_3d_modes(struct device *dev,
					"%d=%s", *video_mode++,
					buff_3d);
		}
	} else {
		ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%d",
			edid_ctrl->video_resolution);
	}

	DEV_DBG("%s: '%s'\n", __func__, buf);
@@ -1860,6 +1861,32 @@ 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;

	if (!edid_ctrl) {
		DEV_ERR("%s: invalid input\n", __func__);
		return false;
	}
	sink_data = &edid_ctrl->sink_data;
	for (i = 0; i < sink_data->num_of_elements; ++i) {
		if (sink_data->disp_mode_list[i] != video_mode)
			continue;
		if (sink_data->disp_3d_mode_list[i] & (1 << s3d_mode))
			ret = true;
		else
			DEV_DBG("%s: return false: vic=%d caps=%x s3d=%d\n",
				__func__, video_mode,
				sink_data->disp_3d_mode_list[i], s3d_mode);
		break;
	}
	return ret;
}

int hdmi_edid_get_audio_blk(void *input, struct msm_hdmi_audio_edid_blk *blk)
{
	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+3 −1
Original line number Diff line number Diff line
/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -33,5 +33,7 @@ int hdmi_edid_get_audio_blk(void *edid_ctrl,
void hdmi_edid_set_video_resolution(void *edid_ctrl, u32 resolution);
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__ */
+107 −24
Original line number Diff line number Diff line
@@ -169,6 +169,8 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
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 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,
@@ -1001,6 +1003,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: invalide 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->video_resolution,
			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(video_mode, S_IRUGO, hdmi_tx_sysfs_rda_video_mode, NULL);
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
@@ -1012,6 +1074,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,
@@ -1021,6 +1085,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 = {
@@ -1605,14 +1670,13 @@ static void hdmi_tx_set_avi_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl)
		DSS_REG_R(io, HDMI_INFOFRAME_CTRL0) | BIT(1) | BIT(0));
} /* hdmi_tx_set_avi_infoframe */

/* todo: add 3D support */
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) {
@@ -1638,6 +1702,26 @@ static void hdmi_tx_set_vendor_specific_infoframe(
	vs_iframe[5] = 0x0C;
	vs_iframe[6] = 0x00;

	if ((hdmi_ctrl->s3d_mode != HDMI_S3D_NONE) &&
		hdmi_edid_is_s3d_mode_supported(
			hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
			hdmi_ctrl->video_resolution,
			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->video_resolution) {
		case HDMI_VFRMT_3840x2160p30_16_9:
@@ -1656,13 +1740,12 @@ static void hdmi_tx_set_vendor_specific_infoframe(
			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++)
@@ -1672,7 +1755,7 @@ static 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);

+1 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ struct hdmi_tx_ctrl {
	void *downstream_data;

	void *feature_data[HDMI_TX_FEAT_MAX];
	u32 s3d_mode;
};

#endif /* __MDSS_HDMI_TX_H__ */
+3 −3
Original line number Diff line number Diff line
@@ -225,9 +225,9 @@
#define HDCP_KSV_LSB                     (0x000060D8)
#define HDCP_KSV_MSB                     (0x000060DC)

#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)
Loading