diff mbox

[v4,1/4] drm: Helper for lspcon in drm_dp_dual_mode

Message ID 1471366049-28737-2-git-send-email-shashank.sharma@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Sharma, Shashank Aug. 16, 2016, 4:47 p.m. UTC
This patch adds lspcon support in dp_dual_mode helper.
lspcon is essentially a dp->hdmi dongle with dual personality.

LS mode: It works as a passive dongle, by level shifting DP++
signals to HDMI signals, in LS mode.
PCON mode: It works as a protocol converter active dongle
in pcon mode, by converting DP++ outputs to HDMI 2.0 outputs.

This patch adds support for lspcon detection and mode set
switch operations, as a dp dual mode dongle.

v2: Addressed review comments from Ville
- add adaptor id for lspcon devices (0x08), use it to identify lspcon
- change function names
  old: drm_lspcon_get_current_mode/drm_lspcon_change_mode
  new: drm_lspcon_get_mode/drm_lspcon_set_mode
- change drm_lspcon_get_mode type to int, to match
  drm_dp_dual_mode_get_tmds_output
- change 'err' to 'ret' to match the rest of the functions
- remove pointless typecasting during call to dual_mode_read
- fix the but while setting value of data, while writing lspcon mode
- fix indentation
- change mdelay(10) -> msleep(10)
- return ETIMEDOUT instead of EFAULT, when lspcon mode change times out
- Add an empty line to separate std regs macros and lspcon regs macros
  Indent bit definition

v3: Addressed review comments from Rodrigo
- change macro name from DP_DUAL_MODE_TYPE_LSPCON to
  DP_DUAL_MODE_TYPE_HAS_DPCD for better readability
- change macro name from DP_DUAL_MODE_LSPCON_MODE_PCON to
  DP_DUAL_MODE_LSPCON_MODE_PCON for better readability
- add comment for MCA specific offsets like 0x40 and 0x41
- remove DP_DUAL_MODE_REV_TYPE2 check while checking lspcon adapter id

v4: Addressed review comments from Ville
- Fixed indentation at few places
- s/current_mode/mode
- s/reqd_mode/mode
- remove unnecessary void* cast
- remove drm_edid.h from includes
- Add a comment for _HAS_DPCD
- Fix enum description, for lspcon_mode.

Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
---
 drivers/gpu/drm/drm_dp_dual_mode_helper.c | 103 ++++++++++++++++++++++++++++++
 include/drm/drm_dp_dual_mode_helper.h     |  26 ++++++++
 2 files changed, 129 insertions(+)

Comments

kernel test robot Aug. 24, 2016, 1:22 a.m. UTC | #1
Hi Shashank,

