mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 01:51:53 +00:00
drm/i915: protect backlight registers and data with a spinlock
Backlight data and registers are fiddled through LVDS/eDP modeset enable/disable hooks, backlight sysfs files, asle interrupts, and register save/restore. Protect the backlight related registers and driver private fields using a spinlock. The locking in register save/restore covers a little more than is strictly necessary, including non-modeset case, for simplicity. v2: Cover register access, save/restore, i915_read_blc_pwm_ctl() and code paths leading there. Signed-off-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
d654063273
commit
8ba2d18520
@ -1633,6 +1633,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
spin_lock_init(&dev_priv->irq_lock);
|
||||
spin_lock_init(&dev_priv->gpu_error.lock);
|
||||
spin_lock_init(&dev_priv->rps.lock);
|
||||
spin_lock_init(&dev_priv->backlight.lock);
|
||||
mutex_init(&dev_priv->dpio_lock);
|
||||
|
||||
mutex_init(&dev_priv->rps.hw_lock);
|
||||
|
@ -960,6 +960,7 @@ typedef struct drm_i915_private {
|
||||
struct {
|
||||
int level;
|
||||
bool enabled;
|
||||
spinlock_t lock; /* bl registers and the above bl fields */
|
||||
struct backlight_device *device;
|
||||
} backlight;
|
||||
|
||||
|
@ -192,6 +192,7 @@ static void i915_restore_vga(struct drm_device *dev)
|
||||
static void i915_save_display(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long flags;
|
||||
|
||||
/* Display arbitration control */
|
||||
if (INTEL_INFO(dev)->gen <= 4)
|
||||
@ -202,6 +203,8 @@ static void i915_save_display(struct drm_device *dev)
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
i915_save_display_reg(dev);
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
|
||||
|
||||
/* LVDS state */
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
|
||||
@ -222,6 +225,8 @@ static void i915_save_display(struct drm_device *dev)
|
||||
dev_priv->regfile.saveLVDS = I915_READ(LVDS);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
|
||||
|
||||
if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
|
||||
|
||||
@ -257,6 +262,7 @@ static void i915_restore_display(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 mask = 0xffffffff;
|
||||
unsigned long flags;
|
||||
|
||||
/* Display arbitration */
|
||||
if (INTEL_INFO(dev)->gen <= 4)
|
||||
@ -265,6 +271,8 @@ static void i915_restore_display(struct drm_device *dev)
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
i915_restore_display_reg(dev);
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
|
||||
|
||||
/* LVDS state */
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
|
||||
@ -304,6 +312,8 @@ static void i915_restore_display(struct drm_device *dev)
|
||||
I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
|
||||
|
||||
/* only restore FBC info on the platform that supports FBC*/
|
||||
intel_disable_fbc(dev);
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
|
@ -138,6 +138,8 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
|
||||
WARN_ON(!spin_is_locked(&dev_priv->backlight.lock));
|
||||
|
||||
/* Restore the CTL value if it lost, e.g. GPU reset */
|
||||
|
||||
if (HAS_PCH_SPLIT(dev_priv->dev)) {
|
||||
@ -218,6 +220,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
@ -235,6 +240,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev)
|
||||
}
|
||||
|
||||
val = intel_panel_compute_brightness(dev, val);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
|
||||
|
||||
DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
|
||||
return val;
|
||||
}
|
||||
@ -282,11 +290,14 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 freq;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
|
||||
|
||||
freq = intel_panel_get_max_backlight(dev);
|
||||
if (!freq) {
|
||||
/* we are screwed, bail out */
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* scale to hardware */
|
||||
@ -298,11 +309,16 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
|
||||
|
||||
if (dev_priv->backlight.enabled)
|
||||
intel_panel_actually_set_backlight(dev, level);
|
||||
out:
|
||||
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
|
||||
}
|
||||
|
||||
void intel_panel_disable_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
|
||||
|
||||
dev_priv->backlight.enabled = false;
|
||||
intel_panel_actually_set_backlight(dev, 0);
|
||||
@ -320,12 +336,17 @@ void intel_panel_disable_backlight(struct drm_device *dev)
|
||||
I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
|
||||
}
|
||||
|
||||
void intel_panel_enable_backlight(struct drm_device *dev,
|
||||
enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
|
||||
|
||||
if (dev_priv->backlight.level == 0) {
|
||||
dev_priv->backlight.level = intel_panel_get_max_backlight(dev);
|
||||
@ -375,6 +396,8 @@ set_level:
|
||||
*/
|
||||
dev_priv->backlight.enabled = true;
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight.level);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
|
||||
}
|
||||
|
||||
static void intel_panel_init_backlight(struct drm_device *dev)
|
||||
@ -432,6 +455,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct backlight_properties props;
|
||||
unsigned long flags;
|
||||
|
||||
intel_panel_init_backlight(dev);
|
||||
|
||||
@ -441,7 +465,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.brightness = dev_priv->backlight.level;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight.lock, flags);
|
||||
props.max_brightness = intel_panel_get_max_backlight(dev);
|
||||
spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
|
||||
|
||||
if (props.max_brightness == 0) {
|
||||
DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
|
||||
return -ENODEV;
|
||||
|
Loading…
Reference in New Issue
Block a user