Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 329401
b: refs/heads/master
c: 5ab432e
h: refs/heads/master
i:
  329399: 423dfd6
v: v3
  • Loading branch information
Daniel Vetter committed Sep 6, 2012
1 parent 3fd3418 commit df50ed3
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 54 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ef9c3aee60442d1eaf81fbd7b63f256410cc0aa9
refs/heads/master: 5ab432ef4997ce32c9406721b37ef6e97e57dae1
30 changes: 19 additions & 11 deletions trunk/drivers/gpu/drm/i915/intel_ddi.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,26 +757,34 @@ void intel_ddi_mode_set(struct drm_encoder *encoder,
intel_hdmi->set_infoframes(encoder, adjusted_mode);
}

void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
void intel_enable_ddi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
int port = intel_hdmi->ddi_port;
u32 temp;

temp = I915_READ(DDI_BUF_CTL(port));

if (mode != DRM_MODE_DPMS_ON) {
temp &= ~DDI_BUF_CTL_ENABLE;
} else {
temp |= DDI_BUF_CTL_ENABLE;
}
temp |= DDI_BUF_CTL_ENABLE;

/* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
* and swing/emphasis values are ignored so nothing special needs
* to be done besides enabling the port.
*/
I915_WRITE(DDI_BUF_CTL(port),
temp);
I915_WRITE(DDI_BUF_CTL(port), temp);
}

void intel_disable_ddi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
int port = intel_hdmi->ddi_port;
u32 temp;

temp = I915_READ(DDI_BUF_CTL(port));
temp &= ~DDI_BUF_CTL_ENABLE;

I915_WRITE(DDI_BUF_CTL(port), temp);
}
49 changes: 49 additions & 0 deletions trunk/drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -3554,6 +3554,17 @@ void intel_encoder_commit(struct drm_encoder *encoder)
intel_cpt_verify_modeset(dev, intel_crtc->pipe);
}

void intel_encoder_noop(struct drm_encoder *encoder)
{
}

void intel_encoder_disable(struct drm_encoder *encoder)
{
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);

intel_encoder->disable(intel_encoder);
}

void intel_encoder_destroy(struct drm_encoder *encoder)
{
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
Expand All @@ -3562,6 +3573,44 @@ void intel_encoder_destroy(struct drm_encoder *encoder)
kfree(intel_encoder);
}

/* Simple dpms helper for encodres with just one connector, no cloning and only
* one kind of off state. It clamps all !ON modes to fully OFF and changes the
* state of the entire output pipe. */
void intel_encoder_dpms(struct intel_encoder *encoder, int mode)
{
if (mode == DRM_MODE_DPMS_ON) {
encoder->connectors_active = true;

intel_crtc_dpms(encoder->base.crtc, DRM_MODE_DPMS_ON);
} else {
encoder->connectors_active = false;

intel_crtc_dpms(encoder->base.crtc, DRM_MODE_DPMS_OFF);
}
}

/* Even simpler default implementation, if there's really no special case to
* consider. */
void intel_connector_dpms(struct drm_connector *connector, int mode)
{
struct intel_encoder *encoder = intel_attached_encoder(connector);

/* All the simple cases only support two dpms states. */
if (mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;

if (mode == connector->dpms)
return;

connector->dpms = mode;

/* Only need to change hw state when actually enabled */
if (encoder->base.crtc)
intel_encoder_dpms(encoder, mode);
else
encoder->connectors_active = false;
}

static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
Expand Down
8 changes: 7 additions & 1 deletion trunk/drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ struct intel_encoder {
* simple flag is enough to compute the possible_clones mask.
*/
bool cloneable;
bool connectors_active;
void (*hot_plug)(struct intel_encoder *);
void (*enable)(struct intel_encoder *);
void (*disable)(struct intel_encoder *);
Expand Down Expand Up @@ -412,7 +413,11 @@ extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare(struct drm_encoder *encoder);
extern void intel_encoder_commit(struct drm_encoder *encoder);
extern void intel_encoder_noop(struct drm_encoder *encoder);
extern void intel_encoder_disable(struct drm_encoder *encoder);
extern void intel_encoder_destroy(struct drm_encoder *encoder);
extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode);
extern void intel_connector_dpms(struct drm_connector *, int mode);

static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
{
Expand Down Expand Up @@ -519,7 +524,8 @@ extern void intel_disable_gt_powersave(struct drm_device *dev);
extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
extern void ironlake_teardown_rc6(struct drm_device *dev);

extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode);
extern void intel_enable_ddi(struct intel_encoder *encoder);
extern void intel_disable_ddi(struct intel_encoder *encoder);
extern void intel_ddi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
Expand Down
126 changes: 85 additions & 41 deletions trunk/drivers/gpu/drm/i915/intel_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,11 +601,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
intel_hdmi->set_infoframes(encoder, adjusted_mode);
}