[auto build test WARNING on drm-intel/for-linux-next]
[also build test WARNING on v4.8-rc3 next-20160823]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
[Suggest to use git(>=2.9.0) format-patch --base=<commit> (or --base=auto for convenience) to record what (public, well-known) commit your patch series was built on]
[Check https://git-scm.com/docs/git-format-patch for more information]

url:    https://github.com/0day-ci/linux/commits/Shashank-Sharma/Enable-lspcon-support-for-GEN9-devices/20160818-183353
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   include/drm/drm_fourcc.h:1: warning: no structured comments found
   include/drm/drm_crtc.h:848: warning: No description found for parameter 'index'
   include/drm/drm_crtc.h:1223: warning: No description found for parameter 'index'
   include/drm/drm_crtc.h:1720: warning: No description found for parameter 'index'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'connector_ida'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'edid_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'dpms_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'path_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tile_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'plane_type_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'rotation_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_src_x'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_src_y'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_src_w'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_src_h'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_crtc_x'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_crtc_y'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_crtc_w'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_crtc_h'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_fb_id'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_crtc_id'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_active'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'prop_mode_id'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'dvi_i_subconnector_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'dvi_i_select_subconnector_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_subconnector_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_select_subconnector_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_mode_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_left_margin_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_right_margin_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_top_margin_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_bottom_margin_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_brightness_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_contrast_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_flicker_reduction_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_overscan_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_saturation_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'tv_hue_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'scaling_mode_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'aspect_ratio_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'dirty_info_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'suggested_x_property'
   include/drm/drm_crtc.h:2505: warning: No description found for parameter 'suggested_y_property'
   include/drm/drmP.h:172: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:188: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:206: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:251: warning: No description found for parameter 'dev'
   include/drm/drmP.h:251: warning: No description found for parameter 'data'
   include/drm/drmP.h:251: warning: No description found for parameter 'file_priv'
   include/drm/drmP.h:284: warning: No description found for parameter 'ioctl'
   include/drm/drmP.h:284: warning: No description found for parameter '_func'
   include/drm/drmP.h:284: warning: No description found for parameter '_flags'
   include/drm/drmP.h:365: warning: cannot understand function prototype: 'struct drm_lock_data '
   include/drm/drmP.h:392: warning: cannot understand function prototype: 'struct drm_driver '
   include/drm/drmP.h:655: warning: cannot understand function prototype: 'struct drm_info_list '
   include/drm/drmP.h:665: warning: cannot understand function prototype: 'struct drm_info_node '
   include/drm/drmP.h:675: warning: cannot understand function prototype: 'struct drm_minor '
   include/drm/drmP.h:720: warning: cannot understand function prototype: 'struct drm_device '
   include/drm/drm_dp_helper.h:752: warning: No description found for parameter 'i2c_nack_count'
   include/drm/drm_dp_helper.h:752: warning: No description found for parameter 'i2c_defer_count'
>> drivers/gpu/drm/drm_dp_dual_mode_helper.c:390: warning: No description found for parameter 'adapter'
>> drivers/gpu/drm/drm_dp_dual_mode_helper.c:390: warning: No description found for parameter 'mode'
>> drivers/gpu/drm/drm_dp_dual_mode_helper.c:390: warning: Excess function parameter 'i2c_adapter' description in 'drm_lspcon_get_mode'
>> drivers/gpu/drm/drm_dp_dual_mode_helper.c:390: warning: Excess function parameter 'current_mode' description in 'drm_lspcon_get_mode'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:426: warning: No description found for parameter 'adapter'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:426: warning: No description found for parameter 'mode'
>> drivers/gpu/drm/drm_dp_dual_mode_helper.c:426: warning: Excess function parameter 'i2c_adapter' description in 'drm_lspcon_set_mode'
>> drivers/gpu/drm/drm_dp_dual_mode_helper.c:426: warning: Excess function parameter 'reqd_mode' description in 'drm_lspcon_set_mode'
>> include/drm/drm_dp_dual_mode_helper.h:84: warning: Enum value 'DRM_LSPCON_MODE_INVALID' not described in enum 'drm_lspcon_mode'
>> include/drm/drm_dp_dual_mode_helper.h:84: warning: Enum value 'DRM_LSPCON_MODE_LS' not described in enum 'drm_lspcon_mode'
>> include/drm/drm_dp_dual_mode_helper.h:84: warning: Enum value 'DRM_LSPCON_MODE_PCON' not described in enum 'drm_lspcon_mode'
>> include/drm/drm_dp_dual_mode_helper.h:104: warning: Enum value 'DRM_DP_DUAL_MODE_LSPCON' not described in enum 'drm_dp_dual_mode_type'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:391: warning: No description found for parameter 'adapter'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:391: warning: No description found for parameter 'mode'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:391: warning: Excess function parameter 'i2c_adapter' description in 'drm_lspcon_get_mode'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:391: warning: Excess function parameter 'current_mode' description in 'drm_lspcon_get_mode'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:427: warning: No description found for parameter 'adapter'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:427: warning: No description found for parameter 'mode'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:427: warning: Excess function parameter 'i2c_adapter' description in 'drm_lspcon_set_mode'
   drivers/gpu/drm/drm_dp_dual_mode_helper.c:427: warning: Excess function parameter 'reqd_mode' description in 'drm_lspcon_set_mode'
   drivers/gpu/drm/drm_dp_mst_topology.c:2383: warning: No description found for parameter 'connector'
   include/drm/drm_dp_mst_helper.h:93: warning: No description found for parameter 'cached_edid'
   include/drm/drm_dp_mst_helper.h:93: warning: No description found for parameter 'has_audio'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'max_dpcd_transaction_bytes'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'sink_count'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'total_slots'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'avail_slots'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'total_pbn'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'qlock'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'tx_msg_downq'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'tx_down_in_progress'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'payload_lock'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'proposed_vcpis'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'payloads'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'payload_mask'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'vcpi_mask'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'tx_waitq'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'work'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'tx_work'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'destroy_connector_list'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'destroy_connector_lock'
   include/drm/drm_dp_mst_helper.h:467: warning: No description found for parameter 'destroy_connector_work'
   drivers/gpu/drm/drm_dp_mst_topology.c:2384: warning: No description found for parameter 'connector'
   drivers/gpu/drm/i915/i915_vgpu.c:105: warning: No description found for parameter 'dev_priv'
   drivers/gpu/drm/i915/i915_vgpu.c:184: warning: No description found for parameter 'dev_priv'
   drivers/gpu/drm/i915/i915_vgpu.c:184: warning: Excess function parameter 'dev' description in 'intel_vgt_balloon'
   drivers/gpu/drm/i915/i915_vgpu.c:106: warning: No description found for parameter 'dev_priv'
   drivers/gpu/drm/i915/i915_vgpu.c:185: warning: No description found for parameter 'dev_priv'
   drivers/gpu/drm/i915/i915_vgpu.c:185: warning: Excess function parameter 'dev' description in 'intel_vgt_balloon'
   drivers/gpu/drm/i915/i915_gem.c:929: warning: No description found for parameter 'i915'
   drivers/gpu/drm/i915/i915_gem.c:929: warning: Excess function parameter 'dev' description in 'i915_gem_gtt_pwrite_fast'
   drivers/gpu/drm/i915/intel_hotplug.c:543: warning: Excess function parameter 'enabled' description in 'intel_hpd_poll_init'
   drivers/gpu/drm/i915/intel_hotplug.c:544: warning: Excess function parameter 'enabled' description in 'intel_hpd_poll_init'
   drivers/gpu/drm/i915/intel_fbc.c:1087: warning: No description found for parameter 'crtc_state'
   drivers/gpu/drm/i915/intel_fbc.c:1087: warning: No description found for parameter 'plane_state'
   drivers/gpu/drm/i915/intel_fbc.c:1088: warning: No description found for parameter 'crtc_state'
   drivers/gpu/drm/i915/intel_fbc.c:1088: warning: No description found for parameter 'plane_state'
   Documentation/gpu/drm-internals.rst:249: ERROR: Unexpected indentation.
   Documentation/gpu/drm-internals.rst:188: ERROR: Unknown target name: "devm".
   Documentation/gpu/drm-kms.rst:929: WARNING: Inline literal start-string without end-string.
   Documentation/gpu/drm-kms.rst:971: WARNING: Inline literal start-string without end-string.
   Documentation/gpu/drm-kms.rst:1451: WARNING: Inline literal start-string without end-string.
   Documentation/gpu/drm-kms.rst:1565: WARNING: Inline literal start-string without end-string.
   Documentation/gpu/drm-kms.rst:1615: WARNING: Inline literal start-string without end-string.
   Documentation/gpu/drm-kms.rst:1627: WARNING: Inline literal start-string without end-string.
   Documentation/gpu/drm-kms.rst:836: WARNING: Option list ends without a blank line; unexpected unindent.
   Documentation/gpu/drm-kms-helpers.rst:647: WARNING: Inline emphasis start-string without end-string.
   Documentation/gpu/drm-kms-helpers.rst:275: WARNING: Inline literal start-string without end-string.
   Documentation/gpu/drm-mm.rst:505: WARNING: Inline emphasis start-string without end-string.
   drivers/gpu/drm/i915/intel_uncore.c:1622: ERROR: Unexpected indentation.
   Documentation/gpu/i915.rst:156: WARNING: Block quote ends without a blank line; unexpected unindent.
   drivers/gpu/drm/i915/intel_uncore.c:1656: ERROR: Unexpected indentation.
   Documentation/gpu/i915.rst:192: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/gpu/i915.rst:129: WARNING: Literal block ends without a blank line; unexpected unindent.
   Documentation/gpu/i915.rst:148: WARNING: Inline emphasis start-string without end-string.
   Documentation/gpu/i915.rst:148: WARNING: Inline emphasis start-string without end-string.
   drivers/gpu/drm/i915/intel_lrc.c:1165: ERROR: Unexpected indentation.
   Documentation/gpu/i915.rst:339: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/gpu/i915.rst:329: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/gpu/i915.rst:348: WARNING: Enumerated list ends without a blank line; unexpected unindent.
   Documentation/gpu/drm-kms.rst:499: WARNING: Could not lex literal_block as "C". Highlighting skipped.
   Documentation/gpu/drm-kms-helpers.rst:125: WARNING: Could not lex literal_block as "C". Highlighting skipped.
   Documentation/gpu/i915.rst:109: WARNING: Could not lex literal_block as "C". Highlighting skipped.

vim +/adapter +390 drivers/gpu/drm/drm_dp_dual_mode_helper.c

   384	 * Returns:
   385	 * 0 on success, sets the current_mode value to appropriate mode
   386	 * -error on failure
   387	 */
   388	int drm_lspcon_get_mode(struct i2c_adapter *adapter,
   389				enum drm_lspcon_mode *mode)
 > 390	{
   391		u8 data;
   392		int ret = 0;
   393	
   394		if (!mode) {
   395			DRM_ERROR("NULL input\n");
   396			return -EINVAL;
   397		}
   398	
   399		/* Read Status: i2c over aux */
   400		ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_LSPCON_CURRENT_MODE,
   401					    &data, sizeof(data));
   402		if (ret < 0) {
   403			DRM_ERROR("LSPCON read(0x80, 0x41) failed\n");
   404			return -EFAULT;
   405		}
   406	
   407		if (data & DP_DUAL_MODE_LSPCON_MODE_PCON)
   408			*mode = DRM_LSPCON_MODE_PCON;
   409		else
   410			*mode = DRM_LSPCON_MODE_LS;
   411		return 0;
   412	}
   413	EXPORT_SYMBOL(drm_lspcon_get_mode);
   414	
   415	/**
   416	 * drm_lspcon_change_mode: Change LSPCON's mode of operation by
   417	 * by writing offset (0x80, 0x40)
   418	 * @i2c_adapter: I2C-over-aux adapter
   419	 * @reqd_mode: required mode of operation
   420	 *
   421	 * Returns:
   422	 * 0 on success, -error on failure/timeout
   423	 */
   424	int drm_lspcon_set_mode(struct i2c_adapter *adapter,
   425				enum drm_lspcon_mode mode)
 > 426	{
   427		u8 data = 0;
   428		int ret;
   429		int time_out = 200;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_dp_dual_mode_helper.c b/drivers/gpu/drm/drm_dp_dual_mode_helper.c
index a7b2a75..a7aeb1e 100644
--- a/drivers/gpu/drm/drm_dp_dual_mode_helper.c
+++ b/drivers/gpu/drm/drm_dp_dual_mode_helper.c
@@ -148,6 +148,14 @@  static bool is_type2_adaptor(uint8_t adaptor_id)
 			      DP_DUAL_MODE_REV_TYPE2);
 }
 
