diff options
author | Jani Nikula <jani.nikula@intel.com> | 2013-04-12 08:18:37 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2013-04-25 08:10:10 -0400 |
commit | 8ba2d18520ce380cf572e9902d9b3b91ece6c2c0 (patch) | |
tree | eb1ecb47ee2f713bc2980e97db7a0b566334ff90 /drivers/gpu/drm/i915/intel_panel.c | |
parent | d65406327345e5a5e0f697a3ffe3e53bc9b5d7c6 (diff) |
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>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_panel.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 63a7c36a7603..5d3e9d7d51a7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c | |||
@@ -138,6 +138,8 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) | |||
138 | struct drm_i915_private *dev_priv = dev->dev_private; | 138 | struct drm_i915_private *dev_priv = dev->dev_private; |
139 | u32 val; | 139 | u32 val; |
140 | 140 | ||
141 | WARN_ON(!spin_is_locked(&dev_priv->backlight.lock)); | ||
142 | |||
141 | /* Restore the CTL value if it lost, e.g. GPU reset */ | 143 | /* Restore the CTL value if it lost, e.g. GPU reset */ |
142 | 144 | ||
143 | if (HAS_PCH_SPLIT(dev_priv->dev)) { | 145 | if (HAS_PCH_SPLIT(dev_priv->dev)) { |
@@ -218,6 +220,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev) | |||
218 | { | 220 | { |
219 | struct drm_i915_private *dev_priv = dev->dev_private; | 221 | struct drm_i915_private *dev_priv = dev->dev_private; |
220 | u32 val; | 222 | u32 val; |
223 | unsigned long flags; | ||
224 | |||
225 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | ||
221 | 226 | ||
222 | if (HAS_PCH_SPLIT(dev)) { | 227 | if (HAS_PCH_SPLIT(dev)) { |
223 | val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; | 228 | 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) | |||
235 | } | 240 | } |
236 | 241 | ||
237 | val = intel_panel_compute_brightness(dev, val); | 242 | val = intel_panel_compute_brightness(dev, val); |
243 | |||
244 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | ||
245 | |||
238 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); | 246 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
239 | return val; | 247 | return val; |
240 | } | 248 | } |
@@ -282,11 +290,14 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) | |||
282 | { | 290 | { |
283 | struct drm_i915_private *dev_priv = dev->dev_private; | 291 | struct drm_i915_private *dev_priv = dev->dev_private; |
284 | u32 freq; | 292 | u32 freq; |
293 | unsigned long flags; | ||
294 | |||
295 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | ||
285 | 296 | ||
286 | freq = intel_panel_get_max_backlight(dev); | 297 | freq = intel_panel_get_max_backlight(dev); |
287 | if (!freq) { | 298 | if (!freq) { |
288 | /* we are screwed, bail out */ | 299 | /* we are screwed, bail out */ |
289 | return; | 300 | goto out; |
290 | } | 301 | } |
291 | 302 | ||
292 | /* scale to hardware */ | 303 | /* scale to hardware */ |
@@ -298,11 +309,16 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) | |||
298 | 309 | ||
299 | if (dev_priv->backlight.enabled) | 310 | if (dev_priv->backlight.enabled) |
300 | intel_panel_actually_set_backlight(dev, level); | 311 | intel_panel_actually_set_backlight(dev, level); |
312 | out: | ||
313 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | ||
301 | } | 314 | } |
302 | 315 | ||
303 | void intel_panel_disable_backlight(struct drm_device *dev) | 316 | void intel_panel_disable_backlight(struct drm_device *dev) |
304 | { | 317 | { |
305 | struct drm_i915_private *dev_priv = dev->dev_private; | 318 | struct drm_i915_private *dev_priv = dev->dev_private; |
319 | unsigned long flags; | ||
320 | |||
321 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | ||
306 | 322 | ||
307 | dev_priv->backlight.enabled = false; | 323 | dev_priv->backlight.enabled = false; |
308 | intel_panel_actually_set_backlight(dev, 0); | 324 | intel_panel_actually_set_backlight(dev, 0); |
@@ -320,12 +336,17 @@ void intel_panel_disable_backlight(struct drm_device *dev) | |||
320 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); | 336 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
321 | } | 337 | } |
322 | } | 338 | } |
339 | |||
340 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | ||
323 | } | 341 | } |
324 | 342 | ||
325 | void intel_panel_enable_backlight(struct drm_device *dev, | 343 | void intel_panel_enable_backlight(struct drm_device *dev, |
326 | enum pipe pipe) | 344 | enum pipe pipe) |
327 | { | 345 | { |
328 | struct drm_i915_private *dev_priv = dev->dev_private; | 346 | struct drm_i915_private *dev_priv = dev->dev_private; |
347 | unsigned long flags; | ||
348 | |||
349 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | ||
329 | 350 | ||
330 | if (dev_priv->backlight.level == 0) { | 351 | if (dev_priv->backlight.level == 0) { |
331 | dev_priv->backlight.level = intel_panel_get_max_backlight(dev); | 352 | dev_priv->backlight.level = intel_panel_get_max_backlight(dev); |
@@ -375,6 +396,8 @@ set_level: | |||
375 | */ | 396 | */ |
376 | dev_priv->backlight.enabled = true; | 397 | dev_priv->backlight.enabled = true; |
377 | intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); | 398 | intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); |
399 | |||
400 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | ||
378 | } | 401 | } |
379 | 402 | ||
380 | static void intel_panel_init_backlight(struct drm_device *dev) | 403 | static void intel_panel_init_backlight(struct drm_device *dev) |
@@ -432,6 +455,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector) | |||
432 | struct drm_device *dev = connector->dev; | 455 | struct drm_device *dev = connector->dev; |
433 | struct drm_i915_private *dev_priv = dev->dev_private; | 456 | struct drm_i915_private *dev_priv = dev->dev_private; |
434 | struct backlight_properties props; | 457 | struct backlight_properties props; |
458 | unsigned long flags; | ||
435 | 459 | ||
436 | intel_panel_init_backlight(dev); | 460 | intel_panel_init_backlight(dev); |
437 | 461 | ||
@@ -441,7 +465,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector) | |||
441 | memset(&props, 0, sizeof(props)); | 465 | memset(&props, 0, sizeof(props)); |
442 | props.type = BACKLIGHT_RAW; | 466 | props.type = BACKLIGHT_RAW; |
443 | props.brightness = dev_priv->backlight.level; | 467 | props.brightness = dev_priv->backlight.level; |
468 | |||
469 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); | ||
444 | props.max_brightness = intel_panel_get_max_backlight(dev); | 470 | props.max_brightness = intel_panel_get_max_backlight(dev); |
471 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); | ||
472 | |||
445 | if (props.max_brightness == 0) { | 473 | if (props.max_brightness == 0) { |
446 | DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); | 474 | DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); |
447 | return -ENODEV; | 475 | return -ENODEV; |