static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
static void intel_enable_hdmi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 temp;
u32 enable_bits = SDVO_ENABLE;

Expand All @@ -617,31 +617,12 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
/* HW workaround for IBX, we need to move the port to transcoder A
* before disabling it. */
if (HAS_PCH_IBX(dev)) {
struct drm_crtc *crtc = encoder->crtc;
struct drm_crtc *crtc = encoder->base.crtc;
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;

if (mode != DRM_MODE_DPMS_ON) {
if (temp & SDVO_PIPE_B_SELECT) {
temp &= ~SDVO_PIPE_B_SELECT;
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);

/* Again we need to write this twice. */
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);

/* Transcoder selection bits only update
* effectively on vblank. */
if (crtc)
intel_wait_for_vblank(dev, pipe);
else
msleep(50);
}
} else {
/* Restore the transcoder select bit. */
if (pipe == PIPE_B)
enable_bits |= SDVO_PIPE_B_SELECT;
}
/* Restore the transcoder select bit. */
if (pipe == PIPE_B)
enable_bits |= SDVO_PIPE_B_SELECT;
}

/* HW workaround, need to toggle enable bit off and on for 12bpc, but
Expand All @@ -652,12 +633,67 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
POSTING_READ(intel_hdmi->sdvox_reg);
}

if (mode != DRM_MODE_DPMS_ON) {
temp &= ~enable_bits;
} else {
temp |= enable_bits;
temp |= enable_bits;

I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);

/* HW workaround, need to write this twice for issue that may result
* in first write getting masked.
*/
if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);
}
}

static void intel_disable_hdmi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
u32 temp;
u32 enable_bits = SDVO_ENABLE;

if (intel_hdmi->has_audio)
enable_bits |= SDVO_AUDIO_ENABLE;

temp = I915_READ(intel_hdmi->sdvox_reg);

/* HW workaround for IBX, we need to move the port to transcoder A
* before disabling it. */
if (HAS_PCH_IBX(dev)) {
struct drm_crtc *crtc = encoder->base.crtc;
int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;

if (temp & SDVO_PIPE_B_SELECT) {
temp &= ~SDVO_PIPE_B_SELECT;
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);

/* Again we need to write this twice. */
I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);

/* Transcoder selection bits only update
* effectively on vblank. */
if (crtc)
intel_wait_for_vblank(dev, pipe);
else
msleep(50);
}
}

/* HW workaround, need to toggle enable bit off and on for 12bpc, but
* we do this anyway which shows more stable in testing.
*/
if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
POSTING_READ(intel_hdmi->sdvox_reg);
}

temp &= ~enable_bits;

I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(intel_hdmi->sdvox_reg);

Expand Down Expand Up @@ -849,23 +885,23 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
}

static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
.dpms = intel_ddi_dpms,
.mode_fixup = intel_hdmi_mode_fixup,
.prepare = intel_encoder_prepare,
.prepare = intel_encoder_noop,
.mode_set = intel_ddi_mode_set,
.commit = intel_encoder_commit,
.commit = intel_encoder_noop,
.disable = intel_encoder_disable,
};

static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
.dpms = intel_hdmi_dpms,
.mode_fixup = intel_hdmi_mode_fixup,
.prepare = intel_encoder_prepare,
.prepare = intel_encoder_noop,
.mode_set = intel_hdmi_mode_set,
.commit = intel_encoder_commit,
.commit = intel_encoder_noop,
.disable = intel_encoder_disable,
};

static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.dpms = intel_connector_dpms,
.detect = intel_hdmi_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_hdmi_set_property,
Expand Down Expand Up @@ -964,10 +1000,18 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port)
intel_hdmi->set_infoframes = cpt_set_infoframes;
}

if (IS_HASWELL(dev))
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
else
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
if (IS_HASWELL(dev)) {
intel_encoder->enable = intel_enable_ddi;
intel_encoder->disable = intel_disable_ddi;
drm_encoder_helper_add(&intel_encoder->base,
&intel_hdmi_helper_funcs_hsw);
} else {
intel_encoder->enable = intel_enable_hdmi;
intel_encoder->disable = intel_disable_hdmi;
drm_encoder_helper_add(&intel_encoder->base,
&intel_hdmi_helper_funcs);
}


intel_hdmi_add_properties(intel_hdmi, connector);

Expand Down

0 comments on commit df50ed3

Please sign in to comment.