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

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

Merge "drm/msm: Add PLL_DELTA property to HDMI connector"

parents 7eacb7e8 b2f2c4d5
Loading
Loading
Loading
Loading
+135 −2
Original line number Diff line number Diff line
@@ -401,12 +401,111 @@ static const struct file_operations edid_vendor_name_fops = {
	.read = _sde_hdmi_edid_vendor_name_read,
};

static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in)
{
	u32 pclk_delta, pclk;
	u64 pclk_clip = pclk_in;

	/* as per standard, 0.5% of deviation is allowed */
	pclk = mode->clock * HDMI_KHZ_TO_HZ;
	pclk_delta = pclk * 5 / 1000;

	if (pclk_in < (pclk - pclk_delta))
		pclk_clip = pclk - pclk_delta;
	else if (pclk_in > (pclk + pclk_delta))
		pclk_clip = pclk + pclk_delta;

	if (pclk_in != pclk_clip)
		pr_warn("clip pclk from %lld to %lld\n", pclk_in, pclk_clip);

	return pclk_clip;
}

/**
 * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm
 *
 * @ppm: ppm is parts per million multiplied by 1000.
 * return: 0 on success, non-zero in case of failure.
 *
 * The input ppm will be clipped if it's more than or less than 5% of the TMDS
 * clock rate defined by HDMI spec.
 */
static int _sde_hdmi_update_pll_delta(struct sde_hdmi *display, s32 ppm)
{
	struct hdmi *hdmi = display->ctrl.ctrl;
	struct drm_display_mode *current_mode = &display->mode;
	u64 cur_pclk, dst_pclk;
	u64 clip_pclk;
	int rc = 0;

	if (!hdmi->power_on || !display->connected) {
		SDE_ERROR("HDMI display is not ready\n");
		return -EINVAL;
	}

	/* get current pclk */
	cur_pclk = hdmi->pixclock;
	/* get desired pclk */
	dst_pclk = cur_pclk * (1000000000 + ppm);
	do_div(dst_pclk, 1000000000);

	clip_pclk = _sde_hdmi_clip_valid_pclk(current_mode, dst_pclk);

	/* update pclk */
	if (clip_pclk != cur_pclk) {
		SDE_DEBUG("PCLK changes from %llu to %llu when delta is %d\n",
				cur_pclk, clip_pclk, ppm);

		rc = clk_set_rate(hdmi->pwr_clks[0], clip_pclk);
		if (rc < 0) {
			SDE_ERROR("PLL update failed, reset clock rate\n");
			return rc;
		}

		hdmi->pixclock = clip_pclk;
	}

	return rc;
}

static ssize_t _sde_hdmi_debugfs_pll_delta_write(struct file *file,
		    const char __user *user_buf, size_t count, loff_t *ppos)
{
	struct sde_hdmi *display = file->private_data;
	char buf[10];
	int ppm = 0;

	if (!display)
		return -ENODEV;

	if (count >= sizeof(buf))
		return -EFAULT;

	if (copy_from_user(buf, user_buf, count))
		return -EFAULT;

	buf[count] = 0;	/* end of string */

	if (kstrtoint(buf, 0, &ppm))
		return -EFAULT;

	if (ppm)
		_sde_hdmi_update_pll_delta(display, ppm);

	return count;
}

static const struct file_operations pll_delta_fops = {
	.open = simple_open,
	.write = _sde_hdmi_debugfs_pll_delta_write,
};

