From: Wu Fengguang <fengguang.wu@intel.com>
To: Keith Packard <keithp@keithp.com>
Cc: Takashi Iwai <tiwai@suse.de>,
"Wang, Zhenyu Z" <zhenyu.z.wang@intel.com>,
"dri-devel@lists.freedesktop.org"
<dri-devel@lists.freedesktop.org>,
"intel-gfx@lists.freedesktop.org"
<intel-gfx@lists.freedesktop.org>,
LKML <linux-kernel@vger.kernel.org>
Subject: [PATCH 3/3 v3] drm/i915: hot plug/unplug notification to HDMI audio driver
Date: Mon, 21 Nov 2011 16:22:23 +0800 [thread overview]
Message-ID: <20111121082223.GA1692@localhost> (raw)
In-Reply-To: <20111121063749.GA23450@localhost>
On monitor hot plug/unplug, update ELD and set/clear SDVO_AUDIO_ENABLE
or DP_AUDIO_OUTPUT_ENABLE accordingly. So that the audio driver will
receive hot plug events and take action to refresh its device state and
ELD contents.
A new callback ->hotplug() is added to struct drm_connector_funcs which
will be called immediately after ->detect() knowing that the monitor is
either plugged or unplugged.
It's noticed that X may not call ->mode_set() at monitor hot plug, so it's
necessary to call drm_edid_to_eld() earlier at ->detect() time rather than
in intel_ddc_get_modes(), so that intel_write_eld() can see the new ELD
in ->hotplug.
The call sequence on hot plug is
(the difference part lies in ->mode_set vs ->hotplug)
- KMS console
->detect
drm_edid_to_eld
->mode_set
intel_write_eld
set SDVO_AUDIO_ENABLE/DP_AUDIO_OUTPUT_ENABLE
- X
->detect
drm_edid_to_eld
->hotplug
intel_write_eld
set SDVO_AUDIO_ENABLE/DP_AUDIO_OUTPUT_ENABLE
On hot remove, the call sequence is
->hotplug
clear SDVO_AUDIO_ENABLE/DP_AUDIO_OUTPUT_ENABLE
cc: Wang Zhenyu <zhenyu.z.wang@intel.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
drivers/gpu/drm/drm_crtc_helper.c | 6 +++
drivers/gpu/drm/i915/intel_dp.c | 44 +++++++++++++++++++++------
drivers/gpu/drm/i915/intel_hdmi.c | 31 +++++++++++++++++++
drivers/gpu/drm/i915/intel_modes.c | 2 -
include/drm/drm_crtc.h | 1
5 files changed, 72 insertions(+), 12 deletions(-)
Changes since v2:
Fix "kernel NULL pointer dereference" due to calling NULL ->hotplug.
--- linux.orig/drivers/gpu/drm/i915/intel_dp.c 2011-11-21 11:26:09.000000000 +0800
+++ linux/drivers/gpu/drm/i915/intel_dp.c 2011-11-21 14:12:21.000000000 +0800
@@ -28,6 +28,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include <drm/drm_edid.h>
#include "drmP.h"
#include "drm.h"
#include "drm_crtc.h"
@@ -1970,20 +1971,44 @@ intel_dp_detect(struct drm_connector *co
if (status != connector_status_connected)
return status;
- if (intel_dp->force_audio) {
- intel_dp->has_audio = intel_dp->force_audio > 0;
- } else {
- edid = intel_dp_get_edid(connector, &intel_dp->adapter);
- if (edid) {
- intel_dp->has_audio = drm_detect_monitor_audio(edid);
- connector->display_info.raw_edid = NULL;
- kfree(edid);
- }
+ edid = intel_dp_get_edid(connector, &intel_dp->adapter);
+ if (edid) {
+ intel_dp->has_audio = drm_detect_monitor_audio(edid);
+ drm_edid_to_eld(connector, edid);
+ connector->display_info.raw_edid = NULL;
+ kfree(edid);
}
+ if (intel_dp->force_audio)
+ intel_dp->has_audio = intel_dp->force_audio > 0;
+
return connector_status_connected;
}
+static void intel_dp_hotplug(struct drm_connector *connector)
+{
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
+ struct drm_device *dev = intel_dp->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = intel_dp->base.base.crtc;
+
+ DRM_DEBUG_DRIVER("DisplayPort hotplug status %d crtc %p eld %#x\n",
+ connector->status,
+ crtc,
+ (unsigned int)connector->eld[0]);
+
+ if (connector->status == connector_status_disconnected) {
+ intel_dp->DP &= ~DP_AUDIO_OUTPUT_ENABLE;
+ } else if (connector->status == connector_status_connected && crtc) {
+ intel_write_eld(&intel_dp->base.base, &crtc->mode);
+ intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
+ } else {
+ return;
+ }
+ I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+ POSTING_READ(intel_dp->output_reg);
+}
+
static int intel_dp_get_modes(struct drm_connector *connector)
{
struct intel_dp *intel_dp = intel_attached_dp(connector);
@@ -2143,6 +2168,7 @@ static const struct drm_connector_funcs
.detect = intel_dp_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property,
+ .hotplug = intel_dp_hotplug,
.destroy = intel_dp_destroy,
};
--- linux.orig/drivers/gpu/drm/i915/intel_hdmi.c 2011-11-21 11:26:09.000000000 +0800
+++ linux/drivers/gpu/drm/i915/intel_hdmi.c 2011-11-21 14:12:26.000000000 +0800
@@ -337,6 +337,7 @@ intel_hdmi_detect(struct drm_connector *
status = connector_status_connected;
intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
+ drm_edid_to_eld(connector, edid);
}
connector->display_info.raw_edid = NULL;
kfree(edid);
@@ -350,6 +351,35 @@ intel_hdmi_detect(struct drm_connector *
return status;
}
+static void intel_hdmi_hotplug(struct drm_connector *connector)
+{
+ struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+ struct drm_i915_private *dev_priv = connector->dev->dev_private;
+ struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
+ u32 temp;
+
+ DRM_DEBUG_DRIVER("HDMI hotplug status %d crtc %p eld %#x\n",
+ connector->status,
+ crtc,
+ (unsigned int)connector->eld[0]);
+
+ if (connector->status == connector_status_disconnected) {
+ temp = I915_READ(intel_hdmi->sdvox_reg) & ~SDVO_AUDIO_ENABLE;
+ } else if (connector->status == connector_status_connected && crtc) {
+ /*
+ * It's for X only, which may not call ->mode_set on hot plug.
+ * KMS console has NULL crtc at this time and will
+ * call ->mode_set to enable HDMI audio a bit later.
+ */
+ intel_write_eld(&intel_hdmi->base.base, &crtc->mode);
+ temp = I915_READ(intel_hdmi->sdvox_reg) | SDVO_AUDIO_ENABLE;
+ } else {
+ return;
+ }
+ I915_WRITE(intel_hdmi->sdvox_reg, temp);
+ POSTING_READ(intel_hdmi->sdvox_reg);
+}
+
static int intel_hdmi_get_modes(struct drm_connector *connector)
{
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
@@ -459,6 +489,7 @@ static const struct drm_connector_funcs
.detect = intel_hdmi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_hdmi_set_property,
+ .hotplug = intel_hdmi_hotplug,
.destroy = intel_hdmi_destroy,
};
--- linux.orig/drivers/gpu/drm/drm_crtc_helper.c 2011-11-21 11:26:09.000000000 +0800
+++ linux/drivers/gpu/drm/drm_crtc_helper.c 2011-11-21 16:19:11.000000000 +0800
@@ -903,8 +903,12 @@ static void output_poll_execute(struct w
connector->base.id,
drm_get_connector_name(connector),
old_status, connector->status);
- if (old_status != connector->status)
+ if (old_status != connector->status) {
changed = true;
+ if (connector->funcs->hotplug)
+ connector->funcs->hotplug(connector);
+ }
+
}
mutex_unlock(&dev->mode_config.mutex);
--- linux.orig/include/drm/drm_crtc.h 2011-11-21 11:26:09.000000000 +0800
+++ linux/include/drm/drm_crtc.h 2011-11-21 11:26:14.000000000 +0800
@@ -419,6 +419,7 @@ struct drm_connector_funcs {
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
uint64_t val);
+ void (*hotplug)(struct drm_connector *connector);
void (*destroy)(struct drm_connector *connector);
void (*force)(struct drm_connector *connector);
};
--- linux.orig/drivers/gpu/drm/i915/intel_modes.c 2011-11-21 11:26:09.000000000 +0800
+++ linux/drivers/gpu/drm/i915/intel_modes.c 2011-11-21 11:26:14.000000000 +0800
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/fb.h>
-#include <drm/drm_edid.h>
#include "drmP.h"
#include "intel_drv.h"
#include "i915_drv.h"
@@ -75,7 +74,6 @@ int intel_ddc_get_modes(struct drm_conne
if (edid) {
drm_mode_connector_update_edid_property(connector, edid);
ret = drm_add_edid_modes(connector, edid);
- drm_edid_to_eld(connector, edid);
connector->display_info.raw_edid = NULL;
kfree(edid);
}
next prev parent reply other threads:[~2011-11-21 8:22 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-21 6:37 [PATCH 3/3 v2] drm/i915: hot plug/unplug notification to HDMI audio driver Wu Fengguang
2011-11-21 8:22 ` Wu Fengguang [this message]
2011-11-21 16:55 ` Keith Packard
2011-11-21 16:55 ` Keith Packard
2011-11-22 7:40 ` Wu Fengguang
2011-11-22 8:26 ` Wu Fengguang
2011-11-22 18:25 ` Keith Packard
2011-11-22 18:25 ` Keith Packard
2011-11-23 8:29 ` Wu Fengguang
2011-11-23 19:26 ` Keith Packard
2011-11-23 19:26 ` Keith Packard
2011-11-24 9:38 ` Wu Fengguang
2011-11-24 9:38 ` Wu Fengguang
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=20111121082223.GA1692@localhost \
--to=fengguang.wu@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=keithp@keithp.com \
--cc=linux-kernel@vger.kernel.org \
--cc=tiwai@suse.de \
--cc=zhenyu.z.wang@intel.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.