51,7 → 51,8 |
|
u32 pfit_control; |
u32 pfit_pgm_ratios; |
bool pfit_dirty; |
bool is_dual_link; |
u32 reg; |
|
struct intel_lvds_connector *attached_connector; |
}; |
71,16 → 72,11 |
{ |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 lvds_reg, tmp; |
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); |
u32 tmp; |
|
if (HAS_PCH_SPLIT(dev)) { |
lvds_reg = PCH_LVDS; |
} else { |
lvds_reg = LVDS; |
} |
tmp = I915_READ(lvds_encoder->reg); |
|
tmp = I915_READ(lvds_reg); |
|
if (!(tmp & LVDS_PORT_EN)) |
return false; |
|
92,6 → 88,91 |
return true; |
} |
|
/* The LVDS pin pair needs to be on before the DPLLs are enabled. |
* This is an exception to the general rule that mode_set doesn't turn |
* things on. |
*/ |
static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) |
{ |
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
struct drm_display_mode *fixed_mode = |
lvds_encoder->attached_connector->base.panel.fixed_mode; |
int pipe = intel_crtc->pipe; |
u32 temp; |
|
temp = I915_READ(lvds_encoder->reg); |
temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; |
|
if (HAS_PCH_CPT(dev)) { |
temp &= ~PORT_TRANS_SEL_MASK; |
temp |= PORT_TRANS_SEL_CPT(pipe); |
} else { |
if (pipe == 1) { |
temp |= LVDS_PIPEB_SELECT; |
} else { |
temp &= ~LVDS_PIPEB_SELECT; |
} |
} |
|
/* set the corresponsding LVDS_BORDER bit */ |
temp |= dev_priv->lvds_border_bits; |
/* Set the B0-B3 data pairs corresponding to whether we're going to |
* set the DPLLs for dual-channel mode or not. |
*/ |
if (lvds_encoder->is_dual_link) |
temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; |
else |
temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); |
|
/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) |
* appropriately here, but we need to look more thoroughly into how |
* panels behave in the two modes. |
*/ |
|
/* Set the dithering flag on LVDS as needed, note that there is no |
* special lvds dither control bit on pch-split platforms, dithering is |
* only controlled through the PIPECONF reg. */ |
if (INTEL_INFO(dev)->gen == 4) { |
if (dev_priv->lvds_dither) |
temp |= LVDS_ENABLE_DITHER; |
else |
temp &= ~LVDS_ENABLE_DITHER; |
} |
temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); |
if (fixed_mode->flags & DRM_MODE_FLAG_NHSYNC) |
temp |= LVDS_HSYNC_POLARITY; |
if (fixed_mode->flags & DRM_MODE_FLAG_NVSYNC) |
temp |= LVDS_VSYNC_POLARITY; |
|
I915_WRITE(lvds_encoder->reg, temp); |
} |
|
static void intel_pre_enable_lvds(struct intel_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base); |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) |
return; |
|
/* |
* Enable automatic panel scaling so that non-native modes |
* fill the screen. The panel fitter should only be |
* adjusted whilst the pipe is disabled, according to |
* register description and PRM. |
*/ |
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", |
enc->pfit_control, |
enc->pfit_pgm_ratios); |
|
I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios); |
I915_WRITE(PFIT_CONTROL, enc->pfit_control); |
} |
|
/** |
* Sets the power state for the panel. |
*/ |
101,38 → 182,20 |
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); |
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 ctl_reg, lvds_reg, stat_reg; |
u32 ctl_reg, stat_reg; |
|
if (HAS_PCH_SPLIT(dev)) { |
ctl_reg = PCH_PP_CONTROL; |
lvds_reg = PCH_LVDS; |
stat_reg = PCH_PP_STATUS; |
} else { |
ctl_reg = PP_CONTROL; |
lvds_reg = LVDS; |
stat_reg = PP_STATUS; |
} |
|
I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); |
I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN); |
|
if (lvds_encoder->pfit_dirty) { |
/* |
* Enable automatic panel scaling so that non-native modes |
* fill the screen. The panel fitter should only be |
* adjusted whilst the pipe is disabled, according to |
* register description and PRM. |
*/ |
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", |
lvds_encoder->pfit_control, |
lvds_encoder->pfit_pgm_ratios); |
|
I915_WRITE(PFIT_PGM_RATIOS, lvds_encoder->pfit_pgm_ratios); |
I915_WRITE(PFIT_CONTROL, lvds_encoder->pfit_control); |
lvds_encoder->pfit_dirty = false; |
} |
|
I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); |
POSTING_READ(lvds_reg); |
POSTING_READ(lvds_encoder->reg); |
if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000)) |
DRM_ERROR("timed out waiting for panel to power on\n"); |
|
144,15 → 207,13 |
struct drm_device *dev = encoder->base.dev; |
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); |
struct drm_i915_private *dev_priv = dev->dev_private; |
u32 ctl_reg, lvds_reg, stat_reg; |
u32 ctl_reg, stat_reg; |
|
if (HAS_PCH_SPLIT(dev)) { |
ctl_reg = PCH_PP_CONTROL; |
lvds_reg = PCH_LVDS; |
stat_reg = PCH_PP_STATUS; |
} else { |
ctl_reg = PP_CONTROL; |
lvds_reg = LVDS; |
stat_reg = PP_STATUS; |
} |
|
162,15 → 223,10 |
if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) |
DRM_ERROR("timed out waiting for panel to power off\n"); |
|
if (lvds_encoder->pfit_control) { |
I915_WRITE(PFIT_CONTROL, 0); |
lvds_encoder->pfit_dirty = true; |
I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN); |
POSTING_READ(lvds_encoder->reg); |
} |
|
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); |
POSTING_READ(lvds_reg); |
} |
|
static int intel_lvds_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
406,7 → 462,6 |
pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { |
lvds_encoder->pfit_control = pfit_control; |
lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; |
lvds_encoder->pfit_dirty = true; |
} |
dev_priv->lvds_border_bits = border; |
|
493,13 → 548,14 |
|
#if 0 |
/* |
* Lid events. Note the use of 'modeset_on_lid': |
* - we set it on lid close, and reset it on open |
* Lid events. Note the use of 'modeset': |
* - we set it to MODESET_ON_LID_OPEN on lid close, |
* and set it to MODESET_DONE on open |
* - we use it as a "only once" bit (ie we ignore |
* duplicate events where it was already properly |
* set/reset) |
* - the suspend/resume paths will also set it to |
* zero, since they restore the mode ("lid open"). |
* duplicate events where it was already properly set) |
* - the suspend/resume paths will set it to |
* MODESET_SUSPENDED and ignore the lid open event, |
* because they restore the mode ("lid open"). |
*/ |
static int intel_lid_notify(struct notifier_block *nb, unsigned long val, |
void *unused) |
513,6 → 569,9 |
if (dev->switch_power_state != DRM_SWITCH_POWER_ON) |
return NOTIFY_OK; |
|
mutex_lock(&dev_priv->modeset_restore_lock); |
if (dev_priv->modeset_restore == MODESET_SUSPENDED) |
goto exit; |
/* |
* check and update the status of LVDS connector after receiving |
* the LID nofication event. |
521,21 → 580,24 |
|
/* Don't force modeset on machines where it causes a GPU lockup */ |
if (dmi_check_system(intel_no_modeset_on_lid)) |
return NOTIFY_OK; |
goto exit; |
if (!acpi_lid_open()) { |
dev_priv->modeset_on_lid = 1; |
return NOTIFY_OK; |
/* do modeset on next lid open event */ |
dev_priv->modeset_restore = MODESET_ON_LID_OPEN; |
goto exit; |
} |
|
if (!dev_priv->modeset_on_lid) |
return NOTIFY_OK; |
if (dev_priv->modeset_restore == MODESET_DONE) |
goto exit; |
|
dev_priv->modeset_on_lid = 0; |
|
mutex_lock(&dev->mode_config.mutex); |
drm_modeset_lock_all(dev); |
intel_modeset_setup_hw_state(dev, true); |
mutex_unlock(&dev->mode_config.mutex); |
drm_modeset_unlock_all(dev); |
|
dev_priv->modeset_restore = MODESET_DONE; |
|
exit: |
mutex_unlock(&dev_priv->modeset_restore_lock); |
return NOTIFY_OK; |
} |
#endif |
591,8 → 653,7 |
* If the CRTC is enabled, the display will be changed |
* according to the new panel fitting mode. |
*/ |
intel_set_mode(crtc, &crtc->mode, |
crtc->x, crtc->y, crtc->fb); |
intel_crtc_restore_mode(crtc); |
} |
} |
|
602,7 → 663,6 |
static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { |
.mode_fixup = intel_lvds_mode_fixup, |
.mode_set = intel_lvds_mode_set, |
.disable = intel_encoder_noop, |
}; |
|
static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { |
895,6 → 955,53 |
return false; |
} |
|
static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) |
{ |
DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident); |
return 1; |
} |
bool intel_is_dual_link_lvds(struct drm_device *dev) |
{ |
struct intel_encoder *encoder; |
struct intel_lvds_encoder *lvds_encoder; |
|
list_for_each_entry(encoder, &dev->mode_config.encoder_list, |
base.head) { |
if (encoder->type == INTEL_OUTPUT_LVDS) { |
lvds_encoder = to_lvds_encoder(&encoder->base); |
|
return lvds_encoder->is_dual_link; |
} |
} |
|
return false; |
} |
|
static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) |
{ |
struct drm_device *dev = lvds_encoder->base.base.dev; |
unsigned int val; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
/* use the module option value if specified */ |
if (i915_lvds_channel_mode > 0) |
return i915_lvds_channel_mode == 2; |
|
// if (dmi_check_system(intel_dual_link_lvds)) |
// return true; |
|
/* BIOS should set the proper LVDS register value at boot, but |
* in reality, it doesn't set the value when the lid is closed; |
* we need to check "the value to be set" in VBT when LVDS |
* register is uninitialized. |
*/ |
val = I915_READ(lvds_encoder->reg); |
if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) |
val = dev_priv->bios_lvds_val; |
|
return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; |
} |
|
static bool intel_lvds_supported(struct drm_device *dev) |
{ |
/* With the introduction of the PCH we gained a dedicated |
980,6 → 1087,8 |
DRM_MODE_ENCODER_LVDS); |
|
intel_encoder->enable = intel_enable_lvds; |
intel_encoder->pre_enable = intel_pre_enable_lvds; |
intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; |
intel_encoder->disable = intel_disable_lvds; |
intel_encoder->get_hw_state = intel_lvds_get_hw_state; |
intel_connector->get_hw_state = intel_connector_get_hw_state; |
1001,6 → 1110,12 |
connector->interlace_allowed = false; |
connector->doublescan_allowed = false; |
|
if (HAS_PCH_SPLIT(dev)) { |
lvds_encoder->reg = PCH_LVDS; |
} else { |
lvds_encoder->reg = LVDS; |
} |
|
/* create the scaling mode property */ |
drm_mode_create_scaling_mode_property(dev); |
drm_object_attach_property(&connector->base, |
1101,6 → 1216,10 |
goto failed; |
|
out: |
lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); |
DRM_DEBUG_KMS("detected %s-link lvds configuration\n", |
lvds_encoder->is_dual_link ? "dual" : "single"); |
|
/* |
* Unlock registers and just |
* leave them unlocked |