static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
{
	int rc = 0;
	struct dentry *dir, *dump_file, *edid_modes;
	struct dentry *edid_vsdb_info, *edid_hdr_info, *edid_hfvsdb_info;
	struct dentry *edid_vcdb_info, *edid_vendor_name;
	struct dentry *edid_vcdb_info, *edid_vendor_name, *pll_file;

	dir = debugfs_create_dir(display->name, NULL);
	if (!dir) {
@@ -423,7 +522,19 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
					&dump_info_fops);
	if (IS_ERR_OR_NULL(dump_file)) {
		rc = PTR_ERR(dump_file);
		SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
		SDE_ERROR("[%s]debugfs create dump_info file failed, rc=%d\n",
		       display->name, rc);
		goto error_remove_dir;
	}

	pll_file = debugfs_create_file("pll_delta",
					0644,
					dir,
					display,
					&pll_delta_fops);
	if (IS_ERR_OR_NULL(pll_file)) {
		rc = PTR_ERR(pll_file);
		SDE_ERROR("[%s]debugfs create pll_delta file failed, rc=%d\n",
		       display->name, rc);
		goto error_remove_dir;
	}
@@ -1324,6 +1435,28 @@ int sde_hdmi_get_info(struct msm_display_info *info,
	return rc;
}

int sde_hdmi_set_property(struct drm_connector *connector,
			struct drm_connector_state *state,
			int property_index,
			uint64_t value,
			void *display)
{
	int rc = 0;

	if (!connector || !display) {
		SDE_ERROR("connector=%pK or display=%pK is NULL\n",
			connector, display);
		return 0;
	}

	SDE_DEBUG("\n");

	if (property_index == CONNECTOR_PROP_PLL_DELTA)
		rc = _sde_hdmi_update_pll_delta(display, value);

	return rc;
}

u32 sde_hdmi_get_num_of_displays(void)
{
	u32 count = 0;
+28 −0
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ struct sde_hdmi_ctrl {
 * @non_pluggable:    If HDMI display is non pluggable
 * @num_of_modes:     Number of modes supported by display if non pluggable.
 * @mode_list:        Mode list if non pluggable.
 * @mode:             Current display mode.
 * @connected:        If HDMI display is connected.
 * @is_tpg_enabled:   TPG state.
 * @hpd_work:         HPD work structure.
@@ -103,6 +104,7 @@ struct sde_hdmi {
	bool non_pluggable;
	u32 num_of_modes;
	struct list_head mode_list;
	struct drm_display_mode mode;
	bool connected;
	bool is_tpg_enabled;

@@ -269,6 +271,22 @@ int sde_hdmi_drm_deinit(struct sde_hdmi *display);
int sde_hdmi_get_info(struct msm_display_info *info,
				void *display);

/**
 * sde_hdmi_set_property() - set the connector properties
 * @connector:        Handle to the connector.
 * @state:            Handle to the connector state.
 * @property_index:   property index.
 * @value:            property value.
 * @display:          Handle to the display.
 *
 * Return: error code.
 */
int sde_hdmi_set_property(struct drm_connector *connector,
			struct drm_connector_state *state,
			int property_index,
			uint64_t value,
			void *display);

/**
 * sde_hdmi_bridge_init() - init sde hdmi bridge
 * @hdmi:          Handle to the hdmi.
@@ -453,5 +471,15 @@ static inline int sde_hdmi_get_info(struct msm_display_info *info,
{
	return 0;
}

static inline int sde_hdmi_set_property(struct drm_connector *connector,
			struct drm_connector_state *state,
			int property_index,
			uint64_t value,
			void *display)
{
	return 0;
}

#endif /*#else of CONFIG_DRM_SDE_HDMI*/
#endif /* _SDE_HDMI_H_ */
+0 −2
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@
#define HDMI_AUDIO_INFO_FRAME_PACKET_VERSION 0x1
#define HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH 0x0A

#define HDMI_KHZ_TO_HZ 1000
#define HDMI_MHZ_TO_HZ 1000000
#define HDMI_ACR_N_MULTIPLIER 128
#define DEFAULT_AUDIO_SAMPLE_RATE_HZ 48000

+11 −0
Original line number Diff line number Diff line
@@ -568,6 +568,15 @@ static void _sde_hdmi_bridge_set_spd_infoframe(struct hdmi *hdmi,
	hdmi_write(hdmi, REG_HDMI_GEN_PKT_CTRL, packet_control);
}

static inline void _sde_hdmi_save_mode(struct hdmi *hdmi,
	struct drm_display_mode *mode)
{
	struct sde_connector *c_conn = to_sde_connector(hdmi->connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;

	drm_mode_copy(&display->mode, mode);
}

static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
		 struct drm_display_mode *mode,
		 struct drm_display_mode *adjusted_mode)
@@ -640,6 +649,8 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
		DRM_DEBUG("hdmi setup info frame\n");
	}
	_sde_hdmi_bridge_setup_scrambler(hdmi, mode);

	_sde_hdmi_save_mode(hdmi, mode);
}

static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = {
+1 −0
Original line number Diff line number Diff line
@@ -148,6 +148,7 @@ enum msm_mdp_conn_property {
	CONNECTOR_PROP_DST_Y,
	CONNECTOR_PROP_DST_W,
	CONNECTOR_PROP_DST_H,
	CONNECTOR_PROP_PLL_DELTA,

	/* enum/bitmask properties */
	CONNECTOR_PROP_TOPOLOGY_NAME,
Loading