/* asserts want to know the pipe even if the port is disabled */ if (HAS_PCH_CPT(display))
*pipe = REG_FIELD_GET(LVDS_PIPE_SEL_MASK_CPT, val); else
*pipe = REG_FIELD_GET(LVDS_PIPE_SEL_MASK, val);
val = intel_de_read(display, PP_DIVISOR(display, 0));
pps->divider = REG_FIELD_GET(PP_REFERENCE_DIVIDER_MASK, val);
val = REG_FIELD_GET(PANEL_POWER_CYCLE_DELAY_MASK, val); /* * Remove the BSpec specified +1 (100ms) offset that accounts for a * too short power-cycle delay due to the asynchronous programming of * the register.
*/ if (val)
val--; /* Convert from 100ms to 100us units */
pps->delays.power_cycle = val * 1000;
if (DISPLAY_VER(display) < 5 &&
pps->delays.power_up == 0 &&
pps->delays.backlight_on == 0 &&
pps->delays.power_down == 0 &&
pps->delays.backlight_off == 0) {
drm_dbg_kms(display->drm, "Panel power timings uninitialized, " "setting defaults\n"); /* Set T2 to 40ms and T5 to 200ms in 100 usec units */
pps->delays.power_up = 40 * 10;
pps->delays.backlight_on = 200 * 10; /* Set T3 to 35ms and Tx to 200ms in 100 usec units */
pps->delays.power_down = 35 * 10;
pps->delays.backlight_off = 200 * 10;
}
/* set the corresponding LVDS_BORDER bit */
temp &= ~LVDS_BORDER_ENABLE;
temp |= crtc_state->gmch_pfit.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. For now, let's just maintain the * value we got from the BIOS.
*/
temp &= ~LVDS_A3_POWER_MASK;
temp |= lvds_encoder->a3_power;
/* * 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 TRANSCONF reg.
*/ if (DISPLAY_VER(display) == 4) { /* * Bspec wording suggests that LVDS port dithering only exists * for 18bpp panels.
*/ if (crtc_state->dither && crtc_state->pipe_bpp == 18)
temp |= LVDS_ENABLE_DITHER; else
temp &= ~LVDS_ENABLE_DITHER;
}
temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
temp |= LVDS_HSYNC_POLARITY; if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
temp |= LVDS_VSYNC_POLARITY;
intel_de_rmw(display, PP_CONTROL(display, 0), PANEL_POWER_ON, 0); if (intel_de_wait_for_clear(display, PP_STATUS(display, 0), PP_ON, 1000))
drm_err(display->drm, "timed out waiting for panel to power off\n");
if (intel_de_wait_for_clear(display, PP_STATUS(display, 0), PP_CYCLE_DELAY_ACTIVE, 5000))
drm_err(display->drm, "timed out waiting for panel power cycle delay\n");
}
/* Should never happen!! */ if (DISPLAY_VER(display) < 4 && crtc->pipe == 0) {
drm_err(display->drm, "Can't support LVDS on pipe A\n"); return -EINVAL;
}
if (HAS_PCH_SPLIT(display)) {
crtc_state->has_pch_encoder = true; if (!intel_fdi_compute_pipe_bpp(crtc_state)) return -EINVAL;
}
/* * We have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, * with the panel scaling set up to source from the H/VDisplay * of the original mode.
*/
ret = intel_panel_compute_config(connector, adjusted_mode); if (ret) return ret;
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL;
ret = intel_pfit_compute_config(crtc_state, conn_state); if (ret) return ret;
/* * XXX: It would be nice to support lower refresh rates on the * panels to reduce power consumption, and perhaps match the * user's requested refresh rate.
*/
return 0;
}
/* * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
*/ staticint intel_lvds_get_modes(struct drm_connector *_connector)
{ struct intel_connector *connector = to_intel_connector(_connector); conststruct drm_edid *fixed_edid = connector->panel.fixed_edid;
/* Use panel fixed edid if we have one */ if (!IS_ERR_OR_NULL(fixed_edid)) {
drm_edid_connector_update(&connector->base, fixed_edid);
/* use the module option value if specified */ if (display->params.lvds_channel_mode > 0) return display->params.lvds_channel_mode == 2;
/* single channel LVDS is limited to 112 MHz */ if (fixed_mode->clock > 112999) returntrue;
if (dmi_check_system(intel_dual_link_lvds)) returntrue;
/* * 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 = intel_de_read(display, lvds_encoder->reg); if (HAS_PCH_CPT(display))
val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK_CPT); else
val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK); if (val == 0)
val = connector->panel.vbt.bios_lvds_val;
/** * intel_lvds_init - setup LVDS connectors on this device * @display: display device * * Create the connector, register the LVDS DDC bus, and try to figure out what * modes we can display on the LVDS panel (if present).
*/ void intel_lvds_init(struct intel_display *display)
{ struct intel_lvds_encoder *lvds_encoder; struct intel_connector *connector; conststruct drm_edid *drm_edid; struct intel_encoder *encoder;
i915_reg_t lvds_reg;
u32 lvds;
u8 ddc_pin;
/* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) {
drm_WARN(display->drm, !display->vbt.int_lvds_support, "Useless DMI match. Internal LVDS support disabled by VBT\n"); return;
}
if (!display->vbt.int_lvds_support) {
drm_dbg_kms(display->drm, "Internal LVDS support disabled by VBT\n"); return;
}
if (HAS_PCH_SPLIT(display))
lvds_reg = PCH_LVDS; else
lvds_reg = LVDS;
lvds = intel_de_read(display, lvds_reg);
if (HAS_PCH_SPLIT(display)) { if ((lvds & LVDS_DETECTED) == 0) return;
}
ddc_pin = GMBUS_PIN_PANEL; if (!intel_bios_is_lvds_present(display, &ddc_pin)) { if ((lvds & LVDS_PORT_EN) == 0) {
drm_dbg_kms(display->drm, "LVDS is not present in VBT\n"); return;
}
drm_dbg_kms(display->drm, "LVDS is not present in VBT, but enabled anyway\n");
}
lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL); if (!lvds_encoder) return;
connector = intel_connector_alloc(); if (!connector) {
kfree(lvds_encoder); return;
}
/* * LVDS discovery: * 1) check for EDID on DDC * 2) check for VBT data * 3) check to see if LVDS is already on * if none of the above, no panel
*/
/* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one.
*/
mutex_lock(&display->drm->mode_config.mutex); if (vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC)
drm_edid = drm_edid_read_switcheroo(&connector->base, connector->base.ddc); else
drm_edid = drm_edid_read_ddc(&connector->base, connector->base.ddc); if (drm_edid) { if (drm_edid_connector_update(&connector->base, drm_edid) ||
!drm_edid_connector_add_modes(&connector->base)) {
drm_edid_connector_update(&connector->base, NULL);
drm_edid_free(drm_edid);
drm_edid = ERR_PTR(-EINVAL);
}
} else {
drm_edid = ERR_PTR(-ENOENT);
}
intel_bios_init_panel_late(display, &connector->panel, NULL,
IS_ERR(drm_edid) ? NULL : drm_edid);
/* Try EDID first */
intel_panel_add_edid_fixed_modes(connector, true);
/* Failed to get EDID, what about VBT? */ if (!intel_panel_preferred_fixed_mode(connector))
intel_panel_add_vbt_lfp_fixed_mode(connector);
/* * If we didn't get a fixed mode from EDID or VBT, try checking * if the panel is already turned on. If so, assume that * whatever is currently programmed is the correct mode.
*/ if (!intel_panel_preferred_fixed_mode(connector))
intel_panel_add_encoder_fixed_mode(connector, encoder);
mutex_unlock(&display->drm->mode_config.mutex);
/* If we still don't have a mode after all that, give up. */ if (!intel_panel_preferred_fixed_mode(connector)) goto failed;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.