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

Commit 71ebcf5f authored by Tatenda Chipeperekwa's avatar Tatenda Chipeperekwa
Browse files

msm: mdss: hdmi: send info frame for HDR video streams



Send the dynamic range and mastering info frame if the sink
supports at least one electro-optical transfer function. This
info frame will be used by the sink to render the HDR video
stream for the duration of the transmission.

CRs-Fixed: 1044326
Change-Id: Iaa2c9e45fe0ed0392e084a381d2d1e1d506bc609
Signed-off-by: default avatarTatenda Chipeperekwa <tatendac@codeaurora.org>
parent 6a6788db
Loading
Loading
Loading
Loading
+7 −7
Original line number Original line Diff line number Diff line
@@ -216,7 +216,7 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl)
	/* reset HDR related data */
	/* reset HDR related data */
	edid_ctrl->hdr_supported = false;
	edid_ctrl->hdr_supported = false;
	edid_ctrl->hdr_data.eotf = 0;
	edid_ctrl->hdr_data.eotf = 0;
	edid_ctrl->hdr_data.descriptor = 0;
	edid_ctrl->hdr_data.metadata_type_one = false;
	edid_ctrl->hdr_data.max_luminance = 0;
	edid_ctrl->hdr_data.max_luminance = 0;
	edid_ctrl->hdr_data.avg_luminance = 0;
	edid_ctrl->hdr_data.avg_luminance = 0;
	edid_ctrl->hdr_data.min_luminance = 0;
	edid_ctrl->hdr_data.min_luminance = 0;
@@ -794,7 +794,7 @@ static ssize_t hdmi_edid_sysfs_rda_hdr_data(struct device *dev,
	ret = scnprintf(buf, PAGE_SIZE, "%d, %u, %u, %u, %u, %u\n",
	ret = scnprintf(buf, PAGE_SIZE, "%d, %u, %u, %u, %u, %u\n",
			edid_ctrl->hdr_supported,
			edid_ctrl->hdr_supported,
			edid_ctrl->hdr_data.eotf,
			edid_ctrl->hdr_data.eotf,
			edid_ctrl->hdr_data.descriptor,
			edid_ctrl->hdr_data.metadata_type_one,
			edid_ctrl->hdr_data.max_luminance,
			edid_ctrl->hdr_data.max_luminance,
			edid_ctrl->hdr_data.avg_luminance,
			edid_ctrl->hdr_data.avg_luminance,
			edid_ctrl->hdr_data.min_luminance);
			edid_ctrl->hdr_data.min_luminance);
@@ -964,8 +964,8 @@ static void hdmi_edid_parse_hdrdb(struct hdmi_edid_ctrl *edid_ctrl,
	/* Byte 3: Electro-Optical Transfer Functions */
	/* Byte 3: Electro-Optical Transfer Functions */
	edid_ctrl->hdr_data.eotf = data_block[2] & 0x3F;
	edid_ctrl->hdr_data.eotf = data_block[2] & 0x3F;


	/* Byte 4: Static Metadata Descriptors */
	/* Byte 4: Static Metadata Descriptor Type 1 */
	edid_ctrl->hdr_data.descriptor = data_block[3] & 0x1;
	edid_ctrl->hdr_data.metadata_type_one = (data_block[3] & 0x1) & BIT(0);


	/* Byte 5: Desired Content Maximum Luminance */
	/* Byte 5: Desired Content Maximum Luminance */
	if (hdmi_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE))
	if (hdmi_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE))
@@ -2458,16 +2458,16 @@ u8 hdmi_edid_get_deep_color(void *input)
 * Return: HDR data.
 * Return: HDR data.
 */
 */
void hdmi_edid_get_hdr_data(void *input,
void hdmi_edid_get_hdr_data(void *input,
		struct hdmi_edid_hdr_data *hdr_data)
		struct hdmi_edid_hdr_data **hdr_data)
{
{
	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
	struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;


	if (!edid_ctrl || !hdr_data) {
	if (!edid_ctrl) {
		DEV_ERR("%s: invalid input\n", __func__);
		DEV_ERR("%s: invalid input\n", __func__);
		return;
		return;
	}
	}


	hdr_data = &edid_ctrl->hdr_data;
	*hdr_data = &edid_ctrl->hdr_data;
}
}


bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode)
bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode)
+3 −3
Original line number Original line Diff line number Diff line
@@ -31,14 +31,14 @@ struct hdmi_edid_init_data {
/*
/*
 * struct hdmi_edid_hdr_data - HDR Static Metadata
 * struct hdmi_edid_hdr_data - HDR Static Metadata
 * @eotf: Electro-Optical Transfer Function
 * @eotf: Electro-Optical Transfer Function
 * @descriptor: Static Metadata Descriptor
 * @metadata_type_one: Static Metadata Type 1 support
 * @max_luminance: Desired Content Maximum Luminance
 * @max_luminance: Desired Content Maximum Luminance
 * @avg_luminance: Desired Content Frame-average Luminance
 * @avg_luminance: Desired Content Frame-average Luminance
 * @min_luminance: Desired Content Minimum Luminance
 * @min_luminance: Desired Content Minimum Luminance
 */
 */
struct hdmi_edid_hdr_data {
struct hdmi_edid_hdr_data {
	u32 eotf;
	u32 eotf;
	u32 descriptor;
	bool metadata_type_one;
	u32 max_luminance;
	u32 max_luminance;
	u32 avg_luminance;
	u32 avg_luminance;
	u32 min_luminance;
	u32 min_luminance;
@@ -61,6 +61,6 @@ bool hdmi_edid_is_s3d_mode_supported(void *input,
	u32 video_mode, u32 s3d_mode);
	u32 video_mode, u32 s3d_mode);
u8 hdmi_edid_get_deep_color(void *edid_ctrl);
u8 hdmi_edid_get_deep_color(void *edid_ctrl);
void hdmi_edid_get_hdr_data(void *edid_ctrl,
void hdmi_edid_get_hdr_data(void *edid_ctrl,
		struct hdmi_edid_hdr_data *hdr_data);
		struct hdmi_edid_hdr_data **hdr_data);


#endif /* __HDMI_EDID_H__ */
#endif /* __HDMI_EDID_H__ */
+191 −1
Original line number Original line Diff line number Diff line
@@ -79,6 +79,8 @@
#define HDMI_TX_MAX_FPS 120000
#define HDMI_TX_MAX_FPS 120000


#define HDMI_TX_VERSION_403	0x40000003	/* msmcobalt */
#define HDMI_TX_VERSION_403	0x40000003	/* msmcobalt */
#define HDMI_GET_MSB(x)		(x >> 8)
#define HDMI_GET_LSB(x)		(x & 0xff)


/* Enable HDCP by default */
/* Enable HDCP by default */
static bool hdcp_feature_on = true;
static bool hdcp_feature_on = true;
@@ -113,6 +115,7 @@ static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl);
static void hdmi_tx_fps_work(struct work_struct *work);
static void hdmi_tx_fps_work(struct work_struct *work);
static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl,
static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl,
			enum hdmi_tx_power_module_type module, bool active);
			enum hdmi_tx_power_module_type module, bool active);
static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *hdmi_ctrl);


static struct mdss_hw hdmi_tx_hw = {
static struct mdss_hw hdmi_tx_hw = {
	.hw_ndx = MDSS_HW_HDMI,
	.hw_ndx = MDSS_HW_HDMI,
@@ -287,6 +290,29 @@ static inline bool hdmi_tx_is_hdcp_enabled(struct hdmi_tx_ctrl *hdmi_ctrl)
		hdmi_ctrl->hdcp_ops;
		hdmi_ctrl->hdcp_ops;
}
}


/*
 * The sink must support at least one electro-optical transfer function for
 * HDMI controller to sendi the dynamic range and mastering infoframe.
 */
static inline bool hdmi_tx_is_hdr_supported(struct hdmi_tx_ctrl *hdmi_ctrl)
{
	struct hdmi_edid_hdr_data *hdr_data;

	hdmi_edid_get_hdr_data(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), &hdr_data);

	return (hdr_data->eotf & BIT(0)) || (hdr_data->eotf & BIT(1)) ||
			(hdr_data->eotf & BIT(2));
}

