/* * Returns the maximum level of the backlight duty cycle field.
*/ static u32 psb_intel_lvds_get_max_backlight(struct drm_device *dev)
{ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
u32 ret;
if (gma_power_begin(dev, false)) {
ret = REG_READ(BLC_PWM_CTL);
gma_power_end(dev);
} else/* Powered off, use the saved value */
ret = dev_priv->regs.saveBLC_PWM_CTL;
/* Top 15bits hold the frequency mask */
ret = (ret & BACKLIGHT_MODULATION_FREQ_MASK) >>
BACKLIGHT_MODULATION_FREQ_SHIFT;
ret *= 2; /* Return a 16bit range as needed for setting */ if (ret == 0)
dev_err(dev->dev, "BL bug: Reg %08x save %08X\n",
REG_READ(BLC_PWM_CTL), dev_priv->regs.saveBLC_PWM_CTL); return ret;
}
/* * Set LVDS backlight level by I2C command * * FIXME: at some point we need to both track this for PM and also * disable runtime pm on MRST if the brightness is nil (ie blanked)
*/ staticint psb_lvds_i2c_set_brightness(struct drm_device *dev, unsignedint level)
{ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
/* * Set LVDS backlight level either by I2C or PWM
*/ void psb_intel_lvds_set_brightness(struct drm_device *dev, int level)
{ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
dev_dbg(dev->dev, "backlight level is %d\n", level);
if (!dev_priv->lvds_bl) {
dev_err(dev->dev, "NO LVDS backlight info\n"); return;
}
if (dev_priv->lvds_bl->type == BLC_I2C_TYPE)
psb_lvds_i2c_set_brightness(dev, level); else
psb_lvds_pwm_set_brightness(dev, level);
}
/* * Sets the backlight level. * * level: backlight level, from 0 to psb_intel_lvds_get_max_backlight().
*/ staticvoid psb_intel_lvds_set_backlight(struct drm_device *dev, int level)
{ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
u32 blc_pwm_ctl;
/*TODO: move backlight_duty_cycle to psb_intel_lvds_priv*/
dev_priv->backlight_duty_cycle = (dev_priv->regs.saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK);
/* * If the light is off at server startup, * just make it full brightness
*/ if (dev_priv->backlight_duty_cycle == 0)
dev_priv->backlight_duty_cycle =
psb_intel_lvds_get_max_backlight(dev);
if (gma_encoder->type == INTEL_OUTPUT_MIPI2)
panel_fixed_mode = mode_dev->panel_fixed_mode2;
/* PSB requires the LVDS is on pipe B, MRST has only one pipe anyway */ if (!IS_MRST(dev) && gma_crtc->pipe == 0) {
pr_err("Can't support LVDS on pipe A\n"); returnfalse;
} if (IS_MRST(dev) && gma_crtc->pipe != 0) {
pr_err("Must use PIPE A\n"); returnfalse;
} /* Should never happen!! */
list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list,
head) { if (tmp_encoder != encoder
&& tmp_encoder->crtc == encoder->crtc) {
pr_err("Can't enable LVDS and another encoder on the same pipe\n"); returnfalse;
}
}
/* * If 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.
*/ if (panel_fixed_mode != NULL) {
adjusted_mode->hdisplay = panel_fixed_mode->hdisplay;
adjusted_mode->hsync_start = panel_fixed_mode->hsync_start;
adjusted_mode->hsync_end = panel_fixed_mode->hsync_end;
adjusted_mode->htotal = panel_fixed_mode->htotal;
adjusted_mode->vdisplay = panel_fixed_mode->vdisplay;
adjusted_mode->vsync_start = panel_fixed_mode->vsync_start;
adjusted_mode->vsync_end = panel_fixed_mode->vsync_end;
adjusted_mode->vtotal = panel_fixed_mode->vtotal;
adjusted_mode->clock = panel_fixed_mode->clock;
drm_mode_set_crtcinfo(adjusted_mode,
CRTC_INTERLACE_HALVE_V);
}
/* * 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.
*/
/* * The LVDS pin pair will already have been turned on in the * psb_intel_crtc_mode_set since it has a large impact on the DPLL * settings.
*/
/* * Enable automatic panel scaling so that non-native modes fill the * screen. Should be enabled before the pipe is enabled, according to * register description and PRM.
*/ if (mode->hdisplay != adjusted_mode->hdisplay ||
mode->vdisplay != adjusted_mode->vdisplay)
pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
HORIZ_INTERP_BILINEAR); else
pfit_control = 0;
if (dev_priv->lvds_dither)
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
REG_WRITE(PFIT_CONTROL, pfit_control);
}
/* * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
*/ staticint psb_intel_lvds_get_modes(struct drm_connector *connector)
{ struct drm_device *dev = connector->dev; struct drm_psb_private *dev_priv = to_drm_psb_private(dev); struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; int ret = 0;
if (!IS_MRST(dev))
ret = psb_intel_ddc_get_modes(connector, connector->ddc);
if (ret) return ret;
if (mode_dev->panel_fixed_mode != NULL) { struct drm_display_mode *mode =
drm_mode_duplicate(dev, mode_dev->panel_fixed_mode); if (!mode) return 0;
/* Set up the DDC bus. */
ddc_bus = gma_i2c_create(dev, GPIOC, "LVDSDDC_C"); if (!ddc_bus) {
dev_printk(KERN_ERR, dev->dev, "DDC bus registration ""failed.\n"); goto err_free_lvds_priv;
}
ret = drm_connector_init_with_ddc(dev, connector,
&psb_intel_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS,
&ddc_bus->base); if (ret) goto err_ddc_destroy;
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); if (ret) goto err_connector_cleanup;
/* * Set up I2C bus * FIXME: distroy i2c_bus when exit
*/
lvds_priv->i2c_bus = gma_i2c_create(dev, GPIOB, "LVDSBLC_B"); if (!lvds_priv->i2c_bus) {
dev_printk(KERN_ERR,
dev->dev, "I2C bus registration failed.\n"); goto err_encoder_cleanup;
}
lvds_priv->i2c_bus->target_addr = 0x2C;
dev_priv->lvds_i2c_bus = lvds_priv->i2c_bus;
/* * 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 * 4) make sure lid is open * if closed, act like it's not there for now
*/
/* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one.
*/
mutex_lock(&dev->mode_config.mutex);
psb_intel_ddc_get_modes(connector, &ddc_bus->base);
list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) {
mode_dev->panel_fixed_mode =
drm_mode_duplicate(dev, scan);
DRM_DEBUG_KMS("Using mode from DDC\n"); goto out; /* FIXME: check for quirks */
}
}
/* Failed to get EDID, what about VBT? do we need this? */ if (dev_priv->lfp_lvds_vbt_mode) {
mode_dev->panel_fixed_mode =
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
if (mode_dev->panel_fixed_mode) {
mode_dev->panel_fixed_mode->type |=
DRM_MODE_TYPE_PREFERRED;
DRM_DEBUG_KMS("Using mode from VBT\n"); goto out;
}
}
/* * If we didn't get EDID, try checking if the panel is already turned * on. If so, assume that whatever is currently programmed is the * correct mode.
*/
lvds = REG_READ(LVDS);
pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
crtc = psb_intel_get_crtc_from_pipe(dev, pipe);
if (crtc && (lvds & LVDS_PORT_EN)) {
mode_dev->panel_fixed_mode =
psb_intel_crtc_mode_get(dev, crtc); if (mode_dev->panel_fixed_mode) {
mode_dev->panel_fixed_mode->type |=
DRM_MODE_TYPE_PREFERRED;
DRM_DEBUG_KMS("Using pre-programmed mode\n"); goto out; /* FIXME: check for quirks */
}
}
/* If we still don't have a mode after all that, give up. */ if (!mode_dev->panel_fixed_mode) {
dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); goto err_unlock;
}
/* * Blacklist machines with BIOSes that list an LVDS panel without * actually having one.
*/
out:
mutex_unlock(&dev->mode_config.mutex); return;
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.