+bool is_lspcon_adaptor(const char hdmi_id[DP_DUAL_MODE_HDMI_ID_LEN],
+	const uint8_t adaptor_id)
+{
+	return is_hdmi_adaptor(hdmi_id) &&
+		(adaptor_id == (DP_DUAL_MODE_TYPE_TYPE2 |
+		 DP_DUAL_MODE_TYPE_HAS_DPCD));
+}
+
 /**
  * drm_dp_dual_mode_detect - Identify the DP dual mode adaptor
  * @adapter: I2C adapter for the DDC bus
@@ -203,6 +211,8 @@  enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter)
 	ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_ADAPTOR_ID,
 				    &adaptor_id, sizeof(adaptor_id));
 	if (ret == 0) {
+		if (is_lspcon_adaptor(hdmi_id, adaptor_id))
+			return DRM_DP_DUAL_MODE_LSPCON;
 		if (is_type2_adaptor(adaptor_id)) {
 			if (is_hdmi_adaptor(hdmi_id))
 				return DRM_DP_DUAL_MODE_TYPE2_HDMI;
@@ -364,3 +374,96 @@  const char *drm_dp_get_dual_mode_type_name(enum drm_dp_dual_mode_type type)
 	}
 }
 EXPORT_SYMBOL(drm_dp_get_dual_mode_type_name);
+
+/**
+ * drm_lspcon_get_mode: Get LSPCON's current mode of operation by
+ * by reading offset (0x80, 0x41)
+ * @i2c_adapter: I2C-over-aux adapter
+ * @current_mode: out vaiable, current lspcon mode of operation
+ *
+ * Returns:
+ * 0 on success, sets the current_mode value to appropriate mode
+ * -error on failure
+ */
+int drm_lspcon_get_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode *mode)
+{
+	u8 data;
+	int ret = 0;
+
+	if (!mode) {
+		DRM_ERROR("NULL input\n");
+		return -EINVAL;
+	}
+
+	/* Read Status: i2c over aux */
+	ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_LSPCON_CURRENT_MODE,
+				    &data, sizeof(data));
+	if (ret < 0) {
+		DRM_ERROR("LSPCON read(0x80, 0x41) failed\n");
+		return -EFAULT;
+	}
+
+	if (data & DP_DUAL_MODE_LSPCON_MODE_PCON)
+		*mode = DRM_LSPCON_MODE_PCON;
+	else
+		*mode = DRM_LSPCON_MODE_LS;
+	return 0;
+}
+EXPORT_SYMBOL(drm_lspcon_get_mode);
+
+/**
+ * drm_lspcon_change_mode: Change LSPCON's mode of operation by
+ * by writing offset (0x80, 0x40)
+ * @i2c_adapter: I2C-over-aux adapter
+ * @reqd_mode: required mode of operation
+ *
+ * Returns:
+ * 0 on success, -error on failure/timeout
+ */
+int drm_lspcon_set_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode mode)
+{
+	u8 data = 0;
+	int ret;
+	int time_out = 200;
+	enum drm_lspcon_mode current_mode;
+
+	if (mode == DRM_LSPCON_MODE_PCON)
+		data = DP_DUAL_MODE_LSPCON_MODE_PCON;
+
+	/* Change mode */
+	ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_LSPCON_MODE_CHANGE,
+				     &data, sizeof(data));
+	if (ret < 0) {
+		DRM_ERROR("LSPCON mode change failed\n");
+		return ret;
+	}
+
+	/*
+	 * Confirm mode change by reading the status bit.
+	 * Sometimes, it takes a while to change the mode,
+	 * so wait and retry until time out or done.
+	 */
+	do {
+		ret = drm_lspcon_get_mode(adapter, &current_mode);
+		if (ret) {
+			DRM_ERROR("can't confirm LSPCON mode change\n");
+			return ret;
+		} else {
+			if (current_mode != mode) {
+				msleep(10);
+				time_out -= 10;
+			} else {
+				DRM_DEBUG_KMS("LSPCON mode changed to %s\n",
+						mode == DRM_LSPCON_MODE_LS ?
+						"LS" : "PCON");
+				return 0;
+			}
+		}
+	} while (time_out);
+
+	DRM_ERROR("LSPCON mode change timed out\n");
+	return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(drm_lspcon_set_mode);
diff --git a/include/drm/drm_dp_dual_mode_helper.h b/include/drm/drm_dp_dual_mode_helper.h
index e8a9dfd..5567770 100644
--- a/include/drm/drm_dp_dual_mode_helper.h
+++ b/include/drm/drm_dp_dual_mode_helper.h
@@ -40,6 +40,8 @@ 
 #define  DP_DUAL_MODE_REV_TYPE2 0x00
 #define  DP_DUAL_MODE_TYPE_MASK 0xf0
 #define  DP_DUAL_MODE_TYPE_TYPE2 0xa0