static inline bool hdmi_tx_metadata_type_one(struct hdmi_tx_ctrl *hdmi_ctrl)
{
	struct hdmi_edid_hdr_data *hdr_data;

	hdmi_edid_get_hdr_data(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID), &hdr_data);

	return hdr_data->metadata_type_one;
}

static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
{
{
	return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support &&
	return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support &&
@@ -1246,6 +1272,72 @@ end:
	return ret;
	return ret;
}
}


static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	int ret = 0;
	u32 const hdr_param_count = 13;
	struct hdmi_tx_ctrl *ctrl = NULL;

	ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
	if (!ctrl) {
		pr_err("%s: invalid input\n", __func__);
		ret = -EINVAL;
		goto end;
	}

	if (!hdmi_tx_is_hdr_supported(ctrl)) {
		pr_err("%s: Sink does not support HDR\n", __func__);
		ret = -EINVAL;
		goto end;
	}

	if (sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u %u",
			&ctrl->hdr_data.eotf,
			&ctrl->hdr_data.display_primaries_x[0],
			&ctrl->hdr_data.display_primaries_y[0],
			&ctrl->hdr_data.display_primaries_x[1],
			&ctrl->hdr_data.display_primaries_y[1],
			&ctrl->hdr_data.display_primaries_x[2],
			&ctrl->hdr_data.display_primaries_y[2],
			&ctrl->hdr_data.white_point_x,
			&ctrl->hdr_data.white_point_y,
			&ctrl->hdr_data.max_luminance,
			&ctrl->hdr_data.min_luminance,
			&ctrl->hdr_data.max_content_light_level,
			&ctrl->hdr_data.max_average_light_level)
			!= hdr_param_count) {
		pr_err("%s: Invalid HDR stream data\n", __func__);
		ret = -EINVAL;
		goto end;
	}

	pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
			__func__,
			ctrl->hdr_data.eotf,
			ctrl->hdr_data.display_primaries_x[0],
			ctrl->hdr_data.display_primaries_y[0],
			ctrl->hdr_data.display_primaries_x[1],
			ctrl->hdr_data.display_primaries_y[1],
			ctrl->hdr_data.display_primaries_x[2],
			ctrl->hdr_data.display_primaries_y[2]);

	pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
			__func__,
			ctrl->hdr_data.white_point_x,
			ctrl->hdr_data.white_point_y,
			ctrl->hdr_data.max_luminance,
			ctrl->hdr_data.min_luminance,
			ctrl->hdr_data.max_content_light_level,
			ctrl->hdr_data.max_average_light_level);

	hdmi_panel_set_hdr_infoframe(ctrl);

	ret = strnlen(buf, PAGE_SIZE);
end:
	return ret;
}

static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
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(hdmi_audio_cb, S_IWUSR, NULL, hdmi_tx_sysfs_wta_audio_cb);
static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug);
static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug);
@@ -1266,6 +1358,7 @@ 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,
static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_s3d_mode,
	hdmi_tx_sysfs_wta_s3d_mode);
	hdmi_tx_sysfs_wta_s3d_mode);
static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v);
static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v);
static DEVICE_ATTR(hdr_stream, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hdr_stream);


static struct attribute *hdmi_tx_fs_attrs[] = {
static struct attribute *hdmi_tx_fs_attrs[] = {
	&dev_attr_connected.attr,
	&dev_attr_connected.attr,
@@ -1281,6 +1374,7 @@ static struct attribute *hdmi_tx_fs_attrs[] = {
	&dev_attr_avi_cn0_1.attr,
	&dev_attr_avi_cn0_1.attr,
	&dev_attr_s3d_mode.attr,
	&dev_attr_s3d_mode.attr,
	&dev_attr_5v.attr,
	&dev_attr_5v.attr,
	&dev_attr_hdr_stream.attr,
	NULL,
	NULL,
};
};
static struct attribute_group hdmi_tx_fs_attrs_group = {
static struct attribute_group hdmi_tx_fs_attrs_group = {
@@ -2210,7 +2304,7 @@ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)


