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

Commit b7249f20 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: hdmi: continuous splash screen for HDMI"

parents 4030550f c5ac0a87
Loading
Loading
Loading
Loading
+133 −53
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@
#define COMPATIBLE_NAME "qcom,hdmi-tx"

#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_640x480p60_4_3
#define DEFAULT_HDMI_PRIMARY_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
#define DEFAULT_HDMI_PRIMARY_RESOLUTION HDMI_VFRMT_1280x720p60_16_9

/* HDMI PHY/PLL bit field macros */
#define SW_RESET BIT(2)
@@ -144,6 +144,11 @@ enum hdmi_tx_hpd_states {
	HPD_ENABLE
};

enum hdmi_tx_res_states {
	RESOLUTION_UNCHANGED,
	RESOLUTION_CHANGED
};

/* parameters for clock regeneration */
struct hdmi_tx_audio_acr {
	u32 n;
@@ -1194,14 +1199,21 @@ static inline u32 hdmi_tx_is_controller_on(struct hdmi_tx_ctrl *hdmi_ctrl)
	return DSS_REG_R_ND(io, HDMI_CTRL) & BIT(0);
} /* hdmi_tx_is_controller_on */

static int hdmi_tx_init_panel_info(uint32_t resolution,
	struct mdss_panel_info *pinfo)
static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl)
{
	const struct msm_hdmi_mode_timing_info *timing =
		hdmi_get_supported_mode(resolution);
	struct mdss_panel_info *pinfo;
	const struct msm_hdmi_mode_timing_info *timing;

	if (!hdmi_ctrl) {
		DEV_ERR("%s: invalid input\n", __func__);
		return -EINVAL;
	}

	timing = hdmi_get_supported_mode(hdmi_ctrl->video_resolution);
	pinfo = &hdmi_ctrl->panel_data.panel_info;

	if (!timing || !pinfo) {
		DEV_ERR("%s: invalid input.\n", __func__);
		DEV_ERR("%s: invalid timing data\n", __func__);
		return -EINVAL;
	}

@@ -1226,6 +1238,8 @@ static int hdmi_tx_init_panel_info(uint32_t resolution,
	pinfo->lcdc.underflow_clr = 0xff; /* blue */
	pinfo->lcdc.hsync_skew = 0;

	pinfo->cont_splash_enabled = hdmi_ctrl->pdata.cont_splash_enabled;

	return 0;
} /* hdmi_tx_init_panel_info */

@@ -1310,11 +1324,16 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
			DEV_ERR("%s: Failed to enable ddc power\n", __func__);
			return;
		}

		/* Enable SW DDC before EDID read */
		DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION ,
			DSS_REG_R(io, HDMI_DDC_ARBITRATION) & ~(BIT(4)));

		hdmi_tx_read_sink_info(hdmi_ctrl);

		if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false))
			DEV_ERR("%s: Failed to disable ddc power\n", __func__);

		hdmi_tx_send_cable_notification(hdmi_ctrl, 1);
		DEV_INFO("%s: sense cable CONNECTED: state switch to %d\n",
			__func__, hdmi_ctrl->sdev.state);
@@ -1322,13 +1341,6 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
		hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0, false);
		hdmi_tx_wait_for_audio_engine(hdmi_ctrl);

		if (!hdmi_ctrl->panel_power_on) {
			if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM,
				false))
				DEV_WARN("%s: Failed to disable ddc power\n",
					__func__);
		}

		hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
		DEV_INFO("%s: sense cable DISCONNECTED: state switch to %d\n",
			__func__, hdmi_ctrl->sdev.state);
@@ -1384,6 +1396,7 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl,
{
	int new_vic = -1;
	const struct msm_hdmi_mode_timing_info *timing = NULL;
	int res_changed = RESOLUTION_UNCHANGED;

	if (!hdmi_ctrl || !pinfo) {
		DEV_ERR("%s: invalid input\n", __func__);
@@ -1396,9 +1409,12 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl,
		return -EPERM;
	}

	if (hdmi_ctrl->video_resolution != new_vic) {
		res_changed = RESOLUTION_CHANGED;
		DEV_DBG("%s: switching from %s => %s", __func__,
			msm_hdmi_mode_2string(hdmi_ctrl->video_resolution),
			msm_hdmi_mode_2string(new_vic));
	}

	hdmi_ctrl->video_resolution = (u32)new_vic;

@@ -1417,7 +1433,7 @@ static int hdmi_tx_set_video_fmt(struct hdmi_tx_ctrl *hdmi_ctrl,
		hdmi_ctrl->feature_data[HDMI_TX_FEAT_EDID],
		hdmi_ctrl->video_resolution);

	return 0;
	return res_changed;
} /* hdmi_tx_set_video_fmt */

static int hdmi_tx_video_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
@@ -1974,6 +1990,12 @@ static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
	}

	if (enable) {
		if (hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) {
			DEV_DBG("%s: %s already eanbled by splash\n",
				__func__, hdmi_pm_name(module));
			return 0;
		}

		rc = msm_dss_enable_vreg(power_data->vreg_config,
			power_data->num_vreg, 1);
		if (rc) {
@@ -2763,9 +2785,6 @@ static void hdmi_tx_power_off_work(struct work_struct *work)
		return;
	}

	if (hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM, false))
		DEV_WARN("%s: Failed to disable ddc power\n", __func__);

	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl))
		hdmi_tx_audio_off(hdmi_ctrl);

@@ -2796,7 +2815,9 @@ static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
	struct hdmi_tx_ctrl *hdmi_ctrl =
		hdmi_tx_get_drvdata_from_panel_data(panel_data);

	if (!hdmi_ctrl || !hdmi_ctrl->panel_power_on) {
	if (!hdmi_ctrl ||
		(!panel_data->panel_info.cont_splash_enabled &&
		!hdmi_ctrl->panel_power_on)) {
		DEV_ERR("%s: invalid input\n", __func__);
		return -EINVAL;
	}
@@ -2815,7 +2836,9 @@ static int hdmi_tx_power_off(struct mdss_panel_data *panel_data)
static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
{
	int rc = 0;
	int res_changed = RESOLUTION_UNCHANGED;
	struct dss_io_data *io = NULL;
	struct mdss_panel_info *panel_info = NULL;
	struct hdmi_tx_ctrl *hdmi_ctrl =
		hdmi_tx_get_drvdata_from_panel_data(panel_data);

@@ -2835,19 +2858,33 @@ static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
		return -EPERM;
	}

	panel_info = &panel_data->panel_info;
	hdmi_ctrl->hdcp_feature_on = hdcp_feature_on;

	/* If a power down is already underway, wait for it to finish */
	flush_work(&hdmi_ctrl->power_off_work);

	rc = hdmi_tx_set_video_fmt(hdmi_ctrl, &panel_data->panel_info);
	if (rc) {
		DEV_ERR("%s: cannot set video_fmt.rc=%d\n", __func__, rc);
		return rc;
	}
	res_changed = hdmi_tx_set_video_fmt(hdmi_ctrl, panel_info);

	hdmi_ctrl->hdcp_feature_on = hdcp_feature_on;
	DEV_DBG("%s: %dx%d%s\n", __func__,
		panel_info->xres, panel_info->yres,
		panel_info->cont_splash_enabled ? " (handoff underway)" : "");

	DEV_INFO("power: ON (%s)\n", msm_hdmi_mode_2string(
		hdmi_ctrl->video_resolution));
	if (hdmi_ctrl->pdata.cont_splash_enabled) {
		hdmi_ctrl->pdata.cont_splash_enabled = false;

		if (res_changed == RESOLUTION_UNCHANGED) {
			hdmi_ctrl->panel_power_on = true;
			hdmi_cec_config(
				hdmi_ctrl->feature_data[HDMI_TX_FEAT_CEC]);

			if (!hdmi_ctrl->hdcp_feature_on ||
				!hdmi_ctrl->present_hdcp)
				hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1,
					false);
			goto end;
		}
	}

	rc = hdmi_tx_core_on(hdmi_ctrl);
	if (rc) {
@@ -2871,7 +2908,7 @@ static int hdmi_tx_power_on(struct mdss_panel_data *panel_data)
			return rc;
		}
	}

