Rev 5354 | Rev 6088 | 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 | |||
6084 | serge | 33 | #include |
3031 | serge | 34 | #include |
6084 | serge | 35 | #include |
2330 | Serge | 36 | #include "intel_drv.h" |
37 | |||
6084 | serge | 38 | #define CRC_PMIC_PWM_PERIOD_NS 21333 |
39 | |||
2330 | Serge | 40 | void |
4104 | Serge | 41 | intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, |
2330 | Serge | 42 | struct drm_display_mode *adjusted_mode) |
43 | { |
||
4104 | Serge | 44 | drm_mode_copy(adjusted_mode, fixed_mode); |
2330 | Serge | 45 | |
4104 | Serge | 46 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
2330 | Serge | 47 | } |
48 | |||
5060 | serge | 49 | /** |
50 | * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID |
||
51 | * @dev: drm device |
||
52 | * @fixed_mode : panel native mode |
||
53 | * @connector: LVDS/eDP connector |
||
54 | * |
||
55 | * Return downclock_avail |
||
56 | * Find the reduced downclock for LVDS/eDP in EDID. |
||
57 | */ |
||
58 | struct drm_display_mode * |
||
59 | intel_find_panel_downclock(struct drm_device *dev, |
||
60 | struct drm_display_mode *fixed_mode, |
||
61 | struct drm_connector *connector) |
||
62 | { |
||
63 | struct drm_display_mode *scan, *tmp_mode; |
||
64 | int temp_downclock; |
||
65 | |||
66 | temp_downclock = fixed_mode->clock; |
||
67 | tmp_mode = NULL; |
||
68 | |||
69 | list_for_each_entry(scan, &connector->probed_modes, head) { |
||
70 | /* |
||
71 | * If one mode has the same resolution with the fixed_panel |
||
72 | * mode while they have the different refresh rate, it means |
||
73 | * that the reduced downclock is found. In such |
||
74 | * case we can set the different FPx0/1 to dynamically select |
||
75 | * between low and high frequency. |
||
76 | */ |
||
77 | if (scan->hdisplay == fixed_mode->hdisplay && |
||
78 | scan->hsync_start == fixed_mode->hsync_start && |
||
79 | scan->hsync_end == fixed_mode->hsync_end && |
||
80 | scan->htotal == fixed_mode->htotal && |
||
81 | scan->vdisplay == fixed_mode->vdisplay && |
||
82 | scan->vsync_start == fixed_mode->vsync_start && |
||
83 | scan->vsync_end == fixed_mode->vsync_end && |
||
84 | scan->vtotal == fixed_mode->vtotal) { |
||
85 | if (scan->clock < temp_downclock) { |
||
86 | /* |
||
87 | * The downclock is already found. But we |
||
88 | * expect to find the lower downclock. |
||
89 | */ |
||
90 | temp_downclock = scan->clock; |
||
91 | tmp_mode = scan; |
||
92 | } |
||
93 | } |
||
94 | } |
||
95 | |||
96 | if (temp_downclock < fixed_mode->clock) |
||
97 | return drm_mode_duplicate(dev, tmp_mode); |
||
98 | else |
||
99 | return NULL; |
||
100 | } |
||
101 | |||
2330 | Serge | 102 | /* adjusted_mode has been preset to be the panel's fixed mode */ |
103 | void |
||
4104 | Serge | 104 | intel_pch_panel_fitting(struct intel_crtc *intel_crtc, |
6084 | serge | 105 | struct intel_crtc_state *pipe_config, |
4104 | Serge | 106 | int fitting_mode) |
2330 | Serge | 107 | { |
6084 | serge | 108 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
109 | int x = 0, y = 0, width = 0, height = 0; |
||
2330 | Serge | 110 | |
111 | /* Native modes don't need fitting */ |
||
6084 | serge | 112 | if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w && |
113 | adjusted_mode->crtc_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; |
||
6084 | serge | 120 | x = (adjusted_mode->crtc_hdisplay - width + 1)/2; |
121 | y = (adjusted_mode->crtc_vdisplay - height + 1)/2; |
||
2330 | Serge | 122 | break; |
123 | |||
124 | case DRM_MODE_SCALE_ASPECT: |
||
125 | /* Scale but preserve the aspect ratio */ |
||
126 | { |
||
6084 | serge | 127 | u32 scaled_width = adjusted_mode->crtc_hdisplay |
4560 | Serge | 128 | * pipe_config->pipe_src_h; |
129 | u32 scaled_height = pipe_config->pipe_src_w |
||
6084 | serge | 130 | * adjusted_mode->crtc_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) |
6084 | serge | 134 | width++; |
135 | x = (adjusted_mode->crtc_hdisplay - width + 1) / 2; |
||
2330 | Serge | 136 | y = 0; |
6084 | serge | 137 | height = adjusted_mode->crtc_vdisplay; |
2330 | Serge | 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++; |
||
6084 | serge | 142 | y = (adjusted_mode->crtc_vdisplay - height + 1) / 2; |
2330 | Serge | 143 | x = 0; |
6084 | serge | 144 | width = adjusted_mode->crtc_hdisplay; |
2330 | Serge | 145 | } else { |
146 | x = y = 0; |
||
6084 | serge | 147 | width = adjusted_mode->crtc_hdisplay; |
148 | height = adjusted_mode->crtc_vdisplay; |
||
2330 | Serge | 149 | } |
150 | } |
||
151 | break; |
||
152 | |||
153 | case DRM_MODE_SCALE_FULLSCREEN: |
||
154 | x = y = 0; |
||
6084 | serge | 155 | width = adjusted_mode->crtc_hdisplay; |
156 | height = adjusted_mode->crtc_vdisplay; |
||
2330 | Serge | 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 |
6084 | serge | 171 | centre_horizontally(struct drm_display_mode *adjusted_mode, |
4104 | Serge | 172 | int width) |
173 | { |
||
174 | u32 border, sync_pos, blank_width, sync_width; |
||
175 | |||
176 | /* keep the hsync and hblank widths constant */ |
||
6084 | serge | 177 | sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; |
178 | blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start; |
||
4104 | Serge | 179 | sync_pos = (blank_width - sync_width + 1) / 2; |
180 | |||
6084 | serge | 181 | border = (adjusted_mode->crtc_hdisplay - width + 1) / 2; |
4104 | Serge | 182 | border += border & 1; /* make the border even */ |
183 | |||
6084 | serge | 184 | adjusted_mode->crtc_hdisplay = width; |
185 | adjusted_mode->crtc_hblank_start = width + border; |
||
186 | adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width; |
||
4104 | Serge | 187 | |
6084 | serge | 188 | adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos; |
189 | adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width; |
||
4104 | Serge | 190 | } |
191 | |||
192 | static void |
||
6084 | serge | 193 | centre_vertically(struct drm_display_mode *adjusted_mode, |
4104 | Serge | 194 | int height) |
195 | { |
||
196 | u32 border, sync_pos, blank_width, sync_width; |
||
197 | |||
198 | /* keep the vsync and vblank widths constant */ |
||
6084 | serge | 199 | sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; |
200 | blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start; |
||
4104 | Serge | 201 | sync_pos = (blank_width - sync_width + 1) / 2; |
202 | |||
6084 | serge | 203 | border = (adjusted_mode->crtc_vdisplay - height + 1) / 2; |
4104 | Serge | 204 | |
6084 | serge | 205 | adjusted_mode->crtc_vdisplay = height; |
206 | adjusted_mode->crtc_vblank_start = height + border; |
||
207 | adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width; |
||
4104 | Serge | 208 | |
6084 | serge | 209 | adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos; |
210 | adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width; |
||
4104 | Serge | 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 | |||
6084 | serge | 226 | static void i965_scale_aspect(struct intel_crtc_state *pipe_config, |
4560 | Serge | 227 | u32 *pfit_control) |
4104 | Serge | 228 | { |
6084 | serge | 229 | const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
230 | u32 scaled_width = adjusted_mode->crtc_hdisplay * |
||
4560 | Serge | 231 | pipe_config->pipe_src_h; |
232 | u32 scaled_height = pipe_config->pipe_src_w * |
||
6084 | serge | 233 | adjusted_mode->crtc_vdisplay; |
4104 | Serge | 234 | |
6084 | serge | 235 | /* 965+ is easy, it does everything in hw */ |
236 | if (scaled_width > scaled_height) |
||
4560 | Serge | 237 | *pfit_control |= PFIT_ENABLE | |
6084 | serge | 238 | PFIT_SCALING_PILLAR; |
239 | else if (scaled_width < scaled_height) |
||
4560 | Serge | 240 | *pfit_control |= PFIT_ENABLE | |
6084 | serge | 241 | PFIT_SCALING_LETTER; |
242 | else if (adjusted_mode->crtc_hdisplay != pipe_config->pipe_src_w) |
||
4560 | Serge | 243 | *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; |
244 | } |
||
245 | |||
6084 | serge | 246 | static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config, |
4560 | Serge | 247 | u32 *pfit_control, u32 *pfit_pgm_ratios, |
248 | u32 *border) |
||
249 | { |
||
6084 | serge | 250 | struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
251 | u32 scaled_width = adjusted_mode->crtc_hdisplay * |
||
4560 | Serge | 252 | pipe_config->pipe_src_h; |
253 | u32 scaled_height = pipe_config->pipe_src_w * |
||
6084 | serge | 254 | adjusted_mode->crtc_vdisplay; |
4560 | Serge | 255 | u32 bits; |
256 | |||
6084 | 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; |
6084 | serge | 268 | if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay) { |
4560 | Serge | 269 | bits = panel_fitter_scaling(pipe_config->pipe_src_h, |
6084 | serge | 270 | adjusted_mode->crtc_vdisplay); |
4560 | Serge | 271 | |
272 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
||
6084 | serge | 273 | bits << PFIT_VERT_SCALE_SHIFT); |
4560 | Serge | 274 | *pfit_control |= (PFIT_ENABLE | |
6084 | 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; |
6084 | serge | 284 | if (pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) { |
4560 | Serge | 285 | bits = panel_fitter_scaling(pipe_config->pipe_src_w, |
6084 | serge | 286 | adjusted_mode->crtc_hdisplay); |
4560 | Serge | 287 | |
288 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
||
6084 | serge | 289 | bits << PFIT_VERT_SCALE_SHIFT); |
4560 | Serge | 290 | *pfit_control |= (PFIT_ENABLE | |
6084 | 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 | |
6084 | 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, |
||
6084 | serge | 304 | struct intel_crtc_state *pipe_config, |
4560 | Serge | 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; |
||
6084 | serge | 309 | struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; |
4560 | Serge | 310 | |
311 | /* Native modes don't need fitting */ |
||
6084 | serge | 312 | if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w && |
313 | adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h) |
||
4560 | Serge | 314 | goto out; |
315 | |||
316 | switch (fitting_mode) { |
||
317 | case DRM_MODE_SCALE_CENTER: |
||
318 | /* |
||
319 | * For centered modes, we have to calculate border widths & |
||
320 | * heights and modify the values programmed into the CRTC. |
||
321 | */ |
||
322 | centre_horizontally(adjusted_mode, pipe_config->pipe_src_w); |
||
323 | centre_vertically(adjusted_mode, pipe_config->pipe_src_h); |
||
324 | border = LVDS_BORDER_ENABLE; |
||
4104 | Serge | 325 | break; |
4560 | Serge | 326 | case DRM_MODE_SCALE_ASPECT: |
327 | /* Scale but preserve the aspect ratio */ |
||
328 | if (INTEL_INFO(dev)->gen >= 4) |
||
329 | i965_scale_aspect(pipe_config, &pfit_control); |
||
330 | else |
||
331 | i9xx_scale_aspect(pipe_config, &pfit_control, |
||
332 | &pfit_pgm_ratios, &border); |
||
333 | break; |
||
4104 | Serge | 334 | case DRM_MODE_SCALE_FULLSCREEN: |
335 | /* |
||
336 | * Full scaling, even if it changes the aspect ratio. |
||
337 | * Fortunately this is all done for us in hw. |
||
338 | */ |
||
6084 | serge | 339 | if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay || |
340 | pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) { |
||
4104 | Serge | 341 | pfit_control |= PFIT_ENABLE; |
342 | if (INTEL_INFO(dev)->gen >= 4) |
||
343 | pfit_control |= PFIT_SCALING_AUTO; |
||
344 | else |
||
345 | pfit_control |= (VERT_AUTO_SCALE | |
||
346 | VERT_INTERP_BILINEAR | |
||
347 | HORIZ_AUTO_SCALE | |
||
348 | HORIZ_INTERP_BILINEAR); |
||
349 | } |
||
350 | break; |
||
351 | default: |
||
352 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
||
353 | return; |
||
354 | } |
||
355 | |||
356 | /* 965+ wants fuzzy fitting */ |
||
357 | /* FIXME: handle multiple panels by failing gracefully */ |
||
358 | if (INTEL_INFO(dev)->gen >= 4) |
||
359 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | |
||
360 | PFIT_FILTER_FUZZY); |
||
361 | |||
362 | out: |
||
363 | if ((pfit_control & PFIT_ENABLE) == 0) { |
||
364 | pfit_control = 0; |
||
365 | pfit_pgm_ratios = 0; |
||
366 | } |
||
367 | |||
368 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ |
||
369 | if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) |
||
370 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
||
371 | |||
372 | pipe_config->gmch_pfit.control = pfit_control; |
||
373 | pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; |
||
374 | pipe_config->gmch_pfit.lvds_border_bits = border; |
||
375 | } |
||
376 | |||
5060 | serge | 377 | enum drm_connector_status |
378 | intel_panel_detect(struct drm_device *dev) |
||
379 | { |
||
380 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
381 | |||
382 | /* Assume that the BIOS does not lie through the OpRegion... */ |
||
383 | if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) { |
||
6084 | serge | 384 | return *dev_priv->opregion.lid_state & 0x1 ? |
5060 | serge | 385 | connector_status_connected : |
386 | connector_status_disconnected; |
||
387 | } |
||
388 | |||
389 | switch (i915.panel_ignore_lid) { |
||
390 | case -2: |
||
391 | return connector_status_connected; |
||
392 | case -1: |
||
393 | return connector_status_disconnected; |
||
394 | default: |
||
395 | return connector_status_unknown; |
||
396 | } |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * scale - scale values from one range to another |
||
401 | * |
||
402 | * @source_val: value in range [@source_min..@source_max] |
||
403 | * |
||
404 | * Return @source_val in range [@source_min..@source_max] scaled to range |
||
405 | * [@target_min..@target_max]. |
||
406 | */ |
||
407 | static uint32_t scale(uint32_t source_val, |
||
408 | uint32_t source_min, uint32_t source_max, |
||
409 | uint32_t target_min, uint32_t target_max) |
||
410 | { |
||
411 | uint64_t target_val; |
||
412 | |||
413 | WARN_ON(source_min > source_max); |
||
414 | WARN_ON(target_min > target_max); |
||
415 | |||
416 | /* defensive */ |
||
417 | source_val = clamp(source_val, source_min, source_max); |
||
418 | |||
419 | /* avoid overflows */ |
||
5354 | serge | 420 | target_val = DIV_ROUND_CLOSEST_ULL((uint64_t)(source_val - source_min) * |
421 | (target_max - target_min), source_max - source_min); |
||
5060 | serge | 422 | target_val += target_min; |
423 | |||
424 | return target_val; |
||
425 | } |
||
426 | |||
427 | /* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */ |
||
428 | static inline u32 scale_user_to_hw(struct intel_connector *connector, |
||
429 | u32 user_level, u32 user_max) |
||
430 | { |
||
431 | struct intel_panel *panel = &connector->panel; |
||
432 | |||
433 | return scale(user_level, 0, user_max, |
||
434 | panel->backlight.min, panel->backlight.max); |
||
435 | } |
||
436 | |||
437 | /* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result |
||
438 | * to [hw_min..hw_max]. */ |
||
439 | static inline u32 clamp_user_to_hw(struct intel_connector *connector, |
||
440 | u32 user_level, u32 user_max) |
||
441 | { |
||
442 | struct intel_panel *panel = &connector->panel; |
||
443 | u32 hw_level; |
||
444 | |||
445 | hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max); |
||
446 | hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max); |
||
447 | |||
448 | return hw_level; |
||
449 | } |
||
450 | |||
451 | /* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */ |
||
452 | static inline u32 scale_hw_to_user(struct intel_connector *connector, |
||
453 | u32 hw_level, u32 user_max) |
||
454 | { |
||
455 | struct intel_panel *panel = &connector->panel; |
||
456 | |||
457 | return scale(hw_level, panel->backlight.min, panel->backlight.max, |
||
458 | 0, user_max); |
||
459 | } |
||
460 | |||
4560 | Serge | 461 | static u32 intel_panel_compute_brightness(struct intel_connector *connector, |
462 | u32 val) |
||
2330 | Serge | 463 | { |
4560 | Serge | 464 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 465 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 466 | struct intel_panel *panel = &connector->panel; |
2330 | Serge | 467 | |
4560 | Serge | 468 | WARN_ON(panel->backlight.max == 0); |
2330 | Serge | 469 | |
5060 | serge | 470 | if (i915.invert_brightness < 0) |
4560 | Serge | 471 | return val; |
2330 | Serge | 472 | |
5060 | serge | 473 | if (i915.invert_brightness > 0 || |
4560 | Serge | 474 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { |
475 | return panel->backlight.max - val; |
||
476 | } |
||
477 | |||
478 | return val; |
||
2330 | Serge | 479 | } |
480 | |||
6084 | serge | 481 | static u32 lpt_get_backlight(struct intel_connector *connector) |
2330 | Serge | 482 | { |
4560 | Serge | 483 | struct drm_device *dev = connector->base.dev; |
3243 | Serge | 484 | struct drm_i915_private *dev_priv = dev->dev_private; |
2330 | Serge | 485 | |
4560 | Serge | 486 | return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; |
487 | } |
||
4104 | Serge | 488 | |
4560 | Serge | 489 | static u32 pch_get_backlight(struct intel_connector *connector) |
490 | { |
||
491 | struct drm_device *dev = connector->base.dev; |
||
492 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
2330 | Serge | 493 | |
4560 | Serge | 494 | return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
2330 | Serge | 495 | } |
496 | |||
4560 | Serge | 497 | static u32 i9xx_get_backlight(struct intel_connector *connector) |
2330 | Serge | 498 | { |
4560 | Serge | 499 | struct drm_device *dev = connector->base.dev; |
500 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
501 | struct intel_panel *panel = &connector->panel; |
||
502 | u32 val; |
||
2330 | Serge | 503 | |
4560 | Serge | 504 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
505 | if (INTEL_INFO(dev)->gen < 4) |
||
506 | val >>= 1; |
||
2330 | Serge | 507 | |
4560 | Serge | 508 | if (panel->backlight.combination_mode) { |
509 | u8 lbpc; |
||
2330 | Serge | 510 | |
4560 | Serge | 511 | pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); |
512 | val *= lbpc; |
||
2330 | Serge | 513 | } |
514 | |||
4560 | Serge | 515 | return val; |
2330 | Serge | 516 | } |
517 | |||
4560 | Serge | 518 | static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe) |
2330 | Serge | 519 | { |
520 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
3031 | serge | 521 | |
5354 | serge | 522 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
523 | return 0; |
||
524 | |||
4560 | Serge | 525 | return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; |
526 | } |
||
3031 | serge | 527 | |
4560 | Serge | 528 | static u32 vlv_get_backlight(struct intel_connector *connector) |
529 | { |
||
530 | struct drm_device *dev = connector->base.dev; |
||
531 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
3031 | serge | 532 | |
4560 | Serge | 533 | return _vlv_get_backlight(dev, pipe); |
3031 | serge | 534 | } |
535 | |||
6084 | serge | 536 | static u32 bxt_get_backlight(struct intel_connector *connector) |
537 | { |
||
538 | struct drm_device *dev = connector->base.dev; |
||
539 | struct intel_panel *panel = &connector->panel; |
||
540 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
541 | |||
542 | return I915_READ(BXT_BLC_PWM_DUTY(panel->backlight.controller)); |
||
543 | } |
||
544 | |||
545 | static u32 pwm_get_backlight(struct intel_connector *connector) |
||
546 | { |
||
547 | struct intel_panel *panel = &connector->panel; |
||
548 | int duty_ns; |
||
549 | |||
550 | duty_ns = pwm_get_duty_cycle(panel->backlight.pwm); |
||
551 | return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS); |
||
552 | } |
||
553 | |||
4560 | Serge | 554 | static u32 intel_panel_get_backlight(struct intel_connector *connector) |
3031 | serge | 555 | { |
4560 | Serge | 556 | struct drm_device *dev = connector->base.dev; |
3031 | serge | 557 | struct drm_i915_private *dev_priv = dev->dev_private; |
5354 | serge | 558 | struct intel_panel *panel = &connector->panel; |
559 | u32 val = 0; |
||
2330 | Serge | 560 | |
5354 | serge | 561 | mutex_lock(&dev_priv->backlight_lock); |
4104 | Serge | 562 | |
5354 | serge | 563 | if (panel->backlight.enabled) { |
6084 | serge | 564 | val = panel->backlight.get(connector); |
565 | val = intel_panel_compute_brightness(connector, val); |
||
5354 | serge | 566 | } |
2330 | Serge | 567 | |
5354 | serge | 568 | mutex_unlock(&dev_priv->backlight_lock); |
2330 | Serge | 569 | |
570 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
||
571 | return val; |
||
572 | } |
||
573 | |||
6084 | serge | 574 | static void lpt_set_backlight(struct intel_connector *connector, u32 level) |
2330 | Serge | 575 | { |
4560 | Serge | 576 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 577 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 578 | u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
579 | I915_WRITE(BLC_PWM_PCH_CTL2, val | level); |
||
2330 | Serge | 580 | } |
581 | |||
4560 | Serge | 582 | static void pch_set_backlight(struct intel_connector *connector, u32 level) |
2330 | Serge | 583 | { |
4560 | Serge | 584 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 585 | struct drm_i915_private *dev_priv = dev->dev_private; |
586 | u32 tmp; |
||
587 | |||
4560 | Serge | 588 | tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
589 | I915_WRITE(BLC_PWM_CPU_CTL, tmp | level); |
||
590 | } |
||
2330 | Serge | 591 | |
4560 | Serge | 592 | static void i9xx_set_backlight(struct intel_connector *connector, u32 level) |
593 | { |
||
594 | struct drm_device *dev = connector->base.dev; |
||
595 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
596 | struct intel_panel *panel = &connector->panel; |
||
597 | u32 tmp, mask; |
||
2330 | Serge | 598 | |
4560 | Serge | 599 | WARN_ON(panel->backlight.max == 0); |
600 | |||
601 | if (panel->backlight.combination_mode) { |
||
2330 | Serge | 602 | u8 lbpc; |
603 | |||
4560 | Serge | 604 | lbpc = level * 0xfe / panel->backlight.max + 1; |
2330 | Serge | 605 | level /= lbpc; |
606 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); |
||
607 | } |
||
608 | |||
4560 | Serge | 609 | if (IS_GEN4(dev)) { |
610 | mask = BACKLIGHT_DUTY_CYCLE_MASK; |
||
611 | } else { |
||
2330 | Serge | 612 | level <<= 1; |
4560 | Serge | 613 | mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; |
614 | } |
||
615 | |||
616 | tmp = I915_READ(BLC_PWM_CTL) & ~mask; |
||
2330 | Serge | 617 | I915_WRITE(BLC_PWM_CTL, tmp | level); |
618 | } |
||
619 | |||
4560 | Serge | 620 | static void vlv_set_backlight(struct intel_connector *connector, u32 level) |
621 | { |
||
622 | struct drm_device *dev = connector->base.dev; |
||
623 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
624 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
625 | u32 tmp; |
||
626 | |||
5354 | serge | 627 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
628 | return; |
||
629 | |||
4560 | Serge | 630 | tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
631 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); |
||
632 | } |
||
633 | |||
6084 | serge | 634 | static void bxt_set_backlight(struct intel_connector *connector, u32 level) |
4560 | Serge | 635 | { |
636 | struct drm_device *dev = connector->base.dev; |
||
637 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
6084 | serge | 638 | struct intel_panel *panel = &connector->panel; |
4560 | Serge | 639 | |
6084 | serge | 640 | I915_WRITE(BXT_BLC_PWM_DUTY(panel->backlight.controller), level); |
641 | } |
||
642 | |||
643 | static void pwm_set_backlight(struct intel_connector *connector, u32 level) |
||
644 | { |
||
645 | struct intel_panel *panel = &connector->panel; |
||
646 | int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100); |
||
647 | |||
648 | pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS); |
||
649 | } |
||
650 | |||
651 | static void |
||
652 | intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) |
||
653 | { |
||
654 | struct intel_panel *panel = &connector->panel; |
||
655 | |||
4560 | Serge | 656 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); |
657 | |||
658 | level = intel_panel_compute_brightness(connector, level); |
||
6084 | serge | 659 | panel->backlight.set(connector, level); |
4560 | Serge | 660 | } |
661 | |||
5060 | serge | 662 | /* set backlight brightness to level in range [0..max], scaling wrt hw min */ |
663 | static void intel_panel_set_backlight(struct intel_connector *connector, |
||
664 | u32 user_level, u32 user_max) |
||
2342 | Serge | 665 | { |
4560 | Serge | 666 | struct drm_device *dev = connector->base.dev; |
2342 | Serge | 667 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 668 | struct intel_panel *panel = &connector->panel; |
5060 | serge | 669 | u32 hw_level; |
2342 | Serge | 670 | |
5354 | serge | 671 | if (!panel->backlight.present) |
4560 | Serge | 672 | return; |
3746 | Serge | 673 | |
5354 | serge | 674 | mutex_lock(&dev_priv->backlight_lock); |
4560 | Serge | 675 | |
676 | WARN_ON(panel->backlight.max == 0); |
||
677 | |||
5060 | serge | 678 | hw_level = scale_user_to_hw(connector, user_level, user_max); |
679 | panel->backlight.level = hw_level; |
||
4560 | Serge | 680 | |
5060 | serge | 681 | if (panel->backlight.enabled) |
682 | intel_panel_actually_set_backlight(connector, hw_level); |
||
4560 | Serge | 683 | |
5354 | serge | 684 | mutex_unlock(&dev_priv->backlight_lock); |
5060 | serge | 685 | } |
686 | |||
687 | /* set backlight brightness to level in range [0..max], assuming hw min is |
||
688 | * respected. |
||
689 | */ |
||
690 | void intel_panel_set_backlight_acpi(struct intel_connector *connector, |
||
691 | u32 user_level, u32 user_max) |
||
692 | { |
||
693 | struct drm_device *dev = connector->base.dev; |
||
694 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
695 | struct intel_panel *panel = &connector->panel; |
||
696 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
697 | u32 hw_level; |
||
698 | |||
5354 | serge | 699 | /* |
700 | * INVALID_PIPE may occur during driver init because |
||
701 | * connection_mutex isn't held across the entire backlight |
||
702 | * setup + modeset readout, and the BIOS can issue the |
||
703 | * requests at any time. |
||
704 | */ |
||
5060 | serge | 705 | if (!panel->backlight.present || pipe == INVALID_PIPE) |
706 | return; |
||
707 | |||
5354 | serge | 708 | mutex_lock(&dev_priv->backlight_lock); |
5060 | serge | 709 | |
710 | WARN_ON(panel->backlight.max == 0); |
||
711 | |||
712 | hw_level = clamp_user_to_hw(connector, user_level, user_max); |
||
713 | panel->backlight.level = hw_level; |
||
714 | |||
6084 | serge | 715 | mutex_unlock(&dev_priv->backlight_lock); |
716 | } |
||
5060 | serge | 717 | |
6084 | serge | 718 | static void lpt_disable_backlight(struct intel_connector *connector) |
719 | { |
||
720 | struct drm_device *dev = connector->base.dev; |
||
721 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
722 | u32 tmp; |
||
4560 | Serge | 723 | |
6084 | serge | 724 | intel_panel_actually_set_backlight(connector, 0); |
725 | |||
726 | /* |
||
727 | * Although we don't support or enable CPU PWM with LPT/SPT based |
||
728 | * systems, it may have been enabled prior to loading the |
||
729 | * driver. Disable to avoid warnings on LCPLL disable. |
||
730 | * |
||
731 | * This needs rework if we need to add support for CPU PWM on PCH split |
||
732 | * platforms. |
||
733 | */ |
||
734 | tmp = I915_READ(BLC_PWM_CPU_CTL2); |
||
735 | if (tmp & BLM_PWM_ENABLE) { |
||
736 | DRM_DEBUG_KMS("cpu backlight was enabled, disabling\n"); |
||
737 | I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); |
||
738 | } |
||
739 | |||
740 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
||
741 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); |
||
2342 | Serge | 742 | } |
743 | |||
4560 | Serge | 744 | static void pch_disable_backlight(struct intel_connector *connector) |
2330 | Serge | 745 | { |
4560 | Serge | 746 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 747 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 748 | u32 tmp; |
749 | |||
750 | intel_panel_actually_set_backlight(connector, 0); |
||
751 | |||
752 | tmp = I915_READ(BLC_PWM_CPU_CTL2); |
||
753 | I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); |
||
754 | |||
755 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
||
756 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); |
||
757 | } |
||
758 | |||
759 | static void i9xx_disable_backlight(struct intel_connector *connector) |
||
760 | { |
||
761 | intel_panel_actually_set_backlight(connector, 0); |
||
762 | } |
||
763 | |||
764 | static void i965_disable_backlight(struct intel_connector *connector) |
||
765 | { |
||
766 | struct drm_device *dev = connector->base.dev; |
||
767 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
768 | u32 tmp; |
||
769 | |||
770 | intel_panel_actually_set_backlight(connector, 0); |
||
771 | |||
772 | tmp = I915_READ(BLC_PWM_CTL2); |
||
773 | I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); |
||
774 | } |
||
775 | |||
776 | static void vlv_disable_backlight(struct intel_connector *connector) |
||
777 | { |
||
778 | struct drm_device *dev = connector->base.dev; |
||
779 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
780 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
781 | u32 tmp; |
||
782 | |||
5354 | serge | 783 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
784 | return; |
||
785 | |||
4560 | Serge | 786 | intel_panel_actually_set_backlight(connector, 0); |
787 | |||
788 | tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
||
789 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); |
||
790 | } |
||
791 | |||
6084 | serge | 792 | static void bxt_disable_backlight(struct intel_connector *connector) |
793 | { |
||
794 | struct drm_device *dev = connector->base.dev; |
||
795 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
796 | struct intel_panel *panel = &connector->panel; |
||
797 | u32 tmp, val; |
||
798 | |||
799 | intel_panel_actually_set_backlight(connector, 0); |
||
800 | |||
801 | tmp = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); |
||
802 | I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), |
||
803 | tmp & ~BXT_BLC_PWM_ENABLE); |
||
804 | |||
805 | if (panel->backlight.controller == 1) { |
||
806 | val = I915_READ(UTIL_PIN_CTL); |
||
807 | val &= ~UTIL_PIN_ENABLE; |
||
808 | I915_WRITE(UTIL_PIN_CTL, val); |
||
809 | } |
||
810 | } |
||
811 | |||
812 | static void pwm_disable_backlight(struct intel_connector *connector) |
||
813 | { |
||
814 | struct intel_panel *panel = &connector->panel; |
||
815 | |||
816 | /* Disable the backlight */ |
||
817 | pwm_config(panel->backlight.pwm, 0, CRC_PMIC_PWM_PERIOD_NS); |
||
818 | usleep_range(2000, 3000); |
||
819 | pwm_disable(panel->backlight.pwm); |
||
820 | } |
||
821 | |||
4560 | Serge | 822 | void intel_panel_disable_backlight(struct intel_connector *connector) |
823 | { |
||
824 | struct drm_device *dev = connector->base.dev; |
||
825 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
826 | struct intel_panel *panel = &connector->panel; |
||
2330 | Serge | 827 | |
5354 | serge | 828 | if (!panel->backlight.present) |
4560 | Serge | 829 | return; |
830 | |||
4293 | Serge | 831 | /* |
6084 | serge | 832 | * Do not disable backlight on the vga_switcheroo path. When switching |
4293 | Serge | 833 | * away from i915, the other client may depend on i915 to handle the |
834 | * backlight. This will leave the backlight on unnecessarily when |
||
835 | * another client is not activated. |
||
836 | */ |
||
837 | if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { |
||
838 | DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); |
||
839 | return; |
||
840 | } |
||
841 | |||
5354 | serge | 842 | mutex_lock(&dev_priv->backlight_lock); |
4104 | Serge | 843 | |
6084 | serge | 844 | panel->backlight.enabled = false; |
845 | panel->backlight.disable(connector); |
||
3031 | serge | 846 | |
5354 | serge | 847 | mutex_unlock(&dev_priv->backlight_lock); |
4560 | Serge | 848 | } |
3031 | serge | 849 | |
6084 | serge | 850 | static void lpt_enable_backlight(struct intel_connector *connector) |
4560 | Serge | 851 | { |
852 | struct drm_device *dev = connector->base.dev; |
||
853 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
854 | struct intel_panel *panel = &connector->panel; |
||
855 | u32 pch_ctl1, pch_ctl2; |
||
3031 | serge | 856 | |
4560 | Serge | 857 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
858 | if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { |
||
859 | DRM_DEBUG_KMS("pch backlight already enabled\n"); |
||
860 | pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; |
||
861 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
||
3031 | serge | 862 | } |
4104 | Serge | 863 | |
4560 | Serge | 864 | pch_ctl2 = panel->backlight.max << 16; |
865 | I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); |
||
866 | |||
867 | pch_ctl1 = 0; |
||
868 | if (panel->backlight.active_low_pwm) |
||
869 | pch_ctl1 |= BLM_PCH_POLARITY; |
||
870 | |||
5354 | serge | 871 | /* After LPT, override is the default. */ |
872 | if (HAS_PCH_LPT(dev_priv)) |
||
6084 | serge | 873 | pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; |
4560 | Serge | 874 | |
875 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
||
876 | POSTING_READ(BLC_PWM_PCH_CTL1); |
||
877 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); |
||
878 | |||
879 | /* This won't stick until the above enable. */ |
||
880 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
2330 | Serge | 881 | } |
882 | |||
4560 | Serge | 883 | static void pch_enable_backlight(struct intel_connector *connector) |
2330 | Serge | 884 | { |
4560 | Serge | 885 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 886 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 887 | struct intel_panel *panel = &connector->panel; |
888 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
4104 | Serge | 889 | enum transcoder cpu_transcoder = |
890 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
||
4560 | Serge | 891 | u32 cpu_ctl2, pch_ctl1, pch_ctl2; |
2330 | Serge | 892 | |
4560 | Serge | 893 | cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); |
894 | if (cpu_ctl2 & BLM_PWM_ENABLE) { |
||
5097 | serge | 895 | DRM_DEBUG_KMS("cpu backlight already enabled\n"); |
4560 | Serge | 896 | cpu_ctl2 &= ~BLM_PWM_ENABLE; |
897 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); |
||
898 | } |
||
4104 | Serge | 899 | |
4560 | Serge | 900 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
901 | if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { |
||
902 | DRM_DEBUG_KMS("pch backlight already enabled\n"); |
||
903 | pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; |
||
904 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
||
3746 | Serge | 905 | } |
2330 | Serge | 906 | |
4560 | Serge | 907 | if (cpu_transcoder == TRANSCODER_EDP) |
908 | cpu_ctl2 = BLM_TRANSCODER_EDP; |
||
909 | else |
||
910 | cpu_ctl2 = BLM_PIPE(cpu_transcoder); |
||
911 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); |
||
912 | POSTING_READ(BLC_PWM_CPU_CTL2); |
||
913 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); |
||
3031 | serge | 914 | |
4560 | Serge | 915 | /* This won't stick until the above enable. */ |
916 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
3031 | serge | 917 | |
4560 | Serge | 918 | pch_ctl2 = panel->backlight.max << 16; |
919 | I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); |
||
3031 | serge | 920 | |
4560 | Serge | 921 | pch_ctl1 = 0; |
922 | if (panel->backlight.active_low_pwm) |
||
923 | pch_ctl1 |= BLM_PCH_POLARITY; |
||
3031 | serge | 924 | |
4560 | Serge | 925 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
926 | POSTING_READ(BLC_PWM_PCH_CTL1); |
||
927 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); |
||
928 | } |
||
3031 | serge | 929 | |
4560 | Serge | 930 | static void i9xx_enable_backlight(struct intel_connector *connector) |
931 | { |
||
932 | struct drm_device *dev = connector->base.dev; |
||
933 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
934 | struct intel_panel *panel = &connector->panel; |
||
935 | u32 ctl, freq; |
||
3031 | serge | 936 | |
4560 | Serge | 937 | ctl = I915_READ(BLC_PWM_CTL); |
938 | if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { |
||
5097 | serge | 939 | DRM_DEBUG_KMS("backlight already enabled\n"); |
4560 | Serge | 940 | I915_WRITE(BLC_PWM_CTL, 0); |
941 | } |
||
3031 | serge | 942 | |
4560 | Serge | 943 | freq = panel->backlight.max; |
944 | if (panel->backlight.combination_mode) |
||
945 | freq /= 0xff; |
||
3031 | serge | 946 | |
4560 | Serge | 947 | ctl = freq << 17; |
5060 | serge | 948 | if (panel->backlight.combination_mode) |
4560 | Serge | 949 | ctl |= BLM_LEGACY_MODE; |
950 | if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm) |
||
951 | ctl |= BLM_POLARITY_PNV; |
||
952 | |||
953 | I915_WRITE(BLC_PWM_CTL, ctl); |
||
954 | POSTING_READ(BLC_PWM_CTL); |
||
955 | |||
956 | /* XXX: combine this into above write? */ |
||
957 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
6084 | serge | 958 | |
959 | /* |
||
960 | * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is |
||
961 | * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 |
||
962 | * that has backlight. |
||
963 | */ |
||
964 | if (IS_GEN2(dev)) |
||
965 | I915_WRITE(BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); |
||
4560 | Serge | 966 | } |
967 | |||
968 | static void i965_enable_backlight(struct intel_connector *connector) |
||
969 | { |
||
970 | struct drm_device *dev = connector->base.dev; |
||
971 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
972 | struct intel_panel *panel = &connector->panel; |
||
973 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
974 | u32 ctl, ctl2, freq; |
||
975 | |||
976 | ctl2 = I915_READ(BLC_PWM_CTL2); |
||
977 | if (ctl2 & BLM_PWM_ENABLE) { |
||
5097 | serge | 978 | DRM_DEBUG_KMS("backlight already enabled\n"); |
4560 | Serge | 979 | ctl2 &= ~BLM_PWM_ENABLE; |
980 | I915_WRITE(BLC_PWM_CTL2, ctl2); |
||
6084 | serge | 981 | } |
4560 | Serge | 982 | |
983 | freq = panel->backlight.max; |
||
984 | if (panel->backlight.combination_mode) |
||
985 | freq /= 0xff; |
||
986 | |||
987 | ctl = freq << 16; |
||
988 | I915_WRITE(BLC_PWM_CTL, ctl); |
||
989 | |||
990 | ctl2 = BLM_PIPE(pipe); |
||
991 | if (panel->backlight.combination_mode) |
||
992 | ctl2 |= BLM_COMBINATION_MODE; |
||
993 | if (panel->backlight.active_low_pwm) |
||
994 | ctl2 |= BLM_POLARITY_I965; |
||
995 | I915_WRITE(BLC_PWM_CTL2, ctl2); |
||
996 | POSTING_READ(BLC_PWM_CTL2); |
||
997 | I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); |
||
5060 | serge | 998 | |
999 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
4560 | Serge | 1000 | } |
1001 | |||
1002 | static void vlv_enable_backlight(struct intel_connector *connector) |
||
1003 | { |
||
1004 | struct drm_device *dev = connector->base.dev; |
||
1005 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1006 | struct intel_panel *panel = &connector->panel; |
||
1007 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
1008 | u32 ctl, ctl2; |
||
1009 | |||
5354 | serge | 1010 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
1011 | return; |
||
1012 | |||
4560 | Serge | 1013 | ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
1014 | if (ctl2 & BLM_PWM_ENABLE) { |
||
5097 | serge | 1015 | DRM_DEBUG_KMS("backlight already enabled\n"); |
4560 | Serge | 1016 | ctl2 &= ~BLM_PWM_ENABLE; |
1017 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); |
||
3031 | serge | 1018 | } |
1019 | |||
4560 | Serge | 1020 | ctl = panel->backlight.max << 16; |
1021 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl); |
||
4104 | Serge | 1022 | |
4560 | Serge | 1023 | /* XXX: combine this into above write? */ |
1024 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
1025 | |||
1026 | ctl2 = 0; |
||
1027 | if (panel->backlight.active_low_pwm) |
||
1028 | ctl2 |= BLM_POLARITY_I965; |
||
1029 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); |
||
1030 | POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); |
||
1031 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); |
||
2330 | Serge | 1032 | } |
1033 | |||
6084 | serge | 1034 | static void bxt_enable_backlight(struct intel_connector *connector) |
1035 | { |
||
1036 | struct drm_device *dev = connector->base.dev; |
||
1037 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1038 | struct intel_panel *panel = &connector->panel; |
||
1039 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
1040 | u32 pwm_ctl, val; |
||
1041 | |||
1042 | /* To use 2nd set of backlight registers, utility pin has to be |
||
1043 | * enabled with PWM mode. |
||
1044 | * The field should only be changed when the utility pin is disabled |
||
1045 | */ |
||
1046 | if (panel->backlight.controller == 1) { |
||
1047 | val = I915_READ(UTIL_PIN_CTL); |
||
1048 | if (val & UTIL_PIN_ENABLE) { |
||
1049 | DRM_DEBUG_KMS("util pin already enabled\n"); |
||
1050 | val &= ~UTIL_PIN_ENABLE; |
||
1051 | I915_WRITE(UTIL_PIN_CTL, val); |
||
1052 | } |
||
1053 | |||
1054 | val = 0; |
||
1055 | if (panel->backlight.util_pin_active_low) |
||
1056 | val |= UTIL_PIN_POLARITY; |
||
1057 | I915_WRITE(UTIL_PIN_CTL, val | UTIL_PIN_PIPE(pipe) | |
||
1058 | UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE); |
||
1059 | } |
||
1060 | |||
1061 | pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); |
||
1062 | if (pwm_ctl & BXT_BLC_PWM_ENABLE) { |
||
1063 | DRM_DEBUG_KMS("backlight already enabled\n"); |
||
1064 | pwm_ctl &= ~BXT_BLC_PWM_ENABLE; |
||
1065 | I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), |
||
1066 | pwm_ctl); |
||
1067 | } |
||
1068 | |||
1069 | I915_WRITE(BXT_BLC_PWM_FREQ(panel->backlight.controller), |
||
1070 | panel->backlight.max); |
||
1071 | |||
1072 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
1073 | |||
1074 | pwm_ctl = 0; |
||
1075 | if (panel->backlight.active_low_pwm) |
||
1076 | pwm_ctl |= BXT_BLC_PWM_POLARITY; |
||
1077 | |||
1078 | I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl); |
||
1079 | POSTING_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); |
||
1080 | I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), |
||
1081 | pwm_ctl | BXT_BLC_PWM_ENABLE); |
||
1082 | } |
||
1083 | |||
1084 | static void pwm_enable_backlight(struct intel_connector *connector) |
||
1085 | { |
||
1086 | struct intel_panel *panel = &connector->panel; |
||
1087 | |||
1088 | pwm_enable(panel->backlight.pwm); |
||
1089 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
||
1090 | } |
||
1091 | |||
4560 | Serge | 1092 | void intel_panel_enable_backlight(struct intel_connector *connector) |
2330 | Serge | 1093 | { |
4560 | Serge | 1094 | struct drm_device *dev = connector->base.dev; |
2330 | Serge | 1095 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 1096 | struct intel_panel *panel = &connector->panel; |
1097 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
||
2330 | Serge | 1098 | |
5354 | serge | 1099 | if (!panel->backlight.present) |
4560 | Serge | 1100 | return; |
1101 | |||
1102 | DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); |
||
1103 | |||
5354 | serge | 1104 | mutex_lock(&dev_priv->backlight_lock); |
4560 | Serge | 1105 | |
1106 | WARN_ON(panel->backlight.max == 0); |
||
1107 | |||
6084 | serge | 1108 | panel->backlight.enable(connector); |
4560 | Serge | 1109 | panel->backlight.enabled = true; |
1110 | |||
5354 | serge | 1111 | mutex_unlock(&dev_priv->backlight_lock); |
2330 | Serge | 1112 | } |
1113 | |||
4560 | Serge | 1114 | #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) |
1115 | static int intel_backlight_device_update_status(struct backlight_device *bd) |
||
2330 | Serge | 1116 | { |
4560 | Serge | 1117 | struct intel_connector *connector = bl_get_data(bd); |
5354 | serge | 1118 | struct intel_panel *panel = &connector->panel; |
4560 | Serge | 1119 | struct drm_device *dev = connector->base.dev; |
1120 | |||
5060 | serge | 1121 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
4560 | Serge | 1122 | DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", |
1123 | bd->props.brightness, bd->props.max_brightness); |
||
1124 | intel_panel_set_backlight(connector, bd->props.brightness, |
||
4104 | Serge | 1125 | bd->props.max_brightness); |
6084 | serge | 1126 | |
1127 | /* |
||
1128 | * Allow flipping bl_power as a sub-state of enabled. Sadly the |
||
1129 | * backlight class device does not make it easy to to differentiate |
||
1130 | * between callbacks for brightness and bl_power, so our backlight_power |
||
1131 | * callback needs to take this into account. |
||
1132 | */ |
||
1133 | if (panel->backlight.enabled) { |
||
1134 | if (panel->backlight.power) { |
||
1135 | bool enable = bd->props.power == FB_BLANK_UNBLANK && |
||
1136 | bd->props.brightness != 0; |
||
1137 | panel->backlight.power(connector, enable); |
||
1138 | } |
||
1139 | } else { |
||
1140 | bd->props.power = FB_BLANK_POWERDOWN; |
||
1141 | } |
||
1142 | |||
5060 | serge | 1143 | drm_modeset_unlock(&dev->mode_config.connection_mutex); |
2330 | Serge | 1144 | return 0; |
1145 | } |
||
1146 | |||
4560 | Serge | 1147 | static int intel_backlight_device_get_brightness(struct backlight_device *bd) |
2330 | Serge | 1148 | { |
4560 | Serge | 1149 | struct intel_connector *connector = bl_get_data(bd); |
1150 | struct drm_device *dev = connector->base.dev; |
||
1151 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
5060 | serge | 1152 | u32 hw_level; |
4560 | Serge | 1153 | int ret; |
1154 | |||
1155 | intel_runtime_pm_get(dev_priv); |
||
5060 | serge | 1156 | drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); |
1157 | |||
1158 | hw_level = intel_panel_get_backlight(connector); |
||
1159 | ret = scale_hw_to_user(connector, hw_level, bd->props.max_brightness); |
||
1160 | |||
1161 | drm_modeset_unlock(&dev->mode_config.connection_mutex); |
||
4560 | Serge | 1162 | intel_runtime_pm_put(dev_priv); |
1163 | |||
1164 | return ret; |
||
2330 | Serge | 1165 | } |
1166 | |||
4560 | Serge | 1167 | static const struct backlight_ops intel_backlight_device_ops = { |
1168 | .update_status = intel_backlight_device_update_status, |
||
1169 | .get_brightness = intel_backlight_device_get_brightness, |
||
2330 | Serge | 1170 | }; |
1171 | |||
4560 | Serge | 1172 | static int intel_backlight_device_register(struct intel_connector *connector) |
2330 | Serge | 1173 | { |
4560 | Serge | 1174 | struct intel_panel *panel = &connector->panel; |
2330 | Serge | 1175 | struct backlight_properties props; |
1176 | |||
4560 | Serge | 1177 | if (WARN_ON(panel->backlight.device)) |
3746 | Serge | 1178 | return -ENODEV; |
1179 | |||
5354 | serge | 1180 | if (!panel->backlight.present) |
1181 | return 0; |
||
1182 | |||
5060 | serge | 1183 | WARN_ON(panel->backlight.max == 0); |
4560 | Serge | 1184 | |
3031 | serge | 1185 | memset(&props, 0, sizeof(props)); |
2330 | Serge | 1186 | props.type = BACKLIGHT_RAW; |
5060 | serge | 1187 | |
1188 | /* |
||
1189 | * Note: Everything should work even if the backlight device max |
||
1190 | * presented to the userspace is arbitrarily chosen. |
||
1191 | */ |
||
4560 | Serge | 1192 | props.max_brightness = panel->backlight.max; |
5060 | serge | 1193 | props.brightness = scale_hw_to_user(connector, |
1194 | panel->backlight.level, |
||
1195 | props.max_brightness); |
||
4104 | Serge | 1196 | |
5354 | serge | 1197 | if (panel->backlight.enabled) |
1198 | props.power = FB_BLANK_UNBLANK; |
||
1199 | else |
||
1200 | props.power = FB_BLANK_POWERDOWN; |
||
1201 | |||
4560 | Serge | 1202 | /* |
1203 | * Note: using the same name independent of the connector prevents |
||
1204 | * registration of multiple backlight devices in the driver. |
||
1205 | */ |
||
1206 | panel->backlight.device = |
||
2330 | Serge | 1207 | backlight_device_register("intel_backlight", |
4560 | Serge | 1208 | connector->base.kdev, |
1209 | connector, |
||
1210 | &intel_backlight_device_ops, &props); |
||
2330 | Serge | 1211 | |
4560 | Serge | 1212 | if (IS_ERR(panel->backlight.device)) { |
2330 | Serge | 1213 | DRM_ERROR("Failed to register backlight: %ld\n", |
4560 | Serge | 1214 | PTR_ERR(panel->backlight.device)); |
1215 | panel->backlight.device = NULL; |
||
2330 | Serge | 1216 | return -ENODEV; |
1217 | } |
||
5354 | serge | 1218 | |
1219 | DRM_DEBUG_KMS("Connector %s backlight sysfs interface registered\n", |
||
1220 | connector->base.name); |
||
1221 | |||
2330 | Serge | 1222 | return 0; |
1223 | } |
||
1224 | |||
4560 | Serge | 1225 | static void intel_backlight_device_unregister(struct intel_connector *connector) |
2330 | Serge | 1226 | { |
4560 | Serge | 1227 | struct intel_panel *panel = &connector->panel; |
1228 | |||
1229 | if (panel->backlight.device) { |
||
1230 | backlight_device_unregister(panel->backlight.device); |
||
1231 | panel->backlight.device = NULL; |
||
1232 | } |
||
1233 | } |
||
1234 | #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
||
1235 | static int intel_backlight_device_register(struct intel_connector *connector) |
||
1236 | { |
||
1237 | return 0; |
||
1238 | } |
||
1239 | static void intel_backlight_device_unregister(struct intel_connector *connector) |
||
1240 | { |
||
1241 | } |
||
1242 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
||
1243 | |||
1244 | /* |
||
6084 | serge | 1245 | * SPT: This value represents the period of the PWM stream in clock periods |
1246 | * multiplied by 16 (default increment) or 128 (alternate increment selected in |
||
1247 | * SCHICKEN_1 bit 0). PWM clock is 24 MHz. |
||
1248 | */ |
||
1249 | static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) |
||
1250 | { |
||
1251 | struct drm_device *dev = connector->base.dev; |
||
1252 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1253 | u32 mul, clock; |
||
1254 | |||
1255 | if (I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY) |
||
1256 | mul = 128; |
||
1257 | else |
||
1258 | mul = 16; |
||
1259 | |||
1260 | clock = MHz(24); |
||
1261 | |||
1262 | return clock / (pwm_freq_hz * mul); |
||
1263 | } |
||
1264 | |||
1265 | /* |
||
1266 | * LPT: This value represents the period of the PWM stream in clock periods |
||
1267 | * multiplied by 128 (default increment) or 16 (alternate increment, selected in |
||
1268 | * LPT SOUTH_CHICKEN2 register bit 5). |
||
1269 | */ |
||
1270 | static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) |
||
1271 | { |
||
1272 | struct drm_device *dev = connector->base.dev; |
||
1273 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1274 | u32 mul, clock; |
||
1275 | |||
1276 | if (I915_READ(SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY) |
||
1277 | mul = 16; |
||
1278 | else |
||
1279 | mul = 128; |
||
1280 | |||
1281 | if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) |
||
1282 | clock = MHz(135); /* LPT:H */ |
||
1283 | else |
||
1284 | clock = MHz(24); /* LPT:LP */ |
||
1285 | |||
1286 | return clock / (pwm_freq_hz * mul); |
||
1287 | } |
||
1288 | |||
1289 | /* |
||
1290 | * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH |
||
1291 | * display raw clocks multiplied by 128. |
||
1292 | */ |
||
1293 | static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) |
||
1294 | { |
||
1295 | struct drm_device *dev = connector->base.dev; |
||
1296 | int clock = MHz(intel_pch_rawclk(dev)); |
||
1297 | |||
1298 | return clock / (pwm_freq_hz * 128); |
||
1299 | } |
||
1300 | |||
1301 | /* |
||
1302 | * Gen2: This field determines the number of time base events (display core |
||
1303 | * clock frequency/32) in total for a complete cycle of modulated backlight |
||
1304 | * control. |
||
4560 | Serge | 1305 | * |
6084 | serge | 1306 | * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock) |
1307 | * divided by 32. |
||
4560 | Serge | 1308 | */ |
6084 | serge | 1309 | static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) |
1310 | { |
||
1311 | struct drm_device *dev = connector->base.dev; |
||
1312 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1313 | int clock; |
||
1314 | |||
1315 | if (IS_PINEVIEW(dev)) |
||
1316 | clock = intel_hrawclk(dev); |
||
1317 | else |
||
1318 | clock = 1000 * dev_priv->display.get_display_clock_speed(dev); |
||
1319 | |||
1320 | return clock / (pwm_freq_hz * 32); |
||
1321 | } |
||
1322 | |||
1323 | /* |
||
1324 | * Gen4: This value represents the period of the PWM stream in display core |
||
1325 | * clocks multiplied by 128. |
||
1326 | */ |
||
1327 | static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) |
||
1328 | { |
||
1329 | struct drm_device *dev = connector->base.dev; |
||
1330 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1331 | int clock = 1000 * dev_priv->display.get_display_clock_speed(dev); |
||
1332 | |||
1333 | return clock / (pwm_freq_hz * 128); |
||
1334 | } |
||
1335 | |||
1336 | /* |
||
1337 | * VLV: This value represents the period of the PWM stream in display core |
||
1338 | * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks |
||
1339 | * multiplied by 16. CHV uses a 19.2MHz S0IX clock. |
||
1340 | */ |
||
1341 | static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) |
||
1342 | { |
||
1343 | struct drm_device *dev = connector->base.dev; |
||
1344 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1345 | int clock; |
||
1346 | |||
1347 | if ((I915_READ(CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) { |
||
1348 | if (IS_CHERRYVIEW(dev)) |
||
1349 | return KHz(19200) / (pwm_freq_hz * 16); |
||
1350 | else |
||
1351 | return MHz(25) / (pwm_freq_hz * 16); |
||
1352 | } else { |
||
1353 | clock = intel_hrawclk(dev); |
||
1354 | return MHz(clock) / (pwm_freq_hz * 128); |
||
1355 | } |
||
1356 | } |
||
1357 | |||
1358 | static u32 get_backlight_max_vbt(struct intel_connector *connector) |
||
1359 | { |
||
1360 | struct drm_device *dev = connector->base.dev; |
||
1361 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1362 | struct intel_panel *panel = &connector->panel; |
||
1363 | u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; |
||
1364 | u32 pwm; |
||
1365 | |||
1366 | if (!pwm_freq_hz) { |
||
1367 | DRM_DEBUG_KMS("backlight frequency not specified in VBT\n"); |
||
1368 | return 0; |
||
1369 | } |
||
1370 | |||
1371 | if (!panel->backlight.hz_to_pwm) { |
||
1372 | DRM_DEBUG_KMS("backlight frequency setting from VBT currently not supported on this platform\n"); |
||
1373 | return 0; |
||
1374 | } |
||
1375 | |||
1376 | pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz); |
||
1377 | if (!pwm) { |
||
1378 | DRM_DEBUG_KMS("backlight frequency conversion failed\n"); |
||
1379 | return 0; |
||
1380 | } |
||
1381 | |||
1382 | DRM_DEBUG_KMS("backlight frequency %u Hz from VBT\n", pwm_freq_hz); |
||
1383 | |||
1384 | return pwm; |
||
1385 | } |
||
1386 | |||
1387 | /* |
||
1388 | * Note: The setup hooks can't assume pipe is set! |
||
1389 | */ |
||
5060 | serge | 1390 | static u32 get_backlight_min_vbt(struct intel_connector *connector) |
1391 | { |
||
1392 | struct drm_device *dev = connector->base.dev; |
||
1393 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1394 | struct intel_panel *panel = &connector->panel; |
||
5354 | serge | 1395 | int min; |
5060 | serge | 1396 | |
1397 | WARN_ON(panel->backlight.max == 0); |
||
1398 | |||
5354 | serge | 1399 | /* |
1400 | * XXX: If the vbt value is 255, it makes min equal to max, which leads |
||
1401 | * to problems. There are such machines out there. Either our |
||
1402 | * interpretation is wrong or the vbt has bogus data. Or both. Safeguard |
||
1403 | * against this by letting the minimum be at most (arbitrarily chosen) |
||
1404 | * 25% of the max. |
||
1405 | */ |
||
1406 | min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64); |
||
1407 | if (min != dev_priv->vbt.backlight.min_brightness) { |
||
1408 | DRM_DEBUG_KMS("clamping VBT min backlight %d/255 to %d/255\n", |
||
1409 | dev_priv->vbt.backlight.min_brightness, min); |
||
1410 | } |
||
1411 | |||
5060 | serge | 1412 | /* vbt value is a coefficient in range [0..255] */ |
5354 | serge | 1413 | return scale(min, 0, 255, 0, panel->backlight.max); |
5060 | serge | 1414 | } |
1415 | |||
6084 | serge | 1416 | static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1417 | { |
1418 | struct drm_device *dev = connector->base.dev; |
||
2330 | Serge | 1419 | struct drm_i915_private *dev_priv = dev->dev_private; |
4560 | Serge | 1420 | struct intel_panel *panel = &connector->panel; |
1421 | u32 pch_ctl1, pch_ctl2, val; |
||
1422 | |||
1423 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
||
1424 | panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; |
||
1425 | |||
1426 | pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); |
||
1427 | panel->backlight.max = pch_ctl2 >> 16; |
||
6084 | serge | 1428 | |
4560 | Serge | 1429 | if (!panel->backlight.max) |
6084 | serge | 1430 | panel->backlight.max = get_backlight_max_vbt(connector); |
1431 | |||
1432 | if (!panel->backlight.max) |
||
4560 | Serge | 1433 | return -ENODEV; |
1434 | |||
5060 | serge | 1435 | panel->backlight.min = get_backlight_min_vbt(connector); |
1436 | |||
6084 | serge | 1437 | val = lpt_get_backlight(connector); |
4560 | Serge | 1438 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
1439 | |||
1440 | panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) && |
||
1441 | panel->backlight.level != 0; |
||
1442 | |||
1443 | return 0; |
||
1444 | } |
||
1445 | |||
5354 | serge | 1446 | static int pch_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1447 | { |
1448 | struct drm_device *dev = connector->base.dev; |
||
1449 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1450 | struct intel_panel *panel = &connector->panel; |
||
1451 | u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; |
||
1452 | |||
1453 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
||
1454 | panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; |
||
1455 | |||
1456 | pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); |
||
1457 | panel->backlight.max = pch_ctl2 >> 16; |
||
6084 | serge | 1458 | |
4560 | Serge | 1459 | if (!panel->backlight.max) |
6084 | serge | 1460 | panel->backlight.max = get_backlight_max_vbt(connector); |
1461 | |||
1462 | if (!panel->backlight.max) |
||
4560 | Serge | 1463 | return -ENODEV; |
1464 | |||
5060 | serge | 1465 | panel->backlight.min = get_backlight_min_vbt(connector); |
1466 | |||
4560 | Serge | 1467 | val = pch_get_backlight(connector); |
1468 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1469 | |||
1470 | cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); |
||
1471 | panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && |
||
1472 | (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0; |
||
1473 | |||
1474 | return 0; |
||
1475 | } |
||
1476 | |||
5354 | serge | 1477 | static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1478 | { |
1479 | struct drm_device *dev = connector->base.dev; |
||
1480 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1481 | struct intel_panel *panel = &connector->panel; |
||
1482 | u32 ctl, val; |
||
1483 | |||
1484 | ctl = I915_READ(BLC_PWM_CTL); |
||
1485 | |||
5060 | serge | 1486 | if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev)) |
4560 | Serge | 1487 | panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; |
1488 | |||
1489 | if (IS_PINEVIEW(dev)) |
||
1490 | panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; |
||
1491 | |||
1492 | panel->backlight.max = ctl >> 17; |
||
1493 | |||
6084 | serge | 1494 | if (!panel->backlight.max) { |
1495 | panel->backlight.max = get_backlight_max_vbt(connector); |
||
1496 | panel->backlight.max >>= 1; |
||
1497 | } |
||
1498 | |||
4560 | Serge | 1499 | if (!panel->backlight.max) |
1500 | return -ENODEV; |
||
1501 | |||
6084 | serge | 1502 | if (panel->backlight.combination_mode) |
1503 | panel->backlight.max *= 0xff; |
||
1504 | |||
5060 | serge | 1505 | panel->backlight.min = get_backlight_min_vbt(connector); |
1506 | |||
4560 | Serge | 1507 | val = i9xx_get_backlight(connector); |
1508 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1509 | |||
1510 | panel->backlight.enabled = panel->backlight.level != 0; |
||
1511 | |||
1512 | return 0; |
||
1513 | } |
||
1514 | |||
5354 | serge | 1515 | static int i965_setup_backlight(struct intel_connector *connector, enum pipe unused) |
4560 | Serge | 1516 | { |
1517 | struct drm_device *dev = connector->base.dev; |
||
1518 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1519 | struct intel_panel *panel = &connector->panel; |
||
1520 | u32 ctl, ctl2, val; |
||
1521 | |||
1522 | ctl2 = I915_READ(BLC_PWM_CTL2); |
||
1523 | panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; |
||
1524 | panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; |
||
1525 | |||
1526 | ctl = I915_READ(BLC_PWM_CTL); |
||
1527 | panel->backlight.max = ctl >> 16; |
||
1528 | |||
1529 | if (!panel->backlight.max) |
||
6084 | serge | 1530 | panel->backlight.max = get_backlight_max_vbt(connector); |
1531 | |||
1532 | if (!panel->backlight.max) |
||
4560 | Serge | 1533 | return -ENODEV; |
1534 | |||
6084 | serge | 1535 | if (panel->backlight.combination_mode) |
1536 | panel->backlight.max *= 0xff; |
||
1537 | |||
5060 | serge | 1538 | panel->backlight.min = get_backlight_min_vbt(connector); |
1539 | |||
4560 | Serge | 1540 | val = i9xx_get_backlight(connector); |
1541 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1542 | |||
1543 | panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && |
||
1544 | panel->backlight.level != 0; |
||
1545 | |||
1546 | return 0; |
||
1547 | } |
||
1548 | |||
5354 | serge | 1549 | static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe) |
4560 | Serge | 1550 | { |
1551 | struct drm_device *dev = connector->base.dev; |
||
1552 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1553 | struct intel_panel *panel = &connector->panel; |
||
1554 | u32 ctl, ctl2, val; |
||
1555 | |||
5354 | serge | 1556 | if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B)) |
1557 | return -ENODEV; |
||
1558 | |||
1559 | ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
||
4560 | Serge | 1560 | panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; |
1561 | |||
5354 | serge | 1562 | ctl = I915_READ(VLV_BLC_PWM_CTL(pipe)); |
4560 | Serge | 1563 | panel->backlight.max = ctl >> 16; |
6084 | serge | 1564 | |
4560 | Serge | 1565 | if (!panel->backlight.max) |
6084 | serge | 1566 | panel->backlight.max = get_backlight_max_vbt(connector); |
1567 | |||
1568 | if (!panel->backlight.max) |
||
4560 | Serge | 1569 | return -ENODEV; |
1570 | |||
5060 | serge | 1571 | panel->backlight.min = get_backlight_min_vbt(connector); |
1572 | |||
5354 | serge | 1573 | val = _vlv_get_backlight(dev, pipe); |
4560 | Serge | 1574 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
1575 | |||
1576 | panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && |
||
1577 | panel->backlight.level != 0; |
||
1578 | |||
1579 | return 0; |
||
2330 | Serge | 1580 | } |
4560 | Serge | 1581 | |
6084 | serge | 1582 | static int |
1583 | bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) |
||
1584 | { |
||
1585 | struct drm_device *dev = connector->base.dev; |
||
1586 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1587 | struct intel_panel *panel = &connector->panel; |
||
1588 | u32 pwm_ctl, val; |
||
1589 | |||
1590 | /* |
||
1591 | * For BXT hard coding the Backlight controller to 0. |
||
1592 | * TODO : Read the controller value from VBT and generalize |
||
1593 | */ |
||
1594 | panel->backlight.controller = 0; |
||
1595 | |||
1596 | pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller)); |
||
1597 | |||
1598 | /* Keeping the check if controller 1 is to be programmed. |
||
1599 | * This will come into affect once the VBT parsing |
||
1600 | * is fixed for controller selection, and controller 1 is used |
||
1601 | * for a prticular display configuration. |
||
1602 | */ |
||
1603 | if (panel->backlight.controller == 1) { |
||
1604 | val = I915_READ(UTIL_PIN_CTL); |
||
1605 | panel->backlight.util_pin_active_low = |
||
1606 | val & UTIL_PIN_POLARITY; |
||
1607 | } |
||
1608 | |||
1609 | panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; |
||
1610 | panel->backlight.max = |
||
1611 | I915_READ(BXT_BLC_PWM_FREQ(panel->backlight.controller)); |
||
1612 | |||
1613 | if (!panel->backlight.max) |
||
1614 | panel->backlight.max = get_backlight_max_vbt(connector); |
||
1615 | |||
1616 | if (!panel->backlight.max) |
||
1617 | return -ENODEV; |
||
1618 | |||
1619 | val = bxt_get_backlight(connector); |
||
1620 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
||
1621 | |||
1622 | panel->backlight.enabled = (pwm_ctl & BXT_BLC_PWM_ENABLE) && |
||
1623 | panel->backlight.level != 0; |
||
1624 | |||
1625 | return 0; |
||
1626 | } |
||
1627 | |||
1628 | static int pwm_setup_backlight(struct intel_connector *connector, |
||
1629 | enum pipe pipe) |
||
1630 | { |
||
1631 | struct drm_device *dev = connector->base.dev; |
||
1632 | struct intel_panel *panel = &connector->panel; |
||
1633 | int retval; |
||
1634 | |||
1635 | /* Get the PWM chip for backlight control */ |
||
1636 | panel->backlight.pwm = pwm_get(dev->dev, "pwm_backlight"); |
||
1637 | if (IS_ERR(panel->backlight.pwm)) { |
||
1638 | DRM_ERROR("Failed to own the pwm chip\n"); |
||
1639 | panel->backlight.pwm = NULL; |
||
1640 | return -ENODEV; |
||
1641 | } |
||
1642 | |||
1643 | retval = pwm_config(panel->backlight.pwm, CRC_PMIC_PWM_PERIOD_NS, |
||
1644 | CRC_PMIC_PWM_PERIOD_NS); |
||
1645 | if (retval < 0) { |
||
1646 | DRM_ERROR("Failed to configure the pwm chip\n"); |
||
1647 | pwm_put(panel->backlight.pwm); |
||
1648 | panel->backlight.pwm = NULL; |
||
1649 | return retval; |
||
1650 | } |
||
1651 | |||
1652 | panel->backlight.min = 0; /* 0% */ |
||
1653 | panel->backlight.max = 100; /* 100% */ |
||
1654 | panel->backlight.level = DIV_ROUND_UP( |
||
1655 | pwm_get_duty_cycle(panel->backlight.pwm) * 100, |
||
1656 | CRC_PMIC_PWM_PERIOD_NS); |
||
1657 | panel->backlight.enabled = panel->backlight.level != 0; |
||
1658 | |||
1659 | return 0; |
||
1660 | } |
||
1661 | |||
5354 | serge | 1662 | int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) |
2330 | Serge | 1663 | { |
4560 | Serge | 1664 | struct drm_device *dev = connector->dev; |
1665 | struct drm_i915_private *dev_priv = dev->dev_private; |
||
1666 | struct intel_connector *intel_connector = to_intel_connector(connector); |
||
1667 | struct intel_panel *panel = &intel_connector->panel; |
||
1668 | int ret; |
||
1669 | |||
5060 | serge | 1670 | if (!dev_priv->vbt.backlight.present) { |
1671 | if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { |
||
1672 | DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n"); |
||
1673 | } else { |
||
1674 | DRM_DEBUG_KMS("no backlight present per VBT\n"); |
||
6084 | serge | 1675 | return 0; |
1676 | } |
||
5060 | serge | 1677 | } |
1678 | |||
6084 | serge | 1679 | /* ensure intel_panel has been initialized first */ |
1680 | if (WARN_ON(!panel->backlight.setup)) |
||
1681 | return -ENODEV; |
||
1682 | |||
4560 | Serge | 1683 | /* set level and max in panel struct */ |
5354 | serge | 1684 | mutex_lock(&dev_priv->backlight_lock); |
6084 | serge | 1685 | ret = panel->backlight.setup(intel_connector, pipe); |
5354 | serge | 1686 | mutex_unlock(&dev_priv->backlight_lock); |
4560 | Serge | 1687 | |
1688 | if (ret) { |
||
1689 | DRM_DEBUG_KMS("failed to setup backlight for connector %s\n", |
||
5060 | serge | 1690 | connector->name); |
4560 | Serge | 1691 | return ret; |
1692 | } |
||
1693 | |||
1694 | panel->backlight.present = true; |
||
1695 | |||
5354 | serge | 1696 | DRM_DEBUG_KMS("Connector %s backlight initialized, %s, brightness %u/%u\n", |
1697 | connector->name, |
||
4560 | Serge | 1698 | panel->backlight.enabled ? "enabled" : "disabled", |
5354 | serge | 1699 | panel->backlight.level, panel->backlight.max); |
4560 | Serge | 1700 | |
2330 | Serge | 1701 | return 0; |
1702 | } |
||
1703 | |||
4560 | Serge | 1704 | void intel_panel_destroy_backlight(struct drm_connector *connector) |
2330 | Serge | 1705 | { |
4560 | Serge | 1706 | struct intel_connector *intel_connector = to_intel_connector(connector); |
1707 | struct intel_panel *panel = &intel_connector->panel; |
||
1708 | |||
6084 | serge | 1709 | /* dispose of the pwm */ |
1710 | if (panel->backlight.pwm) |
||
1711 | pwm_put(panel->backlight.pwm); |
||
1712 | |||
4560 | Serge | 1713 | panel->backlight.present = false; |
2330 | Serge | 1714 | } |
3243 | Serge | 1715 | |
4560 | Serge | 1716 | /* Set up chip specific backlight functions */ |
6084 | serge | 1717 | static void |
1718 | intel_panel_init_backlight_funcs(struct intel_panel *panel) |
||
4560 | Serge | 1719 | { |
6084 | serge | 1720 | struct intel_connector *intel_connector = |
1721 | container_of(panel, struct intel_connector, panel); |
||
1722 | struct drm_device *dev = intel_connector->base.dev; |
||
4560 | Serge | 1723 | struct drm_i915_private *dev_priv = dev->dev_private; |
1724 | |||
6084 | serge | 1725 | if (IS_BROXTON(dev)) { |
1726 | panel->backlight.setup = bxt_setup_backlight; |
||
1727 | panel->backlight.enable = bxt_enable_backlight; |
||
1728 | panel->backlight.disable = bxt_disable_backlight; |
||
1729 | panel->backlight.set = bxt_set_backlight; |
||
1730 | panel->backlight.get = bxt_get_backlight; |
||
1731 | } else if (HAS_PCH_LPT(dev) || HAS_PCH_SPT(dev)) { |
||
1732 | panel->backlight.setup = lpt_setup_backlight; |
||
1733 | panel->backlight.enable = lpt_enable_backlight; |
||
1734 | panel->backlight.disable = lpt_disable_backlight; |
||
1735 | panel->backlight.set = lpt_set_backlight; |
||
1736 | panel->backlight.get = lpt_get_backlight; |
||
1737 | if (HAS_PCH_LPT(dev)) |
||
1738 | panel->backlight.hz_to_pwm = lpt_hz_to_pwm; |
||
1739 | else |
||
1740 | panel->backlight.hz_to_pwm = spt_hz_to_pwm; |
||
4560 | Serge | 1741 | } else if (HAS_PCH_SPLIT(dev)) { |
6084 | serge | 1742 | panel->backlight.setup = pch_setup_backlight; |
1743 | panel->backlight.enable = pch_enable_backlight; |
||
1744 | panel->backlight.disable = pch_disable_backlight; |
||
1745 | panel->backlight.set = pch_set_backlight; |
||
1746 | panel->backlight.get = pch_get_backlight; |
||
1747 | panel->backlight.hz_to_pwm = pch_hz_to_pwm; |
||
4560 | Serge | 1748 | } else if (IS_VALLEYVIEW(dev)) { |
6084 | serge | 1749 | if (dev_priv->vbt.has_mipi) { |
1750 | panel->backlight.setup = pwm_setup_backlight; |
||
1751 | panel->backlight.enable = pwm_enable_backlight; |
||
1752 | panel->backlight.disable = pwm_disable_backlight; |
||
1753 | panel->backlight.set = pwm_set_backlight; |
||
1754 | panel->backlight.get = pwm_get_backlight; |
||
1755 | } else { |
||
1756 | panel->backlight.setup = vlv_setup_backlight; |
||
1757 | panel->backlight.enable = vlv_enable_backlight; |
||
1758 | panel->backlight.disable = vlv_disable_backlight; |
||
1759 | panel->backlight.set = vlv_set_backlight; |
||
1760 | panel->backlight.get = vlv_get_backlight; |
||
1761 | panel->backlight.hz_to_pwm = vlv_hz_to_pwm; |
||
1762 | } |
||
4560 | Serge | 1763 | } else if (IS_GEN4(dev)) { |
6084 | serge | 1764 | panel->backlight.setup = i965_setup_backlight; |
1765 | panel->backlight.enable = i965_enable_backlight; |
||
1766 | panel->backlight.disable = i965_disable_backlight; |
||
1767 | panel->backlight.set = i9xx_set_backlight; |
||
1768 | panel->backlight.get = i9xx_get_backlight; |
||
1769 | panel->backlight.hz_to_pwm = i965_hz_to_pwm; |
||
4560 | Serge | 1770 | } else { |
6084 | serge | 1771 | panel->backlight.setup = i9xx_setup_backlight; |
1772 | panel->backlight.enable = i9xx_enable_backlight; |
||
1773 | panel->backlight.disable = i9xx_disable_backlight; |
||
1774 | panel->backlight.set = i9xx_set_backlight; |
||
1775 | panel->backlight.get = i9xx_get_backlight; |
||
1776 | panel->backlight.hz_to_pwm = i9xx_hz_to_pwm; |
||
4560 | Serge | 1777 | } |
1778 | } |
||
1779 | |||
3243 | Serge | 1780 | int intel_panel_init(struct intel_panel *panel, |
5060 | serge | 1781 | struct drm_display_mode *fixed_mode, |
1782 | struct drm_display_mode *downclock_mode) |
||
3243 | Serge | 1783 | { |
6084 | serge | 1784 | intel_panel_init_backlight_funcs(panel); |
1785 | |||
3243 | Serge | 1786 | panel->fixed_mode = fixed_mode; |
5060 | serge | 1787 | panel->downclock_mode = downclock_mode; |
3243 | Serge | 1788 | |
1789 | return 0; |
||
1790 | } |
||
1791 | |||
1792 | void intel_panel_fini(struct intel_panel *panel) |
||
1793 | { |
||
1794 | struct intel_connector *intel_connector = |
||
1795 | container_of(panel, struct intel_connector, panel); |
||
1796 | |||
1797 | if (panel->fixed_mode) |
||
1798 | drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); |
||
4560 | Serge | 1799 | |
1800 | if (panel->downclock_mode) |
||
1801 | drm_mode_destroy(intel_connector->base.dev, |
||
1802 | panel->downclock_mode); |
||
3243 | Serge | 1803 | } |
5354 | serge | 1804 | |
1805 | void intel_backlight_register(struct drm_device *dev) |
||
1806 | { |
||
1807 | struct intel_connector *connector; |
||
1808 | |||
1809 | list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) |
||
1810 | intel_backlight_device_register(connector); |
||
1811 | } |
||
1812 | |||
1813 | void intel_backlight_unregister(struct drm_device *dev) |
||
1814 | { |
||
1815 | struct intel_connector *connector; |
||
1816 | |||
1817 | list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) |
||
1818 | intel_backlight_device_unregister(connector); |
||
1819 | }>><>><>><>><>><>=><=>>>>><>><>><>>><>><>>><>><>><>>>> |