	DEV_DBG("%s: Features <HDMI:%s, HDCP:%s, Deep Color:%s>\n", __func__,
	DEV_DBG("%s: Features <HDMI:%s, HDCP:%s, Deep Color:%s>\n", __func__,
		hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON",
		hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON",
		hdmi_ctrl->dc_feature_on ? "OFF" : "ON");
		!hdmi_ctrl->dc_feature_on ? "OFF" : "ON");


	if (hdmi_disabled) {
	if (hdmi_disabled) {
		DEV_ERR("%s: HDMI disabled\n", __func__);
		DEV_ERR("%s: HDMI disabled\n", __func__);
@@ -2636,6 +2730,102 @@ static void hdmi_tx_phy_reset(struct hdmi_tx_ctrl *hdmi_ctrl)
		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL);
		DSS_REG_W_ND(io, HDMI_PHY_CTRL, val | SW_RESET_PLL);
} /* hdmi_tx_phy_reset */
} /* hdmi_tx_phy_reset */


static void hdmi_panel_set_hdr_infoframe(struct hdmi_tx_ctrl *ctrl)
{
	u32 packet_payload = 0;
	u32 packet_header = 0;
	u32 packet_control = 0;
	u32 const type_code = 0x87;
	u32 const version = 0x01;
	u32 const length = 0x1a;
	u32 const descriptor_id = 0x00;
	struct dss_io_data *io = NULL;

	if (!ctrl) {
		pr_err("%s: invalid input\n", __func__);
		return;
	}

	if (!hdmi_tx_is_hdr_supported(ctrl)) {
		pr_err("%s: Sink does not support HDR\n", __func__);
		return;
	}

	io = &ctrl->pdata.io[HDMI_TX_CORE_IO];
	if (!io->base) {
		pr_err("%s: core io not inititalized\n", __func__);
		return;
	}

	/* Setup Packet header and payload */
	packet_header = type_code | (version << 8) | (length << 16);
	DSS_REG_W(io, HDMI_GENERIC0_HDR, packet_header);

	packet_payload = (ctrl->hdr_data.eotf << 8);
	if (hdmi_tx_metadata_type_one(ctrl)) {
		packet_payload |= (descriptor_id << 16)
			| (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[0])
					<< 24);
		DSS_REG_W(io, HDMI_GENERIC0_0, packet_payload);
	} else {
		pr_debug("%s: Metadata Type 1 not supported\n", __func__);
		DSS_REG_W(io, HDMI_GENERIC0_0, packet_payload);
		goto enable_packet_control;
	}

	packet_payload =
		(HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[0]))
		| (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[0]) << 8)
		| (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[0]) << 16)
		| (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[1]) << 24);
	DSS_REG_W(io, HDMI_GENERIC0_1, packet_payload);

	packet_payload =
		(HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[1]))
		| (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[1]) << 8)
		| (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[1]) << 16)
		| (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_x[2]) << 24);
	DSS_REG_W(io, HDMI_GENERIC0_2, packet_payload);

	packet_payload =
		(HDMI_GET_MSB(ctrl->hdr_data.display_primaries_x[2]))
		| (HDMI_GET_LSB(ctrl->hdr_data.display_primaries_y[2]) << 8)
		| (HDMI_GET_MSB(ctrl->hdr_data.display_primaries_y[2]) << 16)
		| (HDMI_GET_LSB(ctrl->hdr_data.white_point_x) << 24);
	DSS_REG_W(io, HDMI_GENERIC0_3, packet_payload);

	packet_payload =
		(HDMI_GET_MSB(ctrl->hdr_data.white_point_x))
		| (HDMI_GET_LSB(ctrl->hdr_data.white_point_y) << 8)
		| (HDMI_GET_MSB(ctrl->hdr_data.white_point_y) << 16)
		| (HDMI_GET_LSB(ctrl->hdr_data.max_luminance) << 24);
	DSS_REG_W(io, HDMI_GENERIC0_4, packet_payload);

	packet_payload =
		(HDMI_GET_MSB(ctrl->hdr_data.max_luminance))
		| (HDMI_GET_LSB(ctrl->hdr_data.min_luminance) << 8)
		| (HDMI_GET_MSB(ctrl->hdr_data.min_luminance) << 16)
		| (HDMI_GET_LSB(ctrl->hdr_data.max_content_light_level) << 24);
	DSS_REG_W(io, HDMI_GENERIC0_5, packet_payload);

	packet_payload =
		(HDMI_GET_MSB(ctrl->hdr_data.max_content_light_level))
		| (HDMI_GET_LSB(ctrl->hdr_data.max_average_light_level) << 8)
		| (HDMI_GET_MSB(ctrl->hdr_data.max_average_light_level) << 16);
	DSS_REG_W(io, HDMI_GENERIC0_6, packet_payload);