end:
	dss_reg_dump(io->base, io->len, "HDMI-ON: ", REG_DUMP);

	DEV_INFO("%s: HDMI=%s DVI= %s\n", __func__,
@@ -2967,9 +3004,11 @@ static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl)

		dss_reg_dump(io->base, io->len, "HDMI-INIT: ", REG_DUMP);

		if (!hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) {
			hdmi_tx_set_mode(hdmi_ctrl, false);
			hdmi_tx_phy_reset(hdmi_ctrl);
			hdmi_tx_set_mode(hdmi_ctrl, true);
		}

		DSS_REG_W(io, HDMI_USEC_REFTIMER, 0x0001001B);

@@ -3326,13 +3365,22 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
		break;

	case MDSS_EVENT_PANEL_ON:
		if (hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
		if (!hdmi_ctrl->panel_data.panel_info.cont_splash_enabled &&
			hdmi_ctrl->hdcp_feature_on && hdmi_ctrl->present_hdcp) {
			/* Set AV Mute before starting authentication */
			if (hdmi_ctrl->pdata.primary)
				hdmi_tx_en_encryption(hdmi_ctrl, false);
			else
				rc = hdmi_tx_config_avmute(hdmi_ctrl, 1);

			rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM,
				true);
			if (rc) {
				DEV_ERR("%s: Failed to enable ddc power\n",
					__func__);
				break;
			}

			DEV_DBG("%s: Starting HDCP authentication\n", __func__);
			rc = hdmi_hdcp_authenticate(
				hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);
@@ -3360,6 +3408,12 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
			DEV_DBG("%s: Turning off HDCP\n", __func__);
			hdmi_hdcp_off(
				hdmi_ctrl->feature_data[HDMI_TX_FEAT_HDCP]);

			rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_DDC_PM,
				false);
			if (rc)
				DEV_ERR("%s: Failed to disable ddc power\n",
					__func__);
		}
		break;

@@ -3377,9 +3431,14 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
		break;

	case MDSS_EVENT_CLOSE:
		if (panel_data->panel_info.cont_splash_enabled) {
			hdmi_tx_power_off(panel_data);
			panel_data->panel_info.cont_splash_enabled = false;
		} else {
			if (hdmi_ctrl->hpd_feature_on)
				hdmi_tx_hpd_polarity_setup(hdmi_ctrl,
					HPD_CONNECT_POLARITY);
		}
		break;
	}

