40,28 → 40,30 |
//#include <linux/acpi.h> |
|
/* Private structure for the integrated LVDS support */ |
struct intel_lvds { |
struct intel_lvds_connector { |
struct intel_connector base; |
|
// struct notifier_block lid_notifier; |
}; |
|
struct intel_lvds_encoder { |
struct intel_encoder base; |
|
struct edid *edid; |
|
int fitting_mode; |
u32 pfit_control; |
u32 pfit_pgm_ratios; |
bool pfit_dirty; |
|
struct drm_display_mode *fixed_mode; |
struct intel_lvds_connector *attached_connector; |
}; |
|
static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder) |
static struct intel_lvds_encoder *to_lvds_encoder(struct drm_encoder *encoder) |
{ |
return container_of(encoder, struct intel_lvds, base.base); |
return container_of(encoder, struct intel_lvds_encoder, base.base); |
} |
|
static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector) |
static struct intel_lvds_connector *to_lvds_connector(struct drm_connector *connector) |
{ |
return container_of(intel_attached_encoder(connector), |
struct intel_lvds, base); |
return container_of(connector, struct intel_lvds_connector, base.base); |
} |
|
static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, |
96,7 → 98,7 |
static void intel_enable_lvds(struct intel_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base); |
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; |
113,7 → 115,7 |
|
I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); |
|
if (intel_lvds->pfit_dirty) { |
if (lvds_encoder->pfit_dirty) { |
/* |
* Enable automatic panel scaling so that non-native modes |
* fill the screen. The panel fitter should only be |
121,12 → 123,12 |
* register description and PRM. |
*/ |
DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", |
intel_lvds->pfit_control, |
intel_lvds->pfit_pgm_ratios); |
lvds_encoder->pfit_control, |
lvds_encoder->pfit_pgm_ratios); |
|
I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); |
I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); |
intel_lvds->pfit_dirty = false; |
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); |
140,7 → 142,7 |
static void intel_disable_lvds(struct intel_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct intel_lvds *intel_lvds = to_intel_lvds(&encoder->base); |
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; |
|
160,9 → 162,9 |
if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) |
DRM_ERROR("timed out waiting for panel to power off\n"); |
|
if (intel_lvds->pfit_control) { |
if (lvds_encoder->pfit_control) { |
I915_WRITE(PFIT_CONTROL, 0); |
intel_lvds->pfit_dirty = true; |
lvds_encoder->pfit_dirty = true; |
} |
|
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); |
172,8 → 174,8 |
static int intel_lvds_mode_valid(struct drm_connector *connector, |
struct drm_display_mode *mode) |
{ |
struct intel_lvds *intel_lvds = intel_attached_lvds(connector); |
struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode; |
struct intel_connector *intel_connector = to_intel_connector(connector); |
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode; |
|
if (mode->hdisplay > fixed_mode->hdisplay) |
return MODE_PANEL; |
249,8 → 251,10 |
{ |
struct drm_device *dev = encoder->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_lvds *intel_lvds = to_intel_lvds(encoder); |
struct intel_crtc *intel_crtc = intel_lvds->base.new_crtc; |
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder); |
struct intel_connector *intel_connector = |
&lvds_encoder->attached_connector->base; |
struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc; |
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
int pipe; |
|
260,7 → 264,7 |
return false; |
} |
|
if (intel_encoder_check_is_cloned(&intel_lvds->base)) |
if (intel_encoder_check_is_cloned(&lvds_encoder->base)) |
return false; |
|
/* |
269,10 → 273,12 |
* with the panel scaling set up to source from the H/VDisplay |
* of the original mode. |
*/ |
intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode); |
intel_fixed_panel_mode(intel_connector->panel.fixed_mode, |
adjusted_mode); |
|
if (HAS_PCH_SPLIT(dev)) { |
intel_pch_panel_fitting(dev, intel_lvds->fitting_mode, |
intel_pch_panel_fitting(dev, |
intel_connector->panel.fitting_mode, |
mode, adjusted_mode); |
return true; |
} |
298,7 → 304,7 |
|
drm_mode_set_crtcinfo(adjusted_mode, 0); |
|
switch (intel_lvds->fitting_mode) { |
switch (intel_connector->panel.fitting_mode) { |
case DRM_MODE_SCALE_CENTER: |
/* |
* For centered modes, we have to calculate border widths & |
396,11 → 402,11 |
if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither) |
pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
|
if (pfit_control != intel_lvds->pfit_control || |
pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) { |
intel_lvds->pfit_control = pfit_control; |
intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; |
intel_lvds->pfit_dirty = true; |
if (pfit_control != lvds_encoder->pfit_control || |
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; |
|
449,14 → 455,15 |
*/ |
static int intel_lvds_get_modes(struct drm_connector *connector) |
{ |
struct intel_lvds *intel_lvds = intel_attached_lvds(connector); |
struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector); |
struct drm_device *dev = connector->dev; |
struct drm_display_mode *mode; |
|
if (intel_lvds->edid) |
return drm_add_edid_modes(connector, intel_lvds->edid); |
/* use cached edid if we have one */ |
if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) |
return drm_add_edid_modes(connector, lvds_connector->base.edid); |
|
mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); |
mode = drm_mode_duplicate(dev, lvds_connector->base.panel.fixed_mode); |
if (mode == NULL) |
return 0; |
|
497,10 → 504,11 |
static int intel_lid_notify(struct notifier_block *nb, unsigned long val, |
void *unused) |
{ |
struct drm_i915_private *dev_priv = |
container_of(nb, struct drm_i915_private, lid_notifier); |
struct drm_device *dev = dev_priv->dev; |
struct drm_connector *connector = dev_priv->int_lvds_connector; |
struct intel_lvds_connector *lvds_connector = |
container_of(nb, struct intel_lvds_connector, lid_notifier); |
struct drm_connector *connector = &lvds_connector->base.base; |
struct drm_device *dev = connector->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
if (dev->switch_power_state != DRM_SWITCH_POWER_ON) |
return NOTIFY_OK; |
509,9 → 517,7 |
* check and update the status of LVDS connector after receiving |
* the LID nofication event. |
*/ |
if (connector) |
connector->status = connector->funcs->detect(connector, |
false); |
connector->status = connector->funcs->detect(connector, false); |
|
/* Don't force modeset on machines where it causes a GPU lockup */ |
if (dmi_check_system(intel_no_modeset_on_lid)) |
527,7 → 533,7 |
dev_priv->modeset_on_lid = 0; |
|
mutex_lock(&dev->mode_config.mutex); |
intel_modeset_check_state(dev); |
intel_modeset_setup_hw_state(dev, true); |
mutex_unlock(&dev->mode_config.mutex); |
|
return NOTIFY_OK; |
543,13 → 549,16 |
*/ |
static void intel_lvds_destroy(struct drm_connector *connector) |
{ |
struct drm_device *dev = connector->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_lvds_connector *lvds_connector = |
to_lvds_connector(connector); |
|
intel_panel_destroy_backlight(dev); |
|
// if (dev_priv->lid_notifier.notifier_call) |
// acpi_lid_notifier_unregister(&dev_priv->lid_notifier); |
if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) |
kfree(lvds_connector->base.edid); |
|
intel_panel_destroy_backlight(connector->dev); |
intel_panel_fini(&lvds_connector->base.panel); |
|
drm_sysfs_connector_remove(connector); |
drm_connector_cleanup(connector); |
kfree(connector); |
559,11 → 568,11 |
struct drm_property *property, |
uint64_t value) |
{ |
struct intel_lvds *intel_lvds = intel_attached_lvds(connector); |
struct intel_connector *intel_connector = to_intel_connector(connector); |
struct drm_device *dev = connector->dev; |
|
if (property == dev->mode_config.scaling_mode_property) { |
struct drm_crtc *crtc = intel_lvds->base.base.crtc; |
struct drm_crtc *crtc; |
|
if (value == DRM_MODE_SCALE_NONE) { |
DRM_DEBUG_KMS("no scaling not supported\n"); |
570,11 → 579,13 |
return -EINVAL; |
} |
|
if (intel_lvds->fitting_mode == value) { |
if (intel_connector->panel.fitting_mode == value) { |
/* the LVDS scaling property is not changed */ |
return 0; |
} |
intel_lvds->fitting_mode = value; |
intel_connector->panel.fitting_mode = value; |
|
crtc = intel_attached_encoder(connector)->base.crtc; |
if (crtc && crtc->enabled) { |
/* |
* If the CRTC is enabled, the display will be changed |
765,14 → 776,6 |
}, |
{ |
.callback = intel_no_lvds_dmi_callback, |
.ident = "ZOTAC ZBOXSD-ID12/ID13", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "ZOTAC"), |
DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"), |
}, |
}, |
{ |
.callback = intel_no_lvds_dmi_callback, |
.ident = "Gigabyte GA-D525TUD", |
.matches = { |
DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), |
914,12 → 917,15 |
bool intel_lvds_init(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_lvds *intel_lvds; |
struct intel_lvds_encoder *lvds_encoder; |
struct intel_encoder *intel_encoder; |
struct intel_lvds_connector *lvds_connector; |
struct intel_connector *intel_connector; |
struct drm_connector *connector; |
struct drm_encoder *encoder; |
struct drm_display_mode *scan; /* *modes, *bios_mode; */ |
struct drm_display_mode *fixed_mode = NULL; |
struct edid *edid; |
struct drm_crtc *crtc; |
u32 lvds; |
int pipe; |
947,23 → 953,25 |
} |
} |
|
intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); |
if (!intel_lvds) { |
lvds_encoder = kzalloc(sizeof(struct intel_lvds_encoder), GFP_KERNEL); |
if (!lvds_encoder) |
return false; |
} |
|
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); |
if (!intel_connector) { |
kfree(intel_lvds); |
lvds_connector = kzalloc(sizeof(struct intel_lvds_connector), GFP_KERNEL); |
if (!lvds_connector) { |
kfree(lvds_encoder); |
return false; |
} |
|
lvds_encoder->attached_connector = lvds_connector; |
|
if (!HAS_PCH_SPLIT(dev)) { |
intel_lvds->pfit_control = I915_READ(PFIT_CONTROL); |
lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL); |
} |
|
intel_encoder = &intel_lvds->base; |
intel_encoder = &lvds_encoder->base; |
encoder = &intel_encoder->base; |
intel_connector = &lvds_connector->base; |
connector = &intel_connector->base; |
drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs, |
DRM_MODE_CONNECTOR_LVDS); |
995,14 → 1003,10 |
|
/* create the scaling mode property */ |
drm_mode_create_scaling_mode_property(dev); |
/* |
* the initial panel fitting mode will be FULL_SCREEN. |
*/ |
|
drm_connector_attach_property(&intel_connector->base, |
drm_object_attach_property(&connector->base, |
dev->mode_config.scaling_mode_property, |
DRM_MODE_SCALE_ASPECT); |
intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT; |
intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT; |
/* |
* LVDS discovery: |
* 1) check for EDID on DDC |
1017,20 → 1021,21 |
* Attempt to get the fixed panel mode from DDC. Assume that the |
* preferred mode is the right one. |
*/ |
intel_lvds->edid = drm_get_edid(connector, |
intel_gmbus_get_adapter(dev_priv, |
pin)); |
if (intel_lvds->edid) { |
if (drm_add_edid_modes(connector, |
intel_lvds->edid)) { |
edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, pin)); |
if (edid) { |
if (drm_add_edid_modes(connector, edid)) { |
drm_mode_connector_update_edid_property(connector, |
intel_lvds->edid); |
edid); |
} else { |
kfree(intel_lvds->edid); |
intel_lvds->edid = NULL; |
kfree(edid); |
edid = ERR_PTR(-EINVAL); |
} |
} else { |
edid = ERR_PTR(-ENOENT); |
} |
if (!intel_lvds->edid) { |
lvds_connector->base.edid = edid; |
|
if (IS_ERR_OR_NULL(edid)) { |
/* Didn't get an EDID, so |
* Set wide sync ranges so we get all modes |
* handed to valid_mode for checking |
1043,22 → 1048,26 |
|
list_for_each_entry(scan, &connector->probed_modes, head) { |
if (scan->type & DRM_MODE_TYPE_PREFERRED) { |
intel_lvds->fixed_mode = |
drm_mode_duplicate(dev, scan); |
intel_find_lvds_downclock(dev, |
intel_lvds->fixed_mode, |
DRM_DEBUG_KMS("using preferred mode from EDID: "); |
drm_mode_debug_printmodeline(scan); |
|
fixed_mode = drm_mode_duplicate(dev, scan); |
if (fixed_mode) { |
intel_find_lvds_downclock(dev, fixed_mode, |
connector); |
goto out; |
} |
} |
} |
|
/* Failed to get EDID, what about VBT? */ |
if (dev_priv->lfp_lvds_vbt_mode) { |
intel_lvds->fixed_mode = |
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); |
if (intel_lvds->fixed_mode) { |
intel_lvds->fixed_mode->type |= |
DRM_MODE_TYPE_PREFERRED; |
DRM_DEBUG_KMS("using mode from VBT: "); |
drm_mode_debug_printmodeline(dev_priv->lfp_lvds_vbt_mode); |
|
fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); |
if (fixed_mode) { |
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; |
goto out; |
} |
} |
1078,16 → 1087,17 |
crtc = intel_get_crtc_for_pipe(dev, pipe); |
|
if (crtc && (lvds & LVDS_PORT_EN)) { |
intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc); |
if (intel_lvds->fixed_mode) { |
intel_lvds->fixed_mode->type |= |
DRM_MODE_TYPE_PREFERRED; |
fixed_mode = intel_crtc_mode_get(dev, crtc); |
if (fixed_mode) { |
DRM_DEBUG_KMS("using current (BIOS) mode: "); |
drm_mode_debug_printmodeline(fixed_mode); |
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; |
goto out; |
} |
} |
|
/* If we still don't have a mode after all that, give up. */ |
if (!intel_lvds->fixed_mode) |
if (!fixed_mode) |
goto failed; |
|
out: |
1107,11 → 1117,10 |
// DRM_DEBUG_KMS("lid notifier registration failed\n"); |
// dev_priv->lid_notifier.notifier_call = NULL; |
// } |
/* keep the LVDS connector */ |
dev_priv->int_lvds_connector = connector; |
drm_sysfs_connector_add(connector); |
|
intel_panel_setup_backlight(dev); |
intel_panel_init(&intel_connector->panel, fixed_mode); |
intel_panel_setup_backlight(connector); |
|
return true; |
|
1119,7 → 1128,9 |
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n"); |
drm_connector_cleanup(connector); |
drm_encoder_cleanup(encoder); |
kfree(intel_lvds); |
kfree(intel_connector); |
if (fixed_mode) |
drm_mode_destroy(dev, fixed_mode); |
kfree(lvds_encoder); |
kfree(lvds_connector); |
return false; |
} |