enable_packet_control:
	/*
	 * GENERIC0_LINE | GENERIC0_CONT | GENERIC0_SEND
	 * Setup HDMI TX generic packet control
	 * Enable this packet to transmit every frame
	 * Enable HDMI TX engine to transmit Generic packet 1
	 */
	packet_control = DSS_REG_R_ND(io, HDMI_GEN_PKT_CTRL);
	packet_control |= BIT(0) | BIT(1) | BIT(2) | BIT(16);
	DSS_REG_W(io, HDMI_GEN_PKT_CTRL, packet_control);
}

static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
	struct msm_ext_disp_audio_setup_params *params)
	struct msm_ext_disp_audio_setup_params *params)
{
{
+26 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include "mdss_hdmi_audio.h"
#include "mdss_hdmi_audio.h"


#define MAX_SWITCH_NAME_SIZE        5
#define MAX_SWITCH_NAME_SIZE        5
#define HDR_PRIMARIES_COUNT	3


enum hdmi_tx_io_type {
enum hdmi_tx_io_type {
	HDMI_TX_CORE_IO,
	HDMI_TX_CORE_IO,
@@ -61,6 +62,30 @@ struct hdmi_tx_pinctrl {
struct hdmi_tx_ctrl;
struct hdmi_tx_ctrl;
typedef int (*hdmi_tx_evt_handler) (struct hdmi_tx_ctrl *);
typedef int (*hdmi_tx_evt_handler) (struct hdmi_tx_ctrl *);


/*
 * struct hdmi_tx_hdr_stream - HDR video stream characteristics
 * @eotf: Electro-Optical Transfer Function
 * @display_primaries_x: display primaries data for x-coordinate
 * @display_primaries_y: display primaries data for y-coordinate
 * @white_point_x: white point data for x-coordinate
 * @white_point_y: white point data for y-coordinate
 * @max_luminance: content maximum luminance
 * @min_luminance: content minimum luminance
 * @max_content_light_level: content maximum light level
 * @max_average_light_level: content average light level
 */
struct hdmi_tx_hdr_stream_data {
	u32 eotf;
	u32 display_primaries_x[HDR_PRIMARIES_COUNT];
	u32 display_primaries_y[HDR_PRIMARIES_COUNT];
	u32 white_point_x;
	u32 white_point_y;
	u32 max_luminance;
	u32 min_luminance;
	u32 max_content_light_level;
	u32 max_average_light_level;
};

struct hdmi_tx_ctrl {
struct hdmi_tx_ctrl {
	struct platform_device *pdev;
	struct platform_device *pdev;
	struct hdmi_tx_platform_data pdata;
	struct hdmi_tx_platform_data pdata;
@@ -88,6 +113,7 @@ struct hdmi_tx_ctrl {
	struct hdmi_panel_ops panel_ops;
	struct hdmi_panel_ops panel_ops;
	struct msm_ext_disp_audio_setup_params audio_params;
	struct msm_ext_disp_audio_setup_params audio_params;
	struct work_struct fps_work;
	struct work_struct fps_work;
	struct hdmi_tx_hdr_stream_data hdr_data;


	spinlock_t hpd_state_lock;
	spinlock_t hpd_state_lock;