+/* This field is marked reserved in dual mode spec, used in LSPCON */
+#define  DP_DUAL_MODE_TYPE_HAS_DPCD 0x08
 #define DP_DUAL_MODE_IEEE_OUI 0x11 /* 11-13*/
 #define  DP_DUAL_IEEE_OUI_LEN 3
 #define DP_DUAL_DEVICE_ID 0x14 /* 14-19 */
@@ -55,6 +57,11 @@ 
 #define  DP_DUAL_MODE_CEC_ENABLE 0x01
 #define DP_DUAL_MODE_I2C_SPEED_CTRL 0x22
 
+/* LSPCON specific registers, defined by MCA */
+#define DP_DUAL_MODE_LSPCON_MODE_CHANGE		0x40
+#define DP_DUAL_MODE_LSPCON_CURRENT_MODE		0x41
+#define  DP_DUAL_MODE_LSPCON_MODE_PCON			0x1
+
 struct i2c_adapter;
 
 ssize_t drm_dp_dual_mode_read(struct i2c_adapter *adapter,
@@ -63,6 +70,19 @@  ssize_t drm_dp_dual_mode_write(struct i2c_adapter *adapter,
 			       u8 offset, const void *buffer, size_t size);
 
 /**
+* enum drm_lspcon_mode
+* @lspcon_mode_ls: Level shifter mode of LSPCON
+*	which drives DP++ to HDMI 1.4 conversion.
+* @lspcon_mode_pcon: Protocol converter mode of LSPCON
+*	which drives DP++ to HDMI 2.0 active conversion.
+*/
+enum drm_lspcon_mode {
+	DRM_LSPCON_MODE_INVALID,
+	DRM_LSPCON_MODE_LS,
+	DRM_LSPCON_MODE_PCON,
+};
+
+/**
  * enum drm_dp_dual_mode_type - Type of the DP dual mode adaptor
  * @DRM_DP_DUAL_MODE_NONE: No DP dual mode adaptor
  * @DRM_DP_DUAL_MODE_UNKNOWN: Could be either none or type 1 DVI adaptor
@@ -70,6 +90,7 @@  ssize_t drm_dp_dual_mode_write(struct i2c_adapter *adapter,
  * @DRM_DP_DUAL_MODE_TYPE1_HDMI: Type 1 HDMI adaptor
  * @DRM_DP_DUAL_MODE_TYPE2_DVI: Type 2 DVI adaptor
  * @DRM_DP_DUAL_MODE_TYPE2_HDMI: Type 2 HDMI adaptor
+ * @DRM_DP_DUAL_MODE_TYPE2_LSPCON: Level shifter /protocol converter
  */
 enum drm_dp_dual_mode_type {
 	DRM_DP_DUAL_MODE_NONE,
@@ -78,6 +99,7 @@  enum drm_dp_dual_mode_type {
 	DRM_DP_DUAL_MODE_TYPE1_HDMI,
 	DRM_DP_DUAL_MODE_TYPE2_DVI,
 	DRM_DP_DUAL_MODE_TYPE2_HDMI,
+	DRM_DP_DUAL_MODE_LSPCON,
 };
 
 enum drm_dp_dual_mode_type drm_dp_dual_mode_detect(struct i2c_adapter *adapter);
@@ -89,4 +111,8 @@  int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type,
 				     struct i2c_adapter *adapter, bool enable);
 const char *drm_dp_get_dual_mode_type_name(enum drm_dp_dual_mode_type type);
 
+int drm_lspcon_get_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode *current_mode);
+int drm_lspcon_set_mode(struct i2c_adapter *adapter,
+			enum drm_lspcon_mode reqd_mode);
 #endif