@@ -3403,8 +3462,7 @@ static int hdmi_tx_register_panel(struct hdmi_tx_ctrl *hdmi_ctrl)
	else
		hdmi_ctrl->video_resolution = DEFAULT_VIDEO_RESOLUTION;

	rc = hdmi_tx_init_panel_info(hdmi_ctrl->video_resolution,
		&hdmi_ctrl->panel_data.panel_info);
	rc = hdmi_tx_init_panel_info(hdmi_ctrl);
	if (rc) {
		DEV_ERR("%s: hdmi_init_panel_info failed\n", __func__);
		return rc;
@@ -3908,6 +3966,8 @@ static int hdmi_tx_get_dt_data(struct platform_device *pdev,
{
	int i, rc = 0;
	struct device_node *of_node = NULL;
	struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
	bool splash_en;

	if (!pdev || !pdata) {
		DEV_ERR("%s: invalid input\n", __func__);
@@ -3957,16 +4017,20 @@ static int hdmi_tx_get_dt_data(struct platform_device *pdev,
		}
	}

	if (of_find_property(pdev->dev.of_node, "qcom,primary_panel", NULL)) {
		u32 tmp;
		of_property_read_u32(pdev->dev.of_node, "qcom,primary_panel",
			&tmp);
		pdata->primary = tmp ? true : false;
	}
	if (!hdmi_ctrl->pdata.primary)
		hdmi_ctrl->pdata.primary = of_property_read_bool(
			pdev->dev.of_node, "qcom,primary_panel");

	pdata->cond_power_on = of_property_read_bool(pdev->dev.of_node,
		"qcom,conditional-power-on");

	 splash_en = of_property_read_bool(pdev->dev.of_node,
			"qcom,cont_splash_enabled");

	/* cont splash screen is supported only for hdmi primary */
	pdata->cont_splash_enabled =
		hdmi_ctrl->pdata.primary ? splash_en : false;

	return rc;

error:
@@ -3976,7 +4040,7 @@ error:

static int hdmi_tx_probe(struct platform_device *pdev)
{
	int rc = 0;
	int rc = 0, i;
	struct device_node *of_node = pdev->dev.of_node;
	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
	struct mdss_panel_cfg *pan_cfg = NULL;
@@ -3997,13 +4061,6 @@ static int hdmi_tx_probe(struct platform_device *pdev)
	platform_set_drvdata(pdev, hdmi_ctrl);
	hdmi_ctrl->pdev = pdev;

	rc = hdmi_tx_get_dt_data(pdev, &hdmi_ctrl->pdata);
	if (rc) {
		DEV_ERR("%s: FAILED: parsing device tree data. rc=%d\n",
			__func__, rc);
		goto failed_dt_data;
	}

	pan_cfg = mdss_panel_intf_type(MDSS_PANEL_INTF_HDMI);
	if (IS_ERR(pan_cfg)) {
		return PTR_ERR(pan_cfg);
@@ -4025,6 +4082,13 @@ static int hdmi_tx_probe(struct platform_device *pdev)
		return -ENODEV;
	}

	rc = hdmi_tx_get_dt_data(pdev, &hdmi_ctrl->pdata);
	if (rc) {
		DEV_ERR("%s: FAILED: parsing device tree data. rc=%d\n",
			__func__, rc);
		goto failed_dt_data;
	}

	rc = hdmi_tx_init_resource(hdmi_ctrl);
	if (rc) {
		DEV_ERR("%s: FAILED: resource init. rc=%d\n",
@@ -4058,6 +4122,22 @@ static int hdmi_tx_probe(struct platform_device *pdev)
			hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO].len))
		DEV_WARN("%s: hdmi_tx debugfs register failed\n", __func__);

	if (hdmi_ctrl->panel_data.panel_info.cont_splash_enabled) {
		for (i = 0; i < HDMI_TX_MAX_PM; i++) {
			msm_dss_enable_vreg(
				hdmi_ctrl->pdata.power_data[i].vreg_config,
				hdmi_ctrl->pdata.power_data[i].num_vreg, 1);

			msm_dss_enable_gpio(
				hdmi_ctrl->pdata.power_data[i].gpio_config,
				hdmi_ctrl->pdata.power_data[i].num_gpio, 1);

			msm_dss_enable_clk(
				hdmi_ctrl->pdata.power_data[i].clk_config,
				hdmi_ctrl->pdata.power_data[i].num_clk, 1);
		}
	}

	return rc;

failed_reg_panel:
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ enum hdmi_tx_power_module_type {
/* Data filled from device tree */
struct hdmi_tx_platform_data {
	bool primary;
	bool cont_splash_enabled;
	bool cond_power_on;
	struct dss_io_data io[HDMI_TX_MAX_IO];
	struct dss_module_power power_data[HDMI_TX_MAX_PM];