intel-gfx.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
From: Shashank Sharma <shashank.sharma@intel.com>
To: intel-gfx@lists.freedesktop.org, daniel.vetter@intel.com
Cc: akashdeep.sharma@inte.com
Subject: [PATCH 5/7] drm/i915: Add and register lspcon connector functions
Date: Tue, 22 Mar 2016 19:55:06 +0530	[thread overview]
Message-ID: <1458656708-31228-6-git-send-email-shashank.sharma@intel.com> (raw)
In-Reply-To: <1458656708-31228-1-git-send-email-shashank.sharma@intel.com>

This patch adds various lspcon connector functions. Some
of the functions are newly written, to meet the specific
needs of lspcon HW, whereas few of them are just an
abstraction layer on existing HDMI connector functions.

Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h     |  11 +-
 drivers/gpu/drm/i915/intel_hdmi.c    |   8 +-
 drivers/gpu/drm/i915/intel_hotplug.c |   2 +-
 drivers/gpu/drm/i915/intel_lspcon.c  | 238 ++++++++++++++++++++++++++++++++++-
 4 files changed, 251 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 09273d5..7b19a2c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1403,7 +1403,12 @@ int intel_hdmi_init_minimum(struct intel_digital_port *intel_dig_port,
 struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
 bool intel_hdmi_compute_config(struct intel_encoder *encoder,
 			       struct intel_crtc_state *pipe_config);
-
+int intel_hdmi_get_modes(struct drm_connector *connector);
+int intel_hdmi_set_property(struct drm_connector *connector,
+		struct drm_property *property, uint64_t val);
+void intel_hdmi_destroy(struct drm_connector *connector);
+void intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi,
+		struct drm_connector *connector);
 
 /* intel_lvds.c */
 void intel_lvds_init(struct drm_device *dev);
@@ -1492,6 +1497,10 @@ bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
 void intel_display_power_put(struct drm_i915_private *dev_priv,
 			     enum intel_display_power_domain domain);
 
+/* intel_hotplug.c */
+bool intel_hpd_irq_event(struct drm_device *dev,
+		struct drm_connector *connector);
+
 static inline void
 assert_rpm_device_not_suspended(struct drm_i915_private *dev_priv)
 {
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 9fcbbdf..b67bb30 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1447,7 +1447,7 @@ intel_hdmi_force(struct drm_connector *connector)
 	hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
 }
 
-static int intel_hdmi_get_modes(struct drm_connector *connector)
+int intel_hdmi_get_modes(struct drm_connector *connector)
 {
 	struct edid *edid;
 
@@ -1471,7 +1471,7 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
 	return has_audio;
 }
 
-static int
+int
 intel_hdmi_set_property(struct drm_connector *connector,
 			struct drm_property *property,
 			uint64_t val)
@@ -1996,7 +1996,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
 	}
 }
 
-static void intel_hdmi_destroy(struct drm_connector *connector)
+void intel_hdmi_destroy(struct drm_connector *connector)
 {
 	kfree(to_intel_connector(connector)->detect_edid);
 	drm_connector_cleanup(connector);
@@ -2025,7 +2025,7 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
 	.destroy = intel_encoder_destroy,
 };
 
-static void
+void
 intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
 {
 	intel_attach_force_audio_property(connector);
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index bee6730..11a3e02 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -226,7 +226,7 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
 	intel_runtime_pm_put(dev_priv);
 }
 
