drm/i915: Refactor panel backlight controls
There were two instances of code to control the panel backlight and neither handled the complete set of device variations. Fixes: Bug 29716 - [GM965] Regression: Backlight resets to minimum when changing resolution https://bugs.freedesktop.org/show_bug.cgi?id=29716 And a bug on one of my PineView boxes which overflowed the backlight value. Incorporates part of a similar patch by Matthew Garrett that exposes a native Intel backlight controller. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Родитель
5d607f9b03
Коммит
a957355693
|
@ -319,7 +319,7 @@ typedef struct drm_i915_private {
|
||||||
struct intel_overlay *overlay;
|
struct intel_overlay *overlay;
|
||||||
|
|
||||||
/* LVDS info */
|
/* LVDS info */
|
||||||
int backlight_duty_cycle; /* restore backlight to this value */
|
int backlight_level; /* restore backlight to this value */
|
||||||
bool panel_wants_dither;
|
bool panel_wants_dither;
|
||||||
struct drm_display_mode *panel_fixed_mode;
|
struct drm_display_mode *panel_fixed_mode;
|
||||||
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
|
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
|
||||||
|
|
|
@ -204,13 +204,16 @@ extern bool intel_pch_has_edp(struct drm_crtc *crtc);
|
||||||
extern bool intel_dpd_is_edp(struct drm_device *dev);
|
extern bool intel_dpd_is_edp(struct drm_device *dev);
|
||||||
extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
|
extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
|
||||||
|
|
||||||
|
/* intel_panel.c */
|
||||||
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
|
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
|
||||||
struct drm_display_mode *adjusted_mode);
|
struct drm_display_mode *adjusted_mode);
|
||||||
extern void intel_pch_panel_fitting(struct drm_device *dev,
|
extern void intel_pch_panel_fitting(struct drm_device *dev,
|
||||||
int fitting_mode,
|
int fitting_mode,
|
||||||
struct drm_display_mode *mode,
|
struct drm_display_mode *mode,
|
||||||
struct drm_display_mode *adjusted_mode);
|
struct drm_display_mode *adjusted_mode);
|
||||||
|
extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
|
||||||
|
extern u32 intel_panel_get_backlight(struct drm_device *dev);
|
||||||
|
extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
|
||||||
|
|
||||||
extern int intel_panel_fitter_pipe (struct drm_device *dev);
|
extern int intel_panel_fitter_pipe (struct drm_device *dev);
|
||||||
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
|
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
|
||||||
|
|
|
@ -53,43 +53,6 @@ static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
|
||||||
return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
|
return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the backlight level.
|
|
||||||
*
|
|
||||||
* \param level backlight level, from 0 to intel_lvds_get_max_backlight().
|
|
||||||
*/
|
|
||||||
static void intel_lvds_set_backlight(struct drm_device *dev, int level)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
u32 blc_pwm_ctl, reg;
|
|
||||||
|
|
||||||
if (HAS_PCH_SPLIT(dev))
|
|
||||||
reg = BLC_PWM_CPU_CTL;
|
|
||||||
else
|
|
||||||
reg = BLC_PWM_CTL;
|
|
||||||
|
|
||||||
blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
|
|
||||||
I915_WRITE(reg, (blc_pwm_ctl |
|
|
||||||
(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum level of the backlight duty cycle field.
|
|
||||||
*/
|
|
||||||
static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
u32 reg;
|
|
||||||
|
|
||||||
if (HAS_PCH_SPLIT(dev))
|
|
||||||
reg = BLC_PWM_PCH_CTL2;
|
|
||||||
else
|
|
||||||
reg = BLC_PWM_CTL;
|
|
||||||
|
|
||||||
return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
|
|
||||||
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the power state for the panel.
|
* Sets the power state for the panel.
|
||||||
*/
|
*/
|
||||||
|
@ -117,9 +80,9 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
|
||||||
if (wait_for(I915_READ(status_reg) & PP_ON, 1000))
|
if (wait_for(I915_READ(status_reg) & PP_ON, 1000))
|
||||||
DRM_ERROR("timed out waiting to enable LVDS pipe");
|
DRM_ERROR("timed out waiting to enable LVDS pipe");
|
||||||
|
|
||||||
intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
|
intel_panel_set_backlight(dev, dev_priv->backlight_level);
|
||||||
} else {
|
} else {
|
||||||
intel_lvds_set_backlight(dev, 0);
|
intel_panel_set_backlight(dev, 0);
|
||||||
|
|
||||||
I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
|
I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
|
||||||
~POWER_TARGET_ON);
|
~POWER_TARGET_ON);
|
||||||
|
@ -386,16 +349,8 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = encoder->dev;
|
struct drm_device *dev = encoder->dev;
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
u32 reg;
|
|
||||||
|
|
||||||
if (HAS_PCH_SPLIT(dev))
|
dev_priv->backlight_level = intel_panel_get_backlight(dev);
|
||||||
reg = BLC_PWM_CPU_CTL;
|
|
||||||
else
|
|
||||||
reg = BLC_PWM_CTL;
|
|
||||||
|
|
||||||
dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
|
|
||||||
dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
|
|
||||||
BACKLIGHT_DUTY_CYCLE_MASK);
|
|
||||||
|
|
||||||
intel_lvds_set_power(dev, false);
|
intel_lvds_set_power(dev, false);
|
||||||
}
|
}
|
||||||
|
@ -405,9 +360,8 @@ static void intel_lvds_commit( struct drm_encoder *encoder)
|
||||||
struct drm_device *dev = encoder->dev;
|
struct drm_device *dev = encoder->dev;
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
if (dev_priv->backlight_duty_cycle == 0)
|
if (dev_priv->backlight_level == 0)
|
||||||
dev_priv->backlight_duty_cycle =
|
dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
|
||||||
intel_lvds_get_max_backlight(dev);
|
|
||||||
|
|
||||||
intel_lvds_set_power(dev, true);
|
intel_lvds_set_power(dev, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,9 @@
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "i915_drm.h"
|
#include "i915_drm.h"
|
||||||
#include "i915_drv.h"
|
#include "i915_drv.h"
|
||||||
|
#include "intel_drv.h"
|
||||||
|
|
||||||
#define PCI_ASLE 0xe4
|
#define PCI_ASLE 0xe4
|
||||||
#define PCI_LBPC 0xf4
|
|
||||||
#define PCI_ASLS 0xfc
|
#define PCI_ASLS 0xfc
|
||||||
|
|
||||||
#define OPREGION_HEADER_OFFSET 0
|
#define OPREGION_HEADER_OFFSET 0
|
||||||
|
@ -147,36 +147,17 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||||
u32 blc_pwm_ctl, blc_pwm_ctl2;
|
u32 max;
|
||||||
u32 max_backlight, level, shift;
|
|
||||||
|
|
||||||
if (!(bclp & ASLE_BCLP_VALID))
|
if (!(bclp & ASLE_BCLP_VALID))
|
||||||
return ASLE_BACKLIGHT_FAILED;
|
return ASLE_BACKLIGHT_FAILED;
|
||||||
|
|
||||||
bclp &= ASLE_BCLP_MSK;
|
bclp &= ASLE_BCLP_MSK;
|
||||||
if (bclp < 0 || bclp > 255)
|
if (bclp > 255)
|
||||||
return ASLE_BACKLIGHT_FAILED;
|
return ASLE_BACKLIGHT_FAILED;
|
||||||
|
|
||||||
blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
|
max = intel_panel_get_max_backlight(dev);
|
||||||
blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
|
intel_panel_set_backlight(dev, bclp * max / 255);
|
||||||
|
|
||||||
if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
|
|
||||||
pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
|
|
||||||
else {
|
|
||||||
if (IS_PINEVIEW(dev)) {
|
|
||||||
blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
|
|
||||||
max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >>
|
|
||||||
BACKLIGHT_MODULATION_FREQ_SHIFT;
|
|
||||||
shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
|
|
||||||
} else {
|
|
||||||
blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
|
|
||||||
max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >>
|
|
||||||
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
|
|
||||||
shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
|
|
||||||
}
|
|
||||||
level = (bclp * max_backlight) / 255;
|
|
||||||
I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
|
|
||||||
}
|
|
||||||
asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
|
asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -243,36 +224,6 @@ void intel_opregion_asle_intr(struct drm_device *dev)
|
||||||
asle->aslc = asle_stat;
|
asle->aslc = asle_stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
||||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
|
||||||
u32 cpu_pwm_ctl, pch_pwm_ctl2;
|
|
||||||
u32 max_backlight, level;
|
|
||||||
|
|
||||||
if (!(bclp & ASLE_BCLP_VALID))
|
|
||||||
return ASLE_BACKLIGHT_FAILED;
|
|
||||||
|
|
||||||
bclp &= ASLE_BCLP_MSK;
|
|
||||||
if (bclp < 0 || bclp > 255)
|
|
||||||
return ASLE_BACKLIGHT_FAILED;
|
|
||||||
|
|
||||||
cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
|
|
||||||
pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
|
|
||||||
/* get the max PWM frequency */
|
|
||||||
max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
|
|
||||||
/* calculate the expected PMW frequency */
|
|
||||||
level = (bclp * max_backlight) / 255;
|
|
||||||
/* reserve the high 16 bits */
|
|
||||||
cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
|
|
||||||
/* write the updated PWM frequency */
|
|
||||||
I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
|
|
||||||
|
|
||||||
asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only present on Ironlake+ */
|
/* Only present on Ironlake+ */
|
||||||
void intel_opregion_gse_intr(struct drm_device *dev)
|
void intel_opregion_gse_intr(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -297,7 +248,7 @@ void intel_opregion_gse_intr(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asle_req & ASLE_SET_BACKLIGHT)
|
if (asle_req & ASLE_SET_BACKLIGHT)
|
||||||
asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
|
asle_stat |= asle_set_backlight(dev, asle->bclp);
|
||||||
|
|
||||||
if (asle_req & ASLE_SET_PFIT) {
|
if (asle_req & ASLE_SET_PFIT) {
|
||||||
DRM_DEBUG_DRIVER("Pfit is not supported\n");
|
DRM_DEBUG_DRIVER("Pfit is not supported\n");
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "intel_drv.h"
|
#include "intel_drv.h"
|
||||||
|
|
||||||
|
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
|
||||||
|
|
||||||
void
|
void
|
||||||
intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
|
intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
|
||||||
struct drm_display_mode *adjusted_mode)
|
struct drm_display_mode *adjusted_mode)
|
||||||
|
@ -109,3 +111,110 @@ done:
|
||||||
dev_priv->pch_pf_pos = (x << 16) | y;
|
dev_priv->pch_pf_pos = (x << 16) | y;
|
||||||
dev_priv->pch_pf_size = (width << 16) | height;
|
dev_priv->pch_pf_size = (width << 16) | height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_backlight_combination_mode(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
|
||||||
|
if (IS_I965G(dev))
|
||||||
|
return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
|
||||||
|
|
||||||
|
if (IS_GEN2(dev))
|
||||||
|
return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 intel_panel_get_max_backlight(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
u32 max;
|
||||||
|
|
||||||
|
if (HAS_PCH_SPLIT(dev)) {
|
||||||
|
max = I915_READ(BLC_PWM_PCH_CTL2) >> 16;
|
||||||
|
} else {
|
||||||
|
max = I915_READ(BLC_PWM_CTL);
|
||||||
|
if (IS_PINEVIEW(dev)) {
|
||||||
|
max >>= 17;
|
||||||
|
} else {
|
||||||
|
max >>= 16;
|
||||||
|
if (!IS_I965G(dev))
|
||||||
|
max &= ~1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_backlight_combination_mode(dev))
|
||||||
|
max *= 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max == 0) {
|
||||||
|
/* XXX add code here to query mode clock or hardware clock
|
||||||
|
* and program max PWM appropriately.
|
||||||
|
*/
|
||||||
|
DRM_ERROR("fixme: max PWM is zero.\n");
|
||||||
|
max = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 intel_panel_get_backlight(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (HAS_PCH_SPLIT(dev)) {
|
||||||
|
val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
|
} else {
|
||||||
|
val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
|
if (IS_PINEVIEW(dev))
|
||||||
|
val >>= 1;
|
||||||
|
|
||||||
|
if (is_backlight_combination_mode(dev)){
|
||||||
|
u8 lbpc;
|
||||||
|
|
||||||
|
val &= ~1;
|
||||||
|
pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
|
||||||
|
val *= lbpc;
|
||||||
|
val >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
|
I915_WRITE(BLC_PWM_CPU_CTL, val | level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void intel_panel_set_backlight(struct drm_device *dev, u32 level)
|
||||||
|
{
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
|
||||||
|
|
||||||
|
if (HAS_PCH_SPLIT(dev))
|
||||||
|
return intel_pch_panel_set_backlight(dev, level);
|
||||||
|
|
||||||
|
if (is_backlight_combination_mode(dev)){
|
||||||
|
u32 max = intel_panel_get_max_backlight(dev);
|
||||||
|
u8 lpbc;
|
||||||
|
|
||||||
|
lpbc = level * 0xfe / max + 1;
|
||||||
|
level /= lpbc;
|
||||||
|
pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = I915_READ(BLC_PWM_CTL);
|
||||||
|
if (IS_PINEVIEW(dev)) {
|
||||||
|
tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
|
||||||
|
level <<= 1;
|
||||||
|
} else
|
||||||
|
tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||||
|
I915_WRITE(BLC_PWM_CTL, tmp | level);
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче