Rev 5097 | Rev 6084 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2330 | Serge | 1 | /* |
2 | * Copyright © 2006-2010 Intel Corporation |
||
3 | * Copyright (c) 2006 Dave Airlie |
||
4 | * |
||
5 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
6 | * copy of this software and associated documentation files (the "Software"), |
||
7 | * to deal in the Software without restriction, including without limitation |
||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
9 | * and/or sell copies of the Software, and to permit persons to whom the |
||
10 | * Software is furnished to do so, subject to the following conditions: |
||
11 | * |
||
12 | * The above copyright notice and this permission notice (including the next |
||
13 | * paragraph) shall be included in all copies or substantial portions of the |
||
14 | * Software. |
||
15 | * |
||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||
22 | * DEALINGS IN THE SOFTWARE. |
||
23 | * |
||
24 | * Authors: |
||
25 | * Eric Anholt |
||
26 | * Dave Airlie |
||
27 | * Jesse Barnes |
||
28 | * Chris Wilson |
||
29 | */ |
||
30 | |||
3031 | serge | 31 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
32 | |||
33 | #include |
||
2330 | Serge | 34 | #include "intel_drv.h" |
35 | |||
36 | void |
||
4104 | Serge | 37 | intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, |
2330 | Serge | 38 | struct drm_display_mode *adjusted_mode) |
39 | { |
||
4104 | Serge | 40 | drm_mode_copy(adjusted_mode, fixed_mode); |
2330 | Serge | 41 | |
4104 | Serge | 42 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
2330 | Serge | 43 | } |
44 | |||
5060 | serge | 45 | /** |
46 | * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID |
||
47 | * @dev: drm device |
||
48 | * @fixed_mode : panel native mode |
||
49 | * @connector: LVDS/eDP connector |
||
50 | * |
||
51 | * Return downclock_avail |
||
52 | * Find the reduced downclock for LVDS/eDP in EDID. |
||
53 | */ |
||
54 | struct drm_display_mode * |
||
55 | intel_find_panel_downclock(struct drm_device *dev, |
||
56 | struct drm_display_mode *fixed_mode, |
||
57 | struct drm_connector *connector) |
||
58 | { |
||
59 | struct drm_display_mode *scan, *tmp_mode; |
||
60 | int temp_downclock; |
||
61 | |||
62 | temp_downclock = fixed_mode->clock; |
||
63 | tmp_mode = NULL; |
||
64 | |||
65 | list_for_each_entry(scan, &connector->probed_modes, head) { |
||
66 | /* |
||
67 | * If one mode has the same resolution with the fixed_panel |
||
68 | * mode while they have the different refresh rate, it means |
||
69 | * that the reduced downclock is found. In such |
||
70 | * case we can set the different FPx0/1 to dynamically select |
||
71 | * between low and high frequency. |
||
72 | */ |
||
73 | if (scan->hdisplay == fixed_mode->hdisplay && |
||
74 | scan->hsync_start == fixed_mode->hsync_start && |
||
75 | scan->hsync_end == fixed_mode->hsync_end && |
||
76 | scan->htotal == fixed_mode->htotal && |
||
77 | scan->vdisplay == fixed_mode->vdisplay && |
||
78 | scan->vsync_start == fixed_mode->vsync_start && |
||
79 | scan->vsync_end == fixed_mode->vsync_end && |
||
80 | scan->vtotal == fixed_mode->vtotal) { |
||
81 | if (scan->clock < temp_downclock) { |
||
82 | /* |
||
83 | * The downclock is already found. But we |
||
84 | * expect to find the lower downclock. |
||
85 | */ |
||
86 | temp_downclock = scan->clock; |
||
87 | tmp_mode = scan; |
||
88 | } |
||
89 | } |
||
90 | } |
||
91 | |||
92 | if (temp_downclock < fixed_mode->clock) |
||
93 | return drm_mode_duplicate(dev, tmp_mode); |
||
94 | else |
||
95 | return NULL; |
||
96 | } |
||
97 | |||
2330 | Serge | 98 | /* adjusted_mode has been preset to be the panel's fixed mode */ |
99 | void |
||
4104 | Serge | 100 | intel_pch_panel_fitting(struct intel_crtc *intel_crtc, |
101 | struct intel_crtc_config *pipe_config, |
||
102 | int fitting_mode) |
||
2330 | Serge | 103 | { |
4560 | Serge | 104 | struct drm_display_mode *adjusted_mode; |
2330 | Serge | 105 | int x, y, width, height; |
106 | |||
4104 | Serge | 107 | adjusted_mode = &pipe_config->adjusted_mode; |
108 | |||
2330 | Serge | 109 | x = y = width = height = 0; |
110 | |||
111 | /* Native modes don't need fitting */ |
||
4560 | Serge | 112 | if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && |
113 | adjusted_mode->vdisplay == pipe_config->pipe_src_h) |
||
2330 | Serge | 114 | goto done; |
115 | |||
116 | switch (fitting_mode) { |
||
117 | case DRM_MODE_SCALE_CENTER: |
||
4560 | Serge | 118 | width = pipe_config->pipe_src_w; |
119 | height = pipe_config->pipe_src_h; |
||
2330 | Serge | 120 | x = (adjusted_mode->hdisplay - width + 1)/2; |
121 | y = (adjusted_mode->vdisplay - height + 1)/2; |
||
122 | break; |
||
123 | |||
124 | case DRM_MODE_SCALE_ASPECT: |
||
125 | /* Scale but preserve the aspect ratio */ |
||
126 | { |
||
4560 | Serge | 127 | u32 scaled_width = adjusted_mode->hdisplay |
128 | * pipe_config->pipe_src_h; |
||
129 | u32 scaled_height = pipe_config->pipe_src_w |
||
130 | * adjusted_mode->vdisplay; |
||
2330 | Serge | 131 | if (scaled_width > scaled_height) { /* pillar */ |
4560 | Serge | 132 | width = scaled_height / pipe_config->pipe_src_h; |
2330 | Serge | 133 | if (width & 1) |
134 | width++; |
||
135 | x = (adjusted_mode->hdisplay - width + 1) / 2; |
||
136 | y = 0; |
||
137 | height = adjusted_mode->vdisplay; |
||
138 | } else if (scaled_width < scaled_height) { /* letter */ |
||
4560 | Serge | 139 | height = scaled_width / pipe_config->pipe_src_w; |
2330 | Serge | 140 | if (height & 1) |
141 | height++; |
||
142 | y = (adjusted_mode->vdisplay - height + 1) / 2; |
||
143 | x = 0; |
||
144 | width = adjusted_mode->hdisplay; |
||
145 | } else { |
||
146 | x = y = 0; |
||
147 | width = adjusted_mode->hdisplay; |
||
148 | height = adjusted_mode->vdisplay; |
||
149 | } |
||
150 | } |
||
151 | break; |
||
152 | |||
153 | case DRM_MODE_SCALE_FULLSCREEN: |
||
154 | x = y = 0; |
||
155 | width = adjusted_mode->hdisplay; |
||
156 | height = adjusted_mode->vdisplay; |
||
157 | break; |
||
4104 | Serge | 158 | |
159 | default: |
||
160 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
||
161 | return; |
||
2330 | Serge | 162 | } |
163 | |||
164 | done: |
||
4104 | Serge | 165 | pipe_config->pch_pfit.pos = (x << 16) | y; |
166 | pipe_config->pch_pfit.size = (width << 16) | height; |
||
167 | pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; |
||
2330 | Serge | 168 | } |
169 | |||
4104 | Serge | 170 | static void |
171 | centre_horizontally(struct drm_display_mode *mode, |
||
172 | int width) |
||
173 | { |
||
174 | u32 border, sync_pos, blank_width, sync_width; |
||
175 | |||
176 | /* keep the hsync and hblank widths constant */ |
||
177 | sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; |
||
178 | blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; |
||
179 | sync_pos = (blank_width - sync_width + 1) / 2; |
||
180 | |||
181 | border = (mode->hdisplay - width + 1) / 2; |
||
182 | border += border & 1; /* make the border even */ |
||
183 | |||
184 | mode->crtc_hdisplay = width; |
||
185 | mode->crtc_hblank_start = width + border; |
||
186 | mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; |
||
187 | |||
188 | mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; |
||
189 | mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; |
||
190 | } |
||
191 | |||
192 | static void |
||
193 | centre_vertically(struct drm_display_mode *mode, |
||
194 | int height) |
||
195 | { |
||
196 | u32 border, sync_pos, blank_width, sync_width; |
||
197 | |||
198 | /* keep the vsync and vblank widths constant */ |
||
199 | sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; |
||
200 | blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; |
||
201 | sync_pos = (blank_width - sync_width + 1) / 2; |
||
202 | |||
203 | border = (mode->vdisplay - height + 1) / 2; |
||
204 | |||
205 | mode->crtc_vdisplay = height; |
||
206 | mode->crtc_vblank_start = height + border; |
||
207 | mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; |
||
208 | |||
209 | mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; |
||
210 | mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; |
||
211 | } |
||
212 | |||
213 | static inline u32 panel_fitter_scaling(u32 source, u32 target) |
||
214 | { |
||
215 | /* |
||
216 | * Floating point operation is not supported. So the FACTOR |
||
217 | * is defined, which can avoid the floating point computation |
||
218 | * when calculating the panel ratio. |
||
219 | */ |
||
220 | #define ACCURACY 12 |
||
221 | #define FACTOR (1 << ACCURACY) |
||
222 | u32 ratio = source * FACTOR / target; |
||
223 | return (FACTOR * ratio + FACTOR/2) / FACTOR; |
||
224 | } |
||
225 | |||
4560 | Serge | 226 | static void i965_scale_aspect(struct intel_crtc_config *pipe_config, |
227 | u32 *pfit_control) |
||
4104 | Serge | 228 | { |
4560 | Serge | 229 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
4104 | Serge | 230 | u32 scaled_width = adjusted_mode->hdisplay * |
4560 | Serge | 231 | pipe_config->pipe_src_h; |
232 | u32 scaled_height = pipe_config->pipe_src_w * |
||
4104 | Serge | 233 | adjusted_mode->vdisplay; |
234 | |||
235 | /* 965+ is easy, it does everything in hw */ |
||
236 | if (scaled_width > scaled_height) |
||
4560 | Serge | 237 | *pfit_control |= PFIT_ENABLE | |
4104 | Serge | 238 | PFIT_SCALING_PILLAR; |
239 | else if (scaled_width < scaled_height) |
||
4560 | Serge | 240 | *pfit_control |= PFIT_ENABLE | |
4104 | Serge | 241 | PFIT_SCALING_LETTER; |
4560 | Serge | 242 | else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w) |
243 | *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; |
||
244 | } |
||
245 | |||
246 | static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config, |
||
247 | u32 *pfit_control, u32 *pfit_pgm_ratios, |
||
248 | u32 *border) |
||
249 | { |
||
250 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
||
4104 | Serge | 251 | u32 scaled_width = adjusted_mode->hdisplay * |
4560 | Serge | 252 | pipe_config->pipe_src_h; |
253 | u32 scaled_height = pipe_config->pipe_src_w * |
||
4104 | Serge | 254 | adjusted_mode->vdisplay; |
4560 | Serge | 255 | u32 bits; |
256 | |||
4104 | Serge | 257 | /* |
258 | * For earlier chips we have to calculate the scaling |
||
259 | * ratio by hand and program it into the |
||
260 | * PFIT_PGM_RATIO register |
||
261 | */ |
||
262 | if (scaled_width > scaled_height) { /* pillar */ |
||
263 | centre_horizontally(adjusted_mode, |
||
264 | scaled_height / |
||
4560 | Serge | 265 | pipe_config->pipe_src_h); |
4104 | Serge | 266 | |
4560 | Serge | 267 | *border = LVDS_BORDER_ENABLE; |
268 | if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) { |
||
269 | bits = panel_fitter_scaling(pipe_config->pipe_src_h, |
||
270 | adjusted_mode->vdisplay); |
||
271 | |||
272 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
||
4104 | Serge | 273 | bits << PFIT_VERT_SCALE_SHIFT); |
4560 | Serge | 274 | *pfit_control |= (PFIT_ENABLE | |
4104 | Serge | 275 | VERT_INTERP_BILINEAR | |
276 | HORIZ_INTERP_BILINEAR); |
||
277 | } |
||
278 | } else if (scaled_width < scaled_height) { /* letter */ |
||
279 | centre_vertically(adjusted_mode, |
||
280 | scaled_width / |
||
4560 | Serge | 281 | pipe_config->pipe_src_w); |
4104 | Serge | 282 | |
4560 | Serge | 283 | *border = LVDS_BORDER_ENABLE; |
284 | if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) { |
||
285 | bits = panel_fitter_scaling(pipe_config->pipe_src_w, |
||
286 | adjusted_mode->hdisplay); |
||
287 | |||
288 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
||
4104 | Serge | 289 | bits << PFIT_VERT_SCALE_SHIFT); |
4560 | Serge | 290 | *pfit_control |= (PFIT_ENABLE | |
4104 | Serge | 291 | VERT_INTERP_BILINEAR | |
292 | HORIZ_INTERP_BILINEAR); |
||
293 | } |
||
294 | } else { |
||
295 | /* Aspects match, Let hw scale both directions */ |
||
4560 | Serge | 296 | *pfit_control |= (PFIT_ENABLE | |
4104 | Serge | 297 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | |
298 | VERT_INTERP_BILINEAR | |
||
299 | HORIZ_INTERP_BILINEAR); |
||
300 | } |
||
4560 | Serge | 301 | } |
302 | |||
303 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, |
||
304 | struct intel_crtc_config *pipe_config, |
||
305 | int fitting_mode) |
||
306 | { |
||
307 | struct drm_device *dev = intel_crtc->base.dev; |
||
308 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
||
309 | struct drm_display_mode *adjusted_mode; |
||
310 | |||
311 | adjusted_mode = &pipe_config->adjusted_mode; |
||
312 | |||
313 | /* Native modes don't need fitting */ |
||
314 | if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && |
||
315 | adjusted_mode->vdisplay == pipe_config->pipe_src_h) |
||
316 | goto out; |
||
317 | |||
318 | switch (fitting_mode) { |
||
319 | case DRM_MODE_SCALE_CENTER: |
||
320 | /* |
||
321 | * For centered modes, we have to calculate border widths & |
||
322 | * heights and modify the values programmed into the CRTC. |
||
323 | */ |
||
324 | centre_horizontally(adjusted_mode, pipe_config->pipe_src_w); |
||
325 | centre_vertically(adjusted_mode, pipe_config->pipe_src_h); |
||
326 | border = LVDS_BORDER_ENABLE; |
||
4104 | Serge | 327 | break; |
4560 | Serge | 328 | case DRM_MODE_SCALE_ASPECT: |
329 | /* Scale but preserve the aspect ratio */ |
||
330 | if (INTEL_INFO(dev)->gen >= 4) |
||
331 | i965_scale_aspect(pipe_config, &pfit_control); |
||
332 | else |
||
333 | i9xx_scale_aspect(pipe_config, &pfit_control, |
||
334 | &pfit_pgm_ratios, &border); |
||
335 | break; |
||
4104 | Serge | 336 | case DRM_MODE_SCALE_FULLSCREEN: |
337 | /* |
||
338 | * Full scaling, even if it changes the aspect ratio. |
||
339 | * Fortunately this is all done for us in hw. |
||
340 | */ |
||
4560 | Serge | 341 | if (pipe_config->pipe_src_h != adjusted_mode->vdisplay || |
342 | pipe_config->pipe_src_w != adjusted_mode->hdisplay) { |
||
4104 | Serge | 343 | pfit_control |= PFIT_ENABLE; |
344 | if (INTEL_INFO(dev)->gen >= 4) |
||
345 | pfit_control |= PFIT_SCALING_AUTO; |
||
346 | else |
||
347 | pfit_control |= (VERT_AUTO_SCALE | |
||
348 | VERT_INTERP_BILINEAR | |
||
349 | HORIZ_AUTO_SCALE | |
||
350 | HORIZ_INTERP_BILINEAR); |
||
351 | } |
||
352 | break; |
||
353 | default: |
||
354 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
||
355 | return; |
||
356 | } |
||
357 | |||
358 | /* 965+ wants fuzzy fitting */ |
||
359 | /* FIXME: handle multiple panels by failing gracefully */ |
||
360 | if (INTEL_INFO(dev)->gen >= 4) |
||
361 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | |
||
362 | PFIT_FILTER_FUZZY); |
||
363 | |||
364 | out: |
||
365 | if ((pfit_control & PFIT_ENABLE) == 0) { |
||
366 | pfit_control = 0; |
||
367 | pfit_pgm_ratios = 0; |
||
368 | } |
||
369 | |||
370 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ |
||
371 | if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) |
||
372 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
||
373 | |||
374 | pipe_config->gmch_pfit.control = pfit_control; |
||
375 | pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; |
||
376 | pipe_config->gmch_pfit.lvds_border_bits = border; |
||
377 | } |
||
378 | |||
5060 | serge | 379 | enum drm_connector_status |
380 | intel_panel_detect(struct drm_device *dev) |
||
381 | { |
||
382 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
383 | |||
384 | /* Assume that the BIOS does not lie through the OpRegion... */ |
||
385 | if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) { |
||
386 | return ioread32(dev_priv->opregion.lid_state) & 0x1 ? |
||
387 | connector_status_connected : |
||
388 | connector_status_disconnected; |
||
389 | } |
||
390 | |||
391 | switch (i915.panel_ignore_lid) { |
||
392 | case -2: |
||
393 | return connector_status_connected; |
||
394 | case -1: |
||
395 | return connector_status_disconnected; |
||
396 | default: |
||
397 | return connector_status_unknown; |
||
398 | } |
||
399 | } |
||
400 | |||
401 | /** |
||
402 | * scale - scale values from one range to another |
||
403 | * |
||
404 | * @source_val: value in range [@source_min..@source_max] |
||
405 | * |
||
406 | * Return @source_val in range [@source_min..@source_max] scaled to range |
||
407 | * [@target_min..@target_max]. |
||
408 | */ |
||
409 | static uint32_t scale(uint32_t source_val, |
||
410 | uint32_t source_min, uint32_t source_max, |
||
411 | uint32_t target_min, uint32_t target_max) |
||
412 | { |
||
413 | uint64_t target_val; |
||
414 | |||
415 | WARN_ON(source_min > source_max); |
||
416 | WARN_ON(target_min > target_max); |
||
417 | |||
418 | /* defensive */ |
||
419 | source_val = clamp(source_val, source_min, source_max); |
||
420 | |||
421 | /* avoid overflows */ |
||
5354 | serge | 422 | target_val = DIV_ROUND_CLOSEST_ULL((uint64_t)(source_val - source_min) * |
423 | (target_max - target_min), source_max - source_min); |
||
5060 | serge | 424 | target_val += target_min; |
425 | |||
426 | return target_val; |
||
427 | } |
||
428 | |||
429 | /* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */ |
||
430 | static inline u32 scale_user_to_hw(struct intel_connector *connector, |
||
431 | u32 user_level, u32 user_max) |
||
432 | { |
||
433 | struct intel_panel *panel = &connector->panel; |
||
434 | |||
435 | return scale(user_level, 0, user_max, |
||
436 | panel->backlight.min, panel->backlight.max); |
||
437 | } |
||
438 | |||
439 | /* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result |
||
440 | * to [hw_min..hw_max]. */ |
||
441 | static inline u32 clamp_user_to_hw(struct intel_connector *connector, |
||
442 | u32 user_level, u32 user_max) |
||
443 | { |
||
444 | struct intel_panel *panel = &connector->panel; |
||
445 | u32 hw_level; |
||
446 | |||
447 | hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max); |
||
448 | hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max); |
||
449 | |||
450 | return hw_level; |
||
451 | } |
||
452 | |||
453 | /* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */ |
||
454 | static inline u32 scale_hw_to_user(struct intel_connector *connector, |
||
455 | u32 hw_level, u32 user_max) |
||
456 | { |
||
457 | struct intel_panel *panel = &connector->panel; |
||
458 | |||
459 | return scale(hw_level, panel->backlight.min, panel->backlight.max, |
||
460 | 0, user_max); |
||
461 | } |
||
462 | |||
4560 | Serge | 463 | static u32 intel_panel_compute_brightness(struct intel_connector *connector, |
464 | u32 val) |
||
2330 | Serge | 465 | { |
4560 | Serge | 466 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 467 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 468 | struct intel_panel *panel = &connector->panel; |
2330 | Serge | 469 | |
4560 | Serge | 470 | WARN_ON(panel->backlight.max == 0); |
2330 | Serge | 471 | |
5060 | serge | 472 | if (i915.invert_brightness < 0) |
4560 | Serge | 473 | return val; |
2330 | Serge | 474 | |
5060 | serge | 475 | if (i915.invert_brightness > 0 || |
4560 | Serge | 476 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { |
477 | return panel->backlight.max - val; |
||
478 | } |
||
479 | |||
480 | return val; |
||
2330 | Serge | 481 | } |
482 | |||
4560 | Serge | 483 | static u32 bdw_get_backlight(struct intel_connector *connector) |
2330 | Serge | 484 | { |
4560 | Serge | 485 | struct drm_device *dev = connector->base.dev; |
3243 | Serge | 486 | struct drm_i915_private *dev_priv = dev->dev_private; |
2330 | Serge | 487 | |
4560 | Serge | 488 | return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; |
489 | } |
||
4104 | Serge | 490 | |
4560 | Serge | 491 | static u32 pch_get_backlight(struct intel_connector *connector) |
492 | { |
||
493 | struct drm_device *dev = connector->base.dev; |
||
494 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
2330 | Serge | 495 | |
4560 | Serge | 496 | return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
2330 | Serge | 497 | } |
498 | |||
4560 | Serge | 499 | static u32 i9xx_get_backlight(struct intel_connector *connector) |
2330 | Serge | 500 | { |
4560 | Serge | 501 | struct drm_device *dev = connector->base.dev; |
502 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
503 | struct intel_panel *panel = &connector->panel; |
||
504 | u32 val; |
||
2330 | Serge | 505 | |
4560 | Serge | 506 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
507 | if (INTEL_INFO(dev)->gen < 4) |
||
508 | val >>= 1; |
||
2330 | Serge | 509 | |
4560 | Serge | 510 | if (panel->backlight.combination_mode) { |
511 | u8 lbpc; |
||
2330 | Serge | 512 | |
4560 | Serge | 513 | pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); |
514 | val *= lbpc; |
||
2330 | Serge | 515 | } |
516 | |||
4560 | Serge | 517 | return val; |
2330 | Serge | 518 | } |
519 | |||
4560 | Serge | 520 | static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe) |
2330 | Serge | 521 | { |
522 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
3031 | serge | 523 | |
5354 | serge | 524 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
525 | return 0; |
||
526 | |||
4560 | Serge | 527 | return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; |
528 | } |
||
3031 | serge | 529 | |
4560 | Serge | 530 | static u32 vlv_get_backlight(struct intel_connector *connector) |
531 | { |
||
532 | struct drm_device *dev = connector->base.dev; |
||
533 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
3031 | serge | 534 | |
4560 | Serge | 535 | return _vlv_get_backlight(dev, pipe); |
3031 | serge | 536 | } |
537 | |||
4560 | Serge | 538 | static u32 intel_panel_get_backlight(struct intel_connector *connector) |
3031 | serge | 539 | { |
4560 | Serge | 540 | struct drm_device *dev = connector->base.dev; |
3031 | serge | 541 | struct drm_i915_private *dev_priv = dev->dev_private; |
5354 | serge | 542 | struct intel_panel *panel = &connector->panel; |
543 | u32 val = 0; |
||
2330 | Serge | 544 | |
5354 | serge | 545 | mutex_lock(&dev_priv->backlight_lock); |
4104 | Serge | 546 | |
5354 | serge | 547 | if (panel->backlight.enabled) { |
4560 | Serge | 548 | val = dev_priv->display.get_backlight(connector); |
549 | val = intel_panel_compute_brightness(connector, val); |
||
5354 | serge | 550 | } |
2330 | Serge | 551 | |
5354 | serge | 552 | mutex_unlock(&dev_priv->backlight_lock); |
2330 | Serge | 553 | |
554 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
||
555 | return val; |
||
556 | } |
||
557 | |||
4560 | Serge | 558 | static void bdw_set_backlight(struct intel_connector *connector, u32 level) |
2330 | Serge | 559 | { |
4560 | Serge | 560 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 561 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 562 | u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
563 | I915_WRITE(BLC_PWM_PCH_CTL2, val | level); |
||
2330 | Serge | 564 | } |
565 | |||
4560 | Serge | 566 | static void pch_set_backlight(struct intel_connector *connector, u32 level) |
2330 | Serge | 567 | { |
4560 | Serge | 568 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 569 | struct drm_i915_private *dev_priv = dev->dev_private; |
570 | u32 tmp; |
||
571 | |||
4560 | Serge | 572 | tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
573 | I915_WRITE(BLC_PWM_CPU_CTL, tmp | level); |
||
574 | } |
||
2330 | Serge | 575 | |
4560 | Serge | 576 | static void i9xx_set_backlight(struct intel_connector *connector, u32 level) |
577 | { |
||
578 | struct drm_device *dev = connector->base.dev; |
||
579 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
580 | struct intel_panel *panel = &connector->panel; |
||
581 | u32 tmp, mask; |
||
2330 | Serge | 582 | |
4560 | Serge | 583 | WARN_ON(panel->backlight.max == 0); |
584 | |||
585 | if (panel->backlight.combination_mode) { |
||
2330 | Serge | 586 | u8 lbpc; |
587 | |||
4560 | Serge | 588 | lbpc = level * 0xfe / panel->backlight.max + 1; |
2330 | Serge | 589 | level /= lbpc; |
590 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); |
||
591 | } |
||
592 | |||
4560 | Serge | 593 | if (IS_GEN4(dev)) { |
594 | mask = BACKLIGHT_DUTY_CYCLE_MASK; |
||
595 | } else { |
||
2330 | Serge | 596 | level <<= 1; |
4560 | Serge | 597 | mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; |
598 | } |
||
599 | |||
600 | tmp = I915_READ(BLC_PWM_CTL) & ~mask; |
||
2330 | Serge | 601 | I915_WRITE(BLC_PWM_CTL, tmp | level); |
602 | } |
||
603 | |||
4560 | Serge | 604 | static void vlv_set_backlight(struct intel_connector *connector, u32 level) |
605 | { |
||
606 | struct drm_device *dev = connector->base.dev; |
||
607 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
608 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
609 | u32 tmp; |
||
610 | |||
5354 | serge | 611 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
612 | return; |
||
613 | |||
4560 | Serge | 614 | tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
615 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); |
||
616 | } |
||
617 | |||
618 | static void |
||
619 | intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) |
||
620 | { |
||
621 | struct drm_device *dev = connector->base.dev; |
||
622 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
623 | |||
624 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); |
||
625 | |||
626 | level = intel_panel_compute_brightness(connector, level); |
||
627 | dev_priv->display.set_backlight(connector, level); |
||
628 | } |
||
629 | |||
5060 | serge | 630 | /* set backlight brightness to level in range [0..max], scaling wrt hw min */ |
631 | static void intel_panel_set_backlight(struct intel_connector *connector, |
||
632 | u32 user_level, u32 user_max) |
||
2342 | Serge | 633 | { |
4560 | Serge | 634 | struct drm_device *dev = connector->base.dev; |
2342 | Serge | 635 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 636 | struct intel_panel *panel = &connector->panel; |
5060 | serge | 637 | u32 hw_level; |
2342 | Serge | 638 | |
5354 | serge | 639 | if (!panel->backlight.present) |
4560 | Serge | 640 | return; |
3746 | Serge | 641 | |
5354 | serge | 642 | mutex_lock(&dev_priv->backlight_lock); |
4560 | Serge | 643 | |
644 | WARN_ON(panel->backlight.max == 0); |
||
645 | |||
5060 | serge | 646 | hw_level = scale_user_to_hw(connector, user_level, user_max); |
647 | panel->backlight.level = hw_level; |
||
4560 | Serge | 648 | |
5060 | serge | 649 | if (panel->backlight.enabled) |
650 | intel_panel_actually_set_backlight(connector, hw_level); |
||
4560 | Serge | 651 | |
5354 | serge | 652 | mutex_unlock(&dev_priv->backlight_lock); |
5060 | serge | 653 | } |
654 | |||
655 | /* set backlight brightness to level in range [0..max], assuming hw min is |
||
656 | * respected. |
||
657 | */ |
||
658 | void intel_panel_set_backlight_acpi(struct intel_connector *connector, |
||
659 | u32 user_level, u32 user_max) |
||
660 | { |
||
661 | struct drm_device *dev = connector->base.dev; |
||
662 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
663 | struct intel_panel *panel = &connector->panel; |
||
664 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
665 | u32 hw_level; |
||
666 | |||
5354 | serge | 667 | /* |
668 | * INVALID_PIPE may occur during driver init because |
||
669 | * connection_mutex isn't held across the entire backlight |
||
670 | * setup + modeset readout, and the BIOS can issue the |
||
671 | * requests at any time. |
||
672 | */ |
||
5060 | serge | 673 | if (!panel->backlight.present || pipe == INVALID_PIPE) |
674 | return; |
||
675 | |||
5354 | serge | 676 | mutex_lock(&dev_priv->backlight_lock); |
5060 | serge | 677 | |
678 | WARN_ON(panel->backlight.max == 0); |
||
679 | |||
680 | hw_level = clamp_user_to_hw(connector, user_level, user_max); |
||
681 | panel->backlight.level = hw_level; |
||
682 | |||
683 | |||
4560 | Serge | 684 | if (panel->backlight.enabled) |
5060 | serge | 685 | intel_panel_actually_set_backlight(connector, hw_level); |
4560 | Serge | 686 | |
5354 | serge | 687 | mutex_unlock(&dev_priv->backlight_lock); |
2342 | Serge | 688 | } |
689 | |||
4560 | Serge | 690 | static void pch_disable_backlight(struct intel_connector *connector) |
2330 | Serge | 691 | { |
4560 | Serge | 692 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 693 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 694 | u32 tmp; |
695 | |||
696 | intel_panel_actually_set_backlight(connector, 0); |
||
697 | |||
698 | tmp = I915_READ(BLC_PWM_CPU_CTL2); |
||
699 | I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); |
||
700 | |||
701 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
||
702 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); |
||
703 | } |
||
704 | |||
705 | static void i9xx_disable_backlight(struct intel_connector *connector) |
||
706 | { |
||
707 | intel_panel_actually_set_backlight(connector, 0); |
||
708 | } |
||
709 | |||
710 | static void i965_disable_backlight(struct intel_connector *connector) |
||
711 | { |
||
712 | struct drm_device *dev = connector->base.dev; |
||
713 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
714 | u32 tmp; |
||
715 | |||
716 | intel_panel_actually_set_backlight(connector, 0); |
||
717 | |||
718 | tmp = I915_READ(BLC_PWM_CTL2); |
||
719 | I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); |
||
720 | } |
||
721 | |||
722 | static void vlv_disable_backlight(struct intel_connector *connector) |
||
723 | { |
||
724 | struct drm_device *dev = connector->base.dev; |
||
725 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
726 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
727 | u32 tmp; |
||
728 | |||
5354 | serge | 729 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
730 | return; |
||
731 | |||
4560 | Serge | 732 | intel_panel_actually_set_backlight(connector, 0); |
733 | |||
734 | tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
||
735 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); |
||
736 | } |
||
737 | |||
738 | void intel_panel_disable_backlight(struct intel_connector *connector) |
||
739 | { |
||
740 | struct drm_device *dev = connector->base.dev; |
||
741 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
742 | struct intel_panel *panel = &connector->panel; |
||
2330 | Serge | 743 | |
5354 | serge | 744 | if (!panel->backlight.present) |
4560 | Serge | 745 | return; |
746 | |||
4293 | Serge | 747 | /* |
748 | * Do not disable backlight on the vgaswitcheroo path. When switching |
||
749 | * away from i915, the other client may depend on i915 to handle the |
||
750 | * backlight. This will leave the backlight on unnecessarily when |
||
751 | * another client is not activated. |
||
752 | */ |
||
753 | if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { |
||
754 | DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); |
||
755 | return; |
||
756 | } |
||
757 | |||
5354 | serge | 758 | mutex_lock(&dev_priv->backlight_lock); |
4104 | Serge | 759 | |
4560 | Serge | 760 | panel->backlight.enabled = false; |
761 | dev_priv->display.disable_backlight(connector); |
||
3031 | serge | 762 | |
5354 | serge | 763 | mutex_unlock(&dev_priv->backlight_lock); |
4560 | Serge | 764 | } |
3031 | serge | 765 | |
4560 | Serge | 766 | static void bdw_enable_backlight(struct intel_connector *connector) |
767 | { |
||
768 | struct drm_device *dev = connector->base.dev; |
||
769 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
770 | struct intel_panel *panel = &connector->panel; |
||
771 | u32 pch_ctl1, pch_ctl2; |
||
3031 | serge | 772 | |
4560 | Serge | 773 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
774 | if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { |
||
775 | DRM_DEBUG_KMS("pch backlight already enabled\n"); |
||
776 | pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; |
||
777 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
||
3031 | serge | 778 | } |
4104 | Serge | 779 | |
4560 | Serge | 780 | pch_ctl2 = panel->backlight.max << 16; |
781 | I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); |
||
782 | |||
783 | pch_ctl1 = 0; |
||
784 | if (panel->backlight.active_low_pwm) |
||
785 | pch_ctl1 |= BLM_PCH_POLARITY; |
||
786 | |||
5354 | serge | 787 | /* After LPT, override is the default. */ |
788 | if (HAS_PCH_LPT(dev_priv)) |
||
4560 | Serge | 789 | pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; |
790 | |||
791 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
||
792 | POSTING_READ(BLC_PWM_PCH_CTL1); |
||
793 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); |
||
794 | |||
795 | /* This won't stick until the above enable. */ |
||
796 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
2330 | Serge | 797 | } |
798 | |||
4560 | Serge | 799 | static void pch_enable_backlight(struct intel_connector *connector) |
2330 | Serge | 800 | { |
4560 | Serge | 801 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 802 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 803 | struct intel_panel *panel = &connector->panel; |
804 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
4104 | Serge | 805 | enum transcoder cpu_transcoder = |
806 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
||
4560 | Serge | 807 | u32 cpu_ctl2, pch_ctl1, pch_ctl2; |
2330 | Serge | 808 | |
4560 | Serge | 809 | cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); |
810 | if (cpu_ctl2 & BLM_PWM_ENABLE) { |
||
5097 | serge | 811 | DRM_DEBUG_KMS("cpu backlight already enabled\n"); |
4560 | Serge | 812 | cpu_ctl2 &= ~BLM_PWM_ENABLE; |
813 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); |
||
814 | } |
||
4104 | Serge | 815 | |
4560 | Serge | 816 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
817 | if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { |
||
818 | DRM_DEBUG_KMS("pch backlight already enabled\n"); |
||
819 | pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; |
||
820 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
||
3746 | Serge | 821 | } |
2330 | Serge | 822 | |
4560 | Serge | 823 | if (cpu_transcoder == TRANSCODER_EDP) |
824 | cpu_ctl2 = BLM_TRANSCODER_EDP; |
||
825 | else |
||
826 | cpu_ctl2 = BLM_PIPE(cpu_transcoder); |
||
827 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); |
||
828 | POSTING_READ(BLC_PWM_CPU_CTL2); |
||
829 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); |
||
3031 | serge | 830 | |
4560 | Serge | 831 | /* This won't stick until the above enable. */ |
832 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
3031 | serge | 833 | |
4560 | Serge | 834 | pch_ctl2 = panel->backlight.max << 16; |
835 | I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); |
||
3031 | serge | 836 | |
4560 | Serge | 837 | pch_ctl1 = 0; |
838 | if (panel->backlight.active_low_pwm) |
||
839 | pch_ctl1 |= BLM_PCH_POLARITY; |
||
3031 | serge | 840 | |
4560 | Serge | 841 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
842 | POSTING_READ(BLC_PWM_PCH_CTL1); |
||
843 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); |
||
844 | } |
||
3031 | serge | 845 | |
4560 | Serge | 846 | static void i9xx_enable_backlight(struct intel_connector *connector) |
847 | { |
||
848 | struct drm_device *dev = connector->base.dev; |
||
849 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
850 | struct intel_panel *panel = &connector->panel; |
||
851 | u32 ctl, freq; |
||
3031 | serge | 852 | |
4560 | Serge | 853 | ctl = I915_READ(BLC_PWM_CTL); |
854 | if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { |
||
5097 | serge | 855 | DRM_DEBUG_KMS("backlight already enabled\n"); |
4560 | Serge | 856 | I915_WRITE(BLC_PWM_CTL, 0); |
857 | } |
||
3031 | serge | 858 | |
4560 | Serge | 859 | freq = panel->backlight.max; |
860 | if (panel->backlight.combination_mode) |
||
861 | freq /= 0xff; |
||
3031 | serge | 862 | |
4560 | Serge | 863 | ctl = freq << 17; |
5060 | serge | 864 | if (panel->backlight.combination_mode) |
4560 | Serge | 865 | ctl |= BLM_LEGACY_MODE; |
866 | if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm) |
||
867 | ctl |= BLM_POLARITY_PNV; |
||
868 | |||
869 | I915_WRITE(BLC_PWM_CTL, ctl); |
||
870 | POSTING_READ(BLC_PWM_CTL); |
||
871 | |||
872 | /* XXX: combine this into above write? */ |
||
873 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
874 | } |
||
875 | |||
876 | static void i965_enable_backlight(struct intel_connector *connector) |
||
877 | { |
||
878 | struct drm_device *dev = connector->base.dev; |
||
879 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
880 | struct intel_panel *panel = &connector->panel; |
||
881 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
882 | u32 ctl, ctl2, freq; |
||
883 | |||
884 | ctl2 = I915_READ(BLC_PWM_CTL2); |
||
885 | if (ctl2 & BLM_PWM_ENABLE) { |
||
5097 | serge | 886 | DRM_DEBUG_KMS("backlight already enabled\n"); |
4560 | Serge | 887 | ctl2 &= ~BLM_PWM_ENABLE; |
888 | I915_WRITE(BLC_PWM_CTL2, ctl2); |
||
3031 | serge | 889 | } |
4560 | Serge | 890 | |
891 | freq = panel->backlight.max; |
||
892 | if (panel->backlight.combination_mode) |
||
893 | freq /= 0xff; |
||
894 | |||
895 | ctl = freq << 16; |
||
896 | I915_WRITE(BLC_PWM_CTL, ctl); |
||
897 | |||
898 | ctl2 = BLM_PIPE(pipe); |
||
899 | if (panel->backlight.combination_mode) |
||
900 | ctl2 |= BLM_COMBINATION_MODE; |
||
901 | if (panel->backlight.active_low_pwm) |
||
902 | ctl2 |= BLM_POLARITY_I965; |
||
903 | I915_WRITE(BLC_PWM_CTL2, ctl2); |
||
904 | POSTING_READ(BLC_PWM_CTL2); |
||
905 | I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); |
||
5060 | serge | 906 | |
907 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
4560 | Serge | 908 | } |
909 | |||
910 | static void vlv_enable_backlight(struct intel_connector *connector) |
||
911 | { |
||
912 | struct drm_device *dev = connector->base.dev; |
||
913 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
914 | struct intel_panel *panel = &connector->panel; |
||
915 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
916 | u32 ctl, ctl2; |
||
917 | |||
5354 | serge | 918 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
919 | return; |
||
920 | |||
4560 | Serge | 921 | ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
922 | if (ctl2 & BLM_PWM_ENABLE) { |
||
5097 | serge | 923 | DRM_DEBUG_KMS("backlight already enabled\n"); |
4560 | Serge | 924 | ctl2 &= ~BLM_PWM_ENABLE; |
925 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); |
||
3031 | serge | 926 | } |
927 | |||
4560 | Serge | 928 | ctl = panel->backlight.max << 16; |
929 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl); |
||
4104 | Serge | 930 | |
4560 | Serge | 931 | /* XXX: combine this into above write? */ |
932 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
933 | |||
934 | ctl2 = 0; |
||
935 | if (panel->backlight.active_low_pwm) |
||
936 | ctl2 |= BLM_POLARITY_I965; |
||
937 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); |
||
938 | POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); |
||
939 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); |
||
2330 | Serge | 940 | } |
941 | |||
4560 | Serge | 942 | void intel_panel_enable_backlight(struct intel_connector *connector) |
2330 | Serge | 943 | { |
4560 | Serge | 944 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 945 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 946 | struct intel_panel *panel = &connector->panel; |
947 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
2330 | Serge | 948 | |
5354 | serge | 949 | if (!panel->backlight.present) |
4560 | Serge | 950 | return; |
951 | |||
952 | DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); |
||
953 | |||
5354 | serge | 954 | mutex_lock(&dev_priv->backlight_lock); |
4560 | Serge | 955 | |
956 | WARN_ON(panel->backlight.max == 0); |
||
957 | |||
958 | if (panel->backlight.level == 0) { |
||
959 | panel->backlight.level = panel->backlight.max; |
||
960 | } |
||
961 | |||
962 | dev_priv->display.enable_backlight(connector); |
||
963 | panel->backlight.enabled = true; |
||
964 | |||
5354 | serge | 965 | mutex_unlock(&dev_priv->backlight_lock); |
2330 | Serge | 966 | } |
967 | |||
4560 | Serge | 968 | #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) |
969 | static int intel_backlight_device_update_status(struct backlight_device *bd) |
||
2330 | Serge | 970 | { |
4560 | Serge | 971 | struct intel_connector *connector = bl_get_data(bd); |
5354 | serge | 972 | struct intel_panel *panel = &connector->panel; |
4560 | Serge | 973 | struct drm_device *dev = connector->base.dev; |
974 | |||
5060 | serge | 975 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
4560 | Serge | 976 | DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", |
977 | bd->props.brightness, bd->props.max_brightness); |
||
978 | intel_panel_set_backlight(connector, bd->props.brightness, |
||
4104 | Serge | 979 | bd->props.max_brightness); |
5060 | serge | 980 | drm_modeset_unlock(&dev->mode_config.connection_mutex); |
2330 | Serge | 981 | return 0; |
982 | } |
||
983 | |||
4560 | Serge | 984 | static int intel_backlight_device_get_brightness(struct backlight_device *bd) |
2330 | Serge | 985 | { |
4560 | Serge | 986 | struct intel_connector *connector = bl_get_data(bd); |
987 | struct drm_device *dev = connector->base.dev; |
||
988 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
5060 | serge | 989 | u32 hw_level; |
4560 | Serge | 990 | int ret; |
991 | |||
992 | intel_runtime_pm_get(dev_priv); |
||
5060 | serge | 993 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
994 | |||
995 | hw_level = intel_panel_get_backlight(connector); |
||
996 | ret = scale_hw_to_user(connector, hw_level, bd->props.max_brightness); |
||
997 | |||
998 | drm_modeset_unlock(&dev->mode_config.connection_mutex); |
||
4560 | Serge | 999 | intel_runtime_pm_put(dev_priv); |
1000 | |||
1001 | return ret; |
||
2330 | Serge | 1002 | } |
1003 | |||
4560 | Serge | 1004 | static const struct backlight_ops intel_backlight_device_ops = { |
1005 | .update_status = intel_backlight_device_update_status, |
||
1006 | .get_brightness = intel_backlight_device_get_brightness, |
||
2330 | Serge | 1007 | }; |
1008 | |||
4560 | Serge | 1009 | static int intel_backlight_device_register(struct intel_connector *connector) |
2330 | Serge | 1010 | { |
4560 | Serge | 1011 | struct intel_panel *panel = &connector->panel; |
2330 | Serge | 1012 | struct backlight_properties props; |
1013 | |||
4560 | Serge | 1014 | if (WARN_ON(panel->backlight.device)) |
3746 | Serge | 1015 | return -ENODEV; |
1016 | |||
5354 | serge | 1017 | if (!panel->backlight.present) |
1018 | return 0; |
||
1019 | |||
5060 | serge | 1020 | WARN_ON(panel->backlight.max == 0); |
4560 | Serge | 1021 | |
3031 | serge | 1022 | memset(&props, 0, sizeof(props)); |
2330 | Serge | 1023 | props.type = BACKLIGHT_RAW; |
5060 | serge | 1024 | |
1025 | /* |
||
1026 | * Note: Everything should work even if the backlight device max |
||
1027 | * presented to the userspace is arbitrarily chosen. |
||
1028 | */ |
||
4560 | Serge | 1029 | props.max_brightness = panel->backlight.max; |
5060 | serge | 1030 | props.brightness = scale_hw_to_user(connector, |
1031 | panel->backlight.level, |
||
1032 | props.max_brightness); |
||
4104 | Serge | 1033 | |
5354 | serge | 1034 | if (panel->backlight.enabled) |
1035 | props.power = FB_BLANK_UNBLANK; |
||
1036 | else |
||
1037 | props.power = FB_BLANK_POWERDOWN; |
||
1038 | |||
4560 | Serge | 1039 | /* |
1040 | * Note: using the same name independent of the connector prevents |
||
1041 | * registration of multiple backlight devices in the driver. |
||
1042 | */ |
||
1043 | panel->backlight.device = |
||
2330 | Serge | 1044 | backlight_device_register("intel_backlight", |
4560 | Serge | 1045 | connector->base.kdev, |
1046 | connector, |
||
1047 | &intel_backlight_device_ops, &props); |
||
2330 | Serge | 1048 | |
4560 | Serge | 1049 | if (IS_ERR(panel->backlight.device)) { |
2330 | Serge | 1050 | DRM_ERROR("Failed to register backlight: %ld\n", |
4560 | Serge | 1051 | PTR_ERR(panel->backlight.device)); |
1052 | panel->backlight.device = NULL; |
||
2330 | Serge | 1053 | return -ENODEV; |
1054 | } |
||
5354 | serge | 1055 | |
1056 | DRM_DEBUG_KMS("Connector %s backlight sysfs interface registered\n", |
||
1057 | connector->base.name); |
||
1058 | |||
2330 | Serge | 1059 | return 0; |
1060 | } |
||
1061 | |||
4560 | Serge | 1062 | static void intel_backlight_device_unregister(struct intel_connector *connector) |
2330 | Serge | 1063 | { |
4560 | Serge | 1064 | struct intel_panel *panel = &connector->panel; |
1065 | |||
1066 | if (panel->backlight.device) { |
||
1067 | backlight_device_unregister(panel->backlight.device); |
||
1068 | panel->backlight.device = NULL; |
||
1069 | } |
||
1070 | } |
||
1071 | #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
||
1072 | static int intel_backlight_device_register(struct intel_connector *connector) |
||
1073 | { |
||
1074 | return 0; |
||
1075 | } |
||
1076 | static void intel_backlight_device_unregister(struct intel_connector *connector) |
||
1077 | { |
||
1078 | } |
||
1079 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
||
1080 | |||
1081 | /* |
||
1082 | * Note: The setup hooks can't assume pipe is set! |
||
1083 | * |
||
1084 | * XXX: Query mode clock or hardware clock and program PWM modulation frequency |
||
1085 | * appropriately when it's 0. Use VBT and/or sane defaults. |
||
1086 | */ |
||
5060 | serge | 1087 | static u32 get_backlight_min_vbt(struct intel_connector *connector) |
1088 | { |
||
1089 | struct drm_device *dev = connector->base.dev; |
||
1090 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1091 | struct intel_panel *panel = &connector->panel; |
||
5354 | serge | 1092 | int min; |
5060 | serge | 1093 | |
1094 | WARN_ON(panel->backlight.max == 0); |
||
1095 | |||
5354 | serge | 1096 | /* |
1097 | * XXX: If the vbt value is 255, it makes min equal to max, which leads |
||
1098 | * to problems. There are such machines out there. Either our |
||
1099 | * interpretation is wrong or the vbt has bogus data. Or both. Safeguard |
||
1100 | * against this by letting the minimum be at most (arbitrarily chosen) |
||
1101 | * 25% of the max. |
||
1102 | */ |
||
1103 | min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64); |
||
1104 | if (min != dev_priv->vbt.backlight.min_brightness) { |
||
1105 | DRM_DEBUG_KMS("clamping VBT min backlight %d/255 to %d/255\n", |
||
1106 | dev_priv->vbt.backlight.min_brightness, min); |
||
1107 | } |
||
1108 | |||
5060 | serge | 1109 | /* vbt value is a coefficient in range [0..255] */ |
5354 | serge | 1110 | return scale(min, 0, 255, 0, panel->backlight.max); |
5060 | serge | 1111 | } |
1112 | |||
5354 | serge | 1113 | static int bdw_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1114 | { |
1115 | struct drm_device *dev = connector->base.dev; |
||
2330 | Serge | 1116 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 1117 | struct intel_panel *panel = &connector->panel; |
1118 | u32 pch_ctl1, pch_ctl2, val; |
||
1119 | |||
1120 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
||
1121 | panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; |
||
1122 | |||
1123 | pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); |
||
1124 | panel->backlight.max = pch_ctl2 >> 16; |
||
1125 | if (!panel->backlight.max) |
||
1126 | return -ENODEV; |
||
1127 | |||
5060 | serge | 1128 | panel->backlight.min = get_backlight_min_vbt(connector); |
1129 | |||
4560 | Serge | 1130 | val = bdw_get_backlight(connector); |
1131 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1132 | |||
1133 | panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) && |
||
1134 | panel->backlight.level != 0; |
||
1135 | |||
1136 | return 0; |
||
1137 | } |
||
1138 | |||
5354 | serge | 1139 | static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1140 | { |
1141 | struct drm_device *dev = connector->base.dev; |
||
1142 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1143 | struct intel_panel *panel = &connector->panel; |
||
1144 | u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; |
||
1145 | |||
1146 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
||
1147 | panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; |
||
1148 | |||
1149 | pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); |
||
1150 | panel->backlight.max = pch_ctl2 >> 16; |
||
1151 | if (!panel->backlight.max) |
||
1152 | return -ENODEV; |
||
1153 | |||
5060 | serge | 1154 | panel->backlight.min = get_backlight_min_vbt(connector); |
1155 | |||
4560 | Serge | 1156 | val = pch_get_backlight(connector); |
1157 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1158 | |||
1159 | cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); |
||
1160 | panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && |
||
1161 | (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0; |
||
1162 | |||
1163 | return 0; |
||
1164 | } |
||
1165 | |||
5354 | serge | 1166 | static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1167 | { |
1168 | struct drm_device *dev = connector->base.dev; |
||
1169 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1170 | struct intel_panel *panel = &connector->panel; |
||
1171 | u32 ctl, val; |
||
1172 | |||
1173 | ctl = I915_READ(BLC_PWM_CTL); |
||
1174 | |||
5060 | serge | 1175 | if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev)) |
4560 | Serge | 1176 | panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; |
1177 | |||
1178 | if (IS_PINEVIEW(dev)) |
||
1179 | panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; |
||
1180 | |||
1181 | panel->backlight.max = ctl >> 17; |
||
1182 | if (panel->backlight.combination_mode) |
||
1183 | panel->backlight.max *= 0xff; |
||
1184 | |||
1185 | if (!panel->backlight.max) |
||
1186 | return -ENODEV; |
||
1187 | |||
5060 | serge | 1188 | panel->backlight.min = get_backlight_min_vbt(connector); |
1189 | |||
4560 | Serge | 1190 | val = i9xx_get_backlight(connector); |
1191 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1192 | |||
1193 | panel->backlight.enabled = panel->backlight.level != 0; |
||
1194 | |||
1195 | return 0; |
||
1196 | } |
||
1197 | |||
5354 | serge | 1198 | static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1199 | { |
1200 | struct drm_device *dev = connector->base.dev; |
||
1201 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1202 | struct intel_panel *panel = &connector->panel; |
||
1203 | u32 ctl, ctl2, val; |
||
1204 | |||
1205 | ctl2 = I915_READ(BLC_PWM_CTL2); |
||
1206 | panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; |
||
1207 | panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; |
||
1208 | |||
1209 | ctl = I915_READ(BLC_PWM_CTL); |
||
1210 | panel->backlight.max = ctl >> 16; |
||
1211 | if (panel->backlight.combination_mode) |
||
1212 | panel->backlight.max *= 0xff; |
||
1213 | |||
1214 | if (!panel->backlight.max) |
||
1215 | return -ENODEV; |
||
1216 | |||
5060 | serge | 1217 | panel->backlight.min = get_backlight_min_vbt(connector); |
1218 | |||
4560 | Serge | 1219 | val = i9xx_get_backlight(connector); |
1220 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1221 | |||
1222 | panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && |
||
1223 | panel->backlight.level != 0; |
||
1224 | |||
1225 | return 0; |
||
1226 | } |
||
1227 | |||
5354 | serge | 1228 | static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe) |
4560 | Serge | 1229 | { |
1230 | struct drm_device *dev = connector->base.dev; |
||
1231 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1232 | struct intel_panel *panel = &connector->panel; |
||
5354 | serge | 1233 | enum pipe p; |
4560 | Serge | 1234 | u32 ctl, ctl2, val; |
1235 | |||
5354 | serge | 1236 | for_each_pipe(dev_priv, p) { |
1237 | u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(p)); |
||
4560 | Serge | 1238 | |
1239 | /* Skip if the modulation freq is already set */ |
||
1240 | if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) |
||
1241 | continue; |
||
1242 | |||
1243 | cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; |
||
5354 | serge | 1244 | I915_WRITE(VLV_BLC_PWM_CTL(p), (0xf42 << 16) | |
4560 | Serge | 1245 | cur_val); |
3746 | Serge | 1246 | } |
4560 | Serge | 1247 | |
5354 | serge | 1248 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
1249 | return -ENODEV; |
||
1250 | |||
1251 | ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
||
4560 | Serge | 1252 | panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; |
1253 | |||
5354 | serge | 1254 | ctl = I915_READ(VLV_BLC_PWM_CTL(pipe)); |
4560 | Serge | 1255 | panel->backlight.max = ctl >> 16; |
1256 | if (!panel->backlight.max) |
||
1257 | return -ENODEV; |
||
1258 | |||
5060 | serge | 1259 | panel->backlight.min = get_backlight_min_vbt(connector); |
1260 | |||
5354 | serge | 1261 | val = _vlv_get_backlight(dev, pipe); |
4560 | Serge | 1262 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
1263 | |||
1264 | panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && |
||
1265 | panel->backlight.level != 0; |
||
1266 | |||
1267 | return 0; |
||
2330 | Serge | 1268 | } |
4560 | Serge | 1269 | |
5354 | serge | 1270 | int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) |
2330 | Serge | 1271 | { |
4560 | Serge | 1272 | struct drm_device *dev = connector->dev; |
1273 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1274 | struct intel_connector *intel_connector = to_intel_connector(connector); |
||
1275 | struct intel_panel *panel = &intel_connector->panel; |
||
1276 | int ret; |
||
1277 | |||
5060 | serge | 1278 | if (!dev_priv->vbt.backlight.present) { |
1279 | if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { |
||
1280 | DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n"); |
||
1281 | } else { |
||
1282 | DRM_DEBUG_KMS("no backlight present per VBT\n"); |
||
1283 | return 0; |
||
1284 | } |
||
1285 | } |
||
1286 | |||
4560 | Serge | 1287 | /* set level and max in panel struct */ |
5354 | serge | 1288 | mutex_lock(&dev_priv->backlight_lock); |
1289 | ret = dev_priv->display.setup_backlight(intel_connector, pipe); |
||
1290 | mutex_unlock(&dev_priv->backlight_lock); |
||
4560 | Serge | 1291 | |
1292 | if (ret) { |
||
1293 | DRM_DEBUG_KMS("failed to setup backlight for connector %s\n", |
||
5060 | serge | 1294 | connector->name); |
4560 | Serge | 1295 | return ret; |
1296 | } |
||
1297 | |||
1298 | panel->backlight.present = true; |
||
1299 | |||
5354 | serge | 1300 | DRM_DEBUG_KMS("Connector %s backlight initialized, %s, brightness %u/%u\n", |
1301 | connector->name, |
||
4560 | Serge | 1302 | panel->backlight.enabled ? "enabled" : "disabled", |
5354 | serge | 1303 | panel->backlight.level, panel->backlight.max); |
4560 | Serge | 1304 | |
2330 | Serge | 1305 | return 0; |
1306 | } |
||
1307 | |||
4560 | Serge | 1308 | void intel_panel_destroy_backlight(struct drm_connector *connector) |
2330 | Serge | 1309 | { |
4560 | Serge | 1310 | struct intel_connector *intel_connector = to_intel_connector(connector); |
1311 | struct intel_panel *panel = &intel_connector->panel; |
||
1312 | |||
1313 | panel->backlight.present = false; |
||
2330 | Serge | 1314 | } |
3243 | Serge | 1315 | |
4560 | Serge | 1316 | /* Set up chip specific backlight functions */ |
1317 | void intel_panel_init_backlight_funcs(struct drm_device *dev) |
||
1318 | { |
||
1319 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1320 | |||
5354 | serge | 1321 | if (IS_BROADWELL(dev) || (INTEL_INFO(dev)->gen >= 9)) { |
4560 | Serge | 1322 | dev_priv->display.setup_backlight = bdw_setup_backlight; |
1323 | dev_priv->display.enable_backlight = bdw_enable_backlight; |
||
1324 | dev_priv->display.disable_backlight = pch_disable_backlight; |
||
1325 | dev_priv->display.set_backlight = bdw_set_backlight; |
||
1326 | dev_priv->display.get_backlight = bdw_get_backlight; |
||
1327 | } else if (HAS_PCH_SPLIT(dev)) { |
||
1328 | dev_priv->display.setup_backlight = pch_setup_backlight; |
||
1329 | dev_priv->display.enable_backlight = pch_enable_backlight; |
||
1330 | dev_priv->display.disable_backlight = pch_disable_backlight; |
||
1331 | dev_priv->display.set_backlight = pch_set_backlight; |
||
1332 | dev_priv->display.get_backlight = pch_get_backlight; |
||
1333 | } else if (IS_VALLEYVIEW(dev)) { |
||
1334 | dev_priv->display.setup_backlight = vlv_setup_backlight; |
||
1335 | dev_priv->display.enable_backlight = vlv_enable_backlight; |
||
1336 | dev_priv->display.disable_backlight = vlv_disable_backlight; |
||
1337 | dev_priv->display.set_backlight = vlv_set_backlight; |
||
1338 | dev_priv->display.get_backlight = vlv_get_backlight; |
||
1339 | } else if (IS_GEN4(dev)) { |
||
1340 | dev_priv->display.setup_backlight = i965_setup_backlight; |
||
1341 | dev_priv->display.enable_backlight = i965_enable_backlight; |
||
1342 | dev_priv->display.disable_backlight = i965_disable_backlight; |
||
1343 | dev_priv->display.set_backlight = i9xx_set_backlight; |
||
1344 | dev_priv->display.get_backlight = i9xx_get_backlight; |
||
1345 | } else { |
||
1346 | dev_priv->display.setup_backlight = i9xx_setup_backlight; |
||
1347 | dev_priv->display.enable_backlight = i9xx_enable_backlight; |
||
1348 | dev_priv->display.disable_backlight = i9xx_disable_backlight; |
||
1349 | dev_priv->display.set_backlight = i9xx_set_backlight; |
||
1350 | dev_priv->display.get_backlight = i9xx_get_backlight; |
||
1351 | } |
||
1352 | } |
||
1353 | |||
3243 | Serge | 1354 | int intel_panel_init(struct intel_panel *panel, |
5060 | serge | 1355 | struct drm_display_mode *fixed_mode, |
1356 | struct drm_display_mode *downclock_mode) |
||
3243 | Serge | 1357 | { |
1358 | panel->fixed_mode = fixed_mode; |
||
5060 | serge | 1359 | panel->downclock_mode = downclock_mode; |
3243 | Serge | 1360 | |
1361 | return 0; |
||
1362 | } |
||
1363 | |||
1364 | void intel_panel_fini(struct intel_panel *panel) |
||
1365 | { |
||
1366 | struct intel_connector *intel_connector = |
||
1367 | container_of(panel, struct intel_connector, panel); |
||
1368 | |||
1369 | if (panel->fixed_mode) |
||
1370 | drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); |
||
4560 | Serge | 1371 | |
1372 | if (panel->downclock_mode) |
||
1373 | drm_mode_destroy(intel_connector->base.dev, |
||
1374 | panel->downclock_mode); |
||
3243 | Serge | 1375 | } |
5354 | serge | 1376 | |
1377 | void intel_backlight_register(struct drm_device *dev) |
||
1378 | { |
||
1379 | struct intel_connector *connector; |
||
1380 | |||
1381 | list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) |
||
1382 | intel_backlight_device_register(connector); |
||
1383 | } |
||
1384 | |||
1385 | void intel_backlight_unregister(struct drm_device *dev) |
||
1386 | { |
||
1387 | struct intel_connector *connector; |
||
1388 | |||
1389 | list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) |
||
1390 | intel_backlight_device_unregister(connector); |
||
1391 | }><>><>><>><>><>><>=><=>>>>><>><>><>>><>><>>><>><>><>>>> |