-static bool intel_hpd_irq_event(struct drm_device *dev,
+bool intel_hpd_irq_event(struct drm_device *dev,
 				struct drm_connector *connector)
 {
 	enum drm_connector_status old_status;
diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c
index 9d5ed0c..e64abd3 100644
--- a/drivers/gpu/drm/i915/intel_lspcon.c
+++ b/drivers/gpu/drm/i915/intel_lspcon.c
@@ -39,6 +39,8 @@
 #define DP_TYPE2_ADAPTER			0xA0
 #define ADAPTER_TYPE_MASK			0xF0
 #define LSPCON_MODE_MASK			0x1
+#define DDC_SEGMENT_ADDR			0x30
+#define DDC_ADDR				0x50
 
 struct intel_digital_port *lspcon_to_dig_port(struct intel_lspcon *lspcon)
 {
@@ -57,6 +59,11 @@ struct intel_lspcon *enc_to_lspcon(struct drm_encoder *encoder)
 	return &intel_dig_port->lspcon;
 }
 
+struct intel_lspcon *intel_attached_lspcon(struct drm_connector *connector)
+{
+	return enc_to_lspcon(&intel_attached_encoder(connector)->base);
+}
+
 int lspcon_ioa_read(struct i2c_adapter *adapter, u8 *buffer,
 		u8 address, u8 offset, u8 no_of_bytes)
 {
@@ -113,6 +120,214 @@ int lspcon_ioa_write(struct i2c_adapter *adapter, u8 *buffer,
 	return err;
 }
 
+static int lspcon_get_edid_over_aux(void *data,
+	u8 *buf, unsigned int block, size_t len)
+{
+	struct i2c_adapter *adapter = data;
+	unsigned char start = block * EDID_LENGTH;
+	unsigned char segment = block >> 1;
+	unsigned char xfers = segment ? 3 : 2;
+	int ret, retries = 5;
+
+	do {
+		struct i2c_msg msgs[] = {
+			{
+				.addr   = DDC_SEGMENT_ADDR,
+				.flags  = 0,
+				.len    = 1,
+				.buf    = &segment,
+			}, {
+				.addr   = DDC_ADDR,
+				.flags  = 0,
+				.len    = 1,
+				.buf    = &start,
+			}, {
+				.addr   = DDC_ADDR,
+				.flags  = I2C_M_RD,
+				.len    = len,
+				.buf    = buf,
+			}
+		};
+
+		ret = adapter->algo->master_xfer(adapter, &msgs[3 - xfers],
+						xfers);
+
+		if (ret == -ENXIO) {
+			DRM_ERROR("Non-existent adapter %s\n",
+				adapter->name);
+			break;
+		}
+	} while (ret != xfers && --retries);
+
+	return ret == xfers ? 0 : -1;
+}
+
+struct edid *lspcon_get_edid(struct intel_lspcon *lspcon, struct drm_connector
+						*connector)
+{
+	struct edid *edid = NULL;
+	struct intel_digital_port *dig_port = lspcon_to_dig_port(lspcon);
+	struct i2c_adapter *adapter = &dig_port->dp.aux.ddc;
+
+	if (lspcon->mode_of_op != lspcon_mode_ls) {
+		DRM_ERROR("Cant read EDID without current mode info\n");
+		return false;
+	}
+
+	/* LS mode, getting EDID using I2C over Aux */
+	edid = drm_do_get_edid(connector, lspcon_get_edid_over_aux,
+			(void *)adapter);
+	return edid;
+}
+
+static void
+lspcon_unset_edid(struct drm_connector *connector)
+{
+	struct intel_lspcon *lspcon = intel_attached_lspcon(connector);
+	struct intel_hdmi *intel_hdmi = lspcon_to_hdmi(lspcon);
+
+	intel_hdmi->has_hdmi_sink = false;
+	intel_hdmi->has_audio = false;
+	intel_hdmi->rgb_quant_range_selectable = false;
+
+	kfree(to_intel_connector(connector)->detect_edid);
+	to_intel_connector(connector)->detect_edid = NULL;
+}
+
+static bool
+lspcon_set_edid(struct drm_connector *connector, bool force)
+{
+	struct drm_i915_private *dev_priv = to_i915(connector->dev);
+	struct intel_lspcon *lspcon = intel_attached_lspcon(connector);
+	struct intel_hdmi *intel_hdmi = lspcon_to_hdmi(lspcon);
+	struct edid *edid = NULL;
+	bool connected = false;
+
+	if (force) {
+		intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+		edid = lspcon_get_edid(lspcon, connector);
+		intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+	}
+
+	to_intel_connector(connector)->detect_edid = edid;
+	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
+		intel_hdmi->rgb_quant_range_selectable =
+			drm_rgb_quant_range_selectable(edid);
+
+		intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
+		if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
+			intel_hdmi->has_audio =
+				intel_hdmi->force_audio == HDMI_AUDIO_ON;
+
+		if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
+			intel_hdmi->has_hdmi_sink =
+				drm_detect_hdmi_monitor(edid);
+
+		connected = true;
+	}
+	return connected;
+}
+
+static enum drm_connector_status
+lspcon_detect(struct drm_connector *connector, bool force)
+{
+	enum drm_connector_status status;
+	struct drm_i915_private *dev_priv = to_i915(connector->dev);
+	struct intel_lspcon *lspcon = intel_attached_lspcon(connector);
+	struct intel_hdmi *intel_hdmi = lspcon_to_hdmi(lspcon);
+
+	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
+		      connector->base.id, connector->name);
+	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+
+	lspcon_unset_edid(connector);
+	if (lspcon_set_edid(connector, true)) {
+		DRM_DEBUG_DRIVER("HDMI connected\n");
+		hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
+		status = connector_status_connected;
+	} else {
+		DRM_DEBUG_DRIVER("HDMI disconnected\n");
+		status = connector_status_disconnected;
+	}
+	intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+	return status;
+}
+
+static int
+lspcon_set_property(struct drm_connector *connector,
+			struct drm_property *property,
+			uint64_t val)
+{
+	return intel_hdmi_set_property(connector, property, val);
+}
+
+static int
+lspcon_get_modes(struct drm_connector *connector)
+{
+	return intel_hdmi_get_modes(connector);
+}
+
+static void
+lspcon_destroy(struct drm_connector *connector)
+{
+	intel_hdmi_destroy(connector);
+}
+
+static enum drm_mode_status
+lspcon_mode_valid(struct drm_connector *connector,
+		      struct drm_display_mode *mode)
+{
+	int clock = mode->clock;
+	int max_dotclk = 675000; /* 4k@60 */
+	struct drm_device *dev = connector->dev;
+
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		return MODE_NO_DBLESCAN;
+
+	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) ==
+		DRM_MODE_FLAG_3D_FRAME_PACKING)
+		clock *= 2;
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		clock *= 2;
+
+	if (clock < 25000)
+		return MODE_CLOCK_LOW;
+
+	if (clock > max_dotclk)
+		return MODE_CLOCK_HIGH;
+
+	/* BXT DPLL can't generate 223-240 MHz */
+	if (IS_BROXTON(dev) && clock > 223333 && clock < 240000)
+		return MODE_CLOCK_RANGE;
+
+	/* todo: check for 12bpc here */
+	return MODE_OK;
+}
+
+void lspcon_add_properties(struct intel_digital_port *dig_port,
+		struct drm_connector *connector)
+{
+	intel_hdmi_add_properties(&dig_port->hdmi, connector);
+}
+
+static const struct drm_connector_funcs lspcon_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = lspcon_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = lspcon_set_property,
+	.atomic_get_property = intel_connector_atomic_get_property,
+	.destroy = lspcon_destroy,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+};
+
+static const struct drm_connector_helper_funcs lspcon_connector_helper_funcs = {
+	.get_modes = lspcon_get_modes,
+	.mode_valid = lspcon_mode_valid,
+	.best_encoder = intel_best_encoder,
+};
+
 void intel_lspcon_init_connector(struct intel_digital_port *intel_dig_port)
 {
 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
@@ -130,16 +345,28 @@ void intel_lspcon_init_connector(struct intel_digital_port *intel_dig_port)
 	connector->interlace_allowed = true;
 	connector->doublescan_allowed = 0;
 
+	/* Load connector */
+	drm_connector_init(dev, connector, &lspcon_connector_funcs,
+			DRM_MODE_CONNECTOR_DisplayPort);
+	drm_connector_helper_add(connector, &lspcon_connector_helper_funcs);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
+	drm_connector_register(connector);
+
+	/* Add properties and functions */
+	lspcon_add_properties(intel_dig_port, connector);
+	intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
+	i915_debugfs_connector_add(connector);
+
 	/* init DP */
 	if (intel_dp_init_minimum(intel_dig_port, intel_connector)) {
 		DRM_ERROR("DP init for LSPCON failed\n");
-		return;
+		goto fail;
 	}
 
 	/* init HDMI */
 	if (intel_hdmi_init_minimum(intel_dig_port, intel_connector)) {
 		DRM_ERROR("HDMI init for LSPCON failed\n");
-		return;
+		goto fail;
 	}
 
 	/* Set up the hotplug pin. */
@@ -183,4 +410,11 @@ void intel_lspcon_init_connector(struct intel_digital_port *intel_dig_port)
 
 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
 	}
+
+	DRM_DEBUG_DRIVER("LSPCON connector init done\n");
+	return;
+
+fail:
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
 }
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  parent reply	other threads:[~2016-03-22 14:20 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-22 14:25 [PATCH 0/7] Add lspcon support Shashank Sharma
2016-03-22 14:25 ` [PATCH 1/7] drm/i915: add lspcon vbt bit parsing Shashank Sharma
2016-03-22 15:54   ` Jani Nikula
2016-03-22 16:50     ` Sharma, Shashank
2016-03-22 17:05       ` Ville Syrjälä
2016-03-22 17:10         ` Sharma, Shashank
2016-03-22 14:25 ` [PATCH 2/7] drm/i915: Add lspcon data structures Shashank Sharma
2016-03-22 14:25 ` [PATCH 3/7] drm/i915: Add new lspcon file Shashank Sharma
2016-03-22 14:25 ` [PATCH 4/7] drm/i915: Add and initialize lspcon connector Shashank Sharma
2016-03-22 14:25 ` Shashank Sharma [this message]
2016-03-22 14:25 ` [PATCH 6/7] drm/i915: Add lspcon core functions Shashank Sharma
2016-03-22 14:25 ` [PATCH 7/7] drm/i915: Add lspcon hpd handler Shashank Sharma
2016-03-22 16:20 ` [PATCH 0/7] Add lspcon support Ville Syrjälä
2016-03-22 16:47   ` Sharma, Shashank
2016-03-23  9:03     ` Daniel Vetter
2016-03-23  9:12       ` Sharma, Shashank
2016-03-25 16:02       ` Sharma, Shashank
2016-03-22 16:32 ` ✗ Fi.CI.BAT: warning for " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1458656708-31228-6-git-send-email-shashank.sharma@intel.com \
    --to=shashank.sharma@intel.com \
    --cc=akashdeep.sharma@inte.com \
    --cc=daniel.vetter@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).