Blame view

drivers/gpu/drm/i915/intel_panel.c 41.1 KB
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  /*
   * Copyright © 2006-2010 Intel Corporation
   * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   * to deal in the Software without restriction, including without limitation
   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   * and/or sell copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice (including the next
   * paragraph) shall be included in all copies or substantial portions of the
   * Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   * DEALINGS IN THE SOFTWARE.
   *
   * Authors:
   *	Eric Anholt <eric@anholt.net>
   *      Dave Airlie <airlied@linux.ie>
   *      Jesse Barnes <jesse.barnes@intel.com>
   *      Chris Wilson <chris@chris-wilson.co.uk>
   */
a70491cc6   Joe Perches   i915: Add and use...
30
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7bd90909b   Carsten Emde   drm/i915: panel: ...
31
  #include <linux/moduleparam.h>
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
32
33
34
  #include "intel_drv.h"
  
  void
4c6df4b4c   Ville Syrjälä   drm/i915: Fix pip...
35
  intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
36
37
  		       struct drm_display_mode *adjusted_mode)
  {
4c6df4b4c   Ville Syrjälä   drm/i915: Fix pip...
38
  	drm_mode_copy(adjusted_mode, fixed_mode);
a52690e44   Imre Deak   drm/i915: fix lvd...
39
40
  
  	drm_mode_set_crtcinfo(adjusted_mode, 0);
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
41
  }
525997e00   Jani Nikula   drm/i915: shuffle...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  /**
   * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID
   * @dev: drm device
   * @fixed_mode : panel native mode
   * @connector: LVDS/eDP connector
   *
   * Return downclock_avail
   * Find the reduced downclock for LVDS/eDP in EDID.
   */
  struct drm_display_mode *
  intel_find_panel_downclock(struct drm_device *dev,
  			struct drm_display_mode *fixed_mode,
  			struct drm_connector *connector)
  {
  	struct drm_display_mode *scan, *tmp_mode;
  	int temp_downclock;
  
  	temp_downclock = fixed_mode->clock;
  	tmp_mode = NULL;
  
  	list_for_each_entry(scan, &connector->probed_modes, head) {
  		/*
  		 * If one mode has the same resolution with the fixed_panel
  		 * mode while they have the different refresh rate, it means
  		 * that the reduced downclock is found. In such
  		 * case we can set the different FPx0/1 to dynamically select
  		 * between low and high frequency.
  		 */
  		if (scan->hdisplay == fixed_mode->hdisplay &&
  		    scan->hsync_start == fixed_mode->hsync_start &&
  		    scan->hsync_end == fixed_mode->hsync_end &&
  		    scan->htotal == fixed_mode->htotal &&
  		    scan->vdisplay == fixed_mode->vdisplay &&
  		    scan->vsync_start == fixed_mode->vsync_start &&
  		    scan->vsync_end == fixed_mode->vsync_end &&
  		    scan->vtotal == fixed_mode->vtotal) {
  			if (scan->clock < temp_downclock) {
  				/*
  				 * The downclock is already found. But we
  				 * expect to find the lower downclock.
  				 */
  				temp_downclock = scan->clock;
  				tmp_mode = scan;
  			}
  		}
  	}
  
  	if (temp_downclock < fixed_mode->clock)
  		return drm_mode_duplicate(dev, tmp_mode);
  	else
  		return NULL;
  }
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
94
95
  /* adjusted_mode has been preset to be the panel's fixed mode */
  void
b074cec8c   Jesse Barnes   drm/i915: move PC...
96
97
98
  intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
  			struct intel_crtc_config *pipe_config,
  			int fitting_mode)
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
99
  {
37327abdf   Ville Syrjälä   drm/i915: Add exp...
100
  	struct drm_display_mode *adjusted_mode;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
101
  	int x, y, width, height;
b074cec8c   Jesse Barnes   drm/i915: move PC...
102
  	adjusted_mode = &pipe_config->adjusted_mode;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
103
104
105
  	x = y = width = height = 0;
  
  	/* Native modes don't need fitting */
37327abdf   Ville Syrjälä   drm/i915: Add exp...
106
107
  	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
  	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
108
109
110
111
  		goto done;
  
  	switch (fitting_mode) {
  	case DRM_MODE_SCALE_CENTER:
37327abdf   Ville Syrjälä   drm/i915: Add exp...
112
113
  		width = pipe_config->pipe_src_w;
  		height = pipe_config->pipe_src_h;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
114
115
116
117
118
119
120
  		x = (adjusted_mode->hdisplay - width + 1)/2;
  		y = (adjusted_mode->vdisplay - height + 1)/2;
  		break;
  
  	case DRM_MODE_SCALE_ASPECT:
  		/* Scale but preserve the aspect ratio */
  		{
9084e7d27   Daniel Vetter   drm/i915: re-layo...
121
122
123
124
  			u32 scaled_width = adjusted_mode->hdisplay
  				* pipe_config->pipe_src_h;
  			u32 scaled_height = pipe_config->pipe_src_w
  				* adjusted_mode->vdisplay;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
125
  			if (scaled_width > scaled_height) { /* pillar */
37327abdf   Ville Syrjälä   drm/i915: Add exp...
126
  				width = scaled_height / pipe_config->pipe_src_h;
302983e90   Adam Jackson   drm/i915/pch: Fix...
127
  				if (width & 1)
0206e353a   Akshay Joshi   Drivers: i915: Fi...
128
  					width++;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
129
130
131
132
  				x = (adjusted_mode->hdisplay - width + 1) / 2;
  				y = 0;
  				height = adjusted_mode->vdisplay;
  			} else if (scaled_width < scaled_height) { /* letter */
37327abdf   Ville Syrjälä   drm/i915: Add exp...
133
  				height = scaled_width / pipe_config->pipe_src_w;
302983e90   Adam Jackson   drm/i915/pch: Fix...
134
135
  				if (height & 1)
  				    height++;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
136
137
138
139
140
141
142
143
144
145
  				y = (adjusted_mode->vdisplay - height + 1) / 2;
  				x = 0;
  				width = adjusted_mode->hdisplay;
  			} else {
  				x = y = 0;
  				width = adjusted_mode->hdisplay;
  				height = adjusted_mode->vdisplay;
  			}
  		}
  		break;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
146
147
148
149
150
  	case DRM_MODE_SCALE_FULLSCREEN:
  		x = y = 0;
  		width = adjusted_mode->hdisplay;
  		height = adjusted_mode->vdisplay;
  		break;
ab3e67f43   Jesse Barnes   drm/i915: warn ab...
151
152
153
154
155
  
  	default:
  		WARN(1, "bad panel fit mode: %d
  ", fitting_mode);
  		return;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
156
157
158
  	}
  
  done:
b074cec8c   Jesse Barnes   drm/i915: move PC...
159
160
  	pipe_config->pch_pfit.pos = (x << 16) | y;
  	pipe_config->pch_pfit.size = (width << 16) | height;
fd4daa9ce   Chris Wilson   drm/i915: Track p...
161
  	pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0;
1d8e1c75f   Chris Wilson   drm/i915: Enable ...
162
  }
a95735569   Chris Wilson   drm/i915: Refacto...
163

2dd24552c   Jesse Barnes   drm/i915: factor ...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  static void
  centre_horizontally(struct drm_display_mode *mode,
  		    int width)
  {
  	u32 border, sync_pos, blank_width, sync_width;
  
  	/* keep the hsync and hblank widths constant */
  	sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
  	blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
  	sync_pos = (blank_width - sync_width + 1) / 2;
  
  	border = (mode->hdisplay - width + 1) / 2;
  	border += border & 1; /* make the border even */
  
  	mode->crtc_hdisplay = width;
  	mode->crtc_hblank_start = width + border;
  	mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
  
  	mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
  	mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
  }
  
  static void
  centre_vertically(struct drm_display_mode *mode,
  		  int height)
  {
  	u32 border, sync_pos, blank_width, sync_width;
  
  	/* keep the vsync and vblank widths constant */
  	sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
  	blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
  	sync_pos = (blank_width - sync_width + 1) / 2;
  
  	border = (mode->vdisplay - height + 1) / 2;
  
  	mode->crtc_vdisplay = height;
  	mode->crtc_vblank_start = height + border;
  	mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
  
  	mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
  	mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
  }
  
  static inline u32 panel_fitter_scaling(u32 source, u32 target)
  {
  	/*
  	 * Floating point operation is not supported. So the FACTOR
  	 * is defined, which can avoid the floating point computation
  	 * when calculating the panel ratio.
  	 */
  #define ACCURACY 12
  #define FACTOR (1 << ACCURACY)
  	u32 ratio = source * FACTOR / target;
  	return (FACTOR * ratio + FACTOR/2) / FACTOR;
  }
9084e7d27   Daniel Vetter   drm/i915: re-layo...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
  			      u32 *pfit_control)
  {
  	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
  	u32 scaled_width = adjusted_mode->hdisplay *
  		pipe_config->pipe_src_h;
  	u32 scaled_height = pipe_config->pipe_src_w *
  		adjusted_mode->vdisplay;
  
  	/* 965+ is easy, it does everything in hw */
  	if (scaled_width > scaled_height)
  		*pfit_control |= PFIT_ENABLE |
  			PFIT_SCALING_PILLAR;
  	else if (scaled_width < scaled_height)
  		*pfit_control |= PFIT_ENABLE |
  			PFIT_SCALING_LETTER;
  	else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w)
  		*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
  }
  
  static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
  			      u32 *pfit_control, u32 *pfit_pgm_ratios,
  			      u32 *border)
  {
  	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
  	u32 scaled_width = adjusted_mode->hdisplay *
  		pipe_config->pipe_src_h;
  	u32 scaled_height = pipe_config->pipe_src_w *
  		adjusted_mode->vdisplay;
  	u32 bits;
  
  	/*
  	 * For earlier chips we have to calculate the scaling
  	 * ratio by hand and program it into the
  	 * PFIT_PGM_RATIO register
  	 */
  	if (scaled_width > scaled_height) { /* pillar */
  		centre_horizontally(adjusted_mode,
  				    scaled_height /
  				    pipe_config->pipe_src_h);
  
  		*border = LVDS_BORDER_ENABLE;
  		if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) {
  			bits = panel_fitter_scaling(pipe_config->pipe_src_h,
  						    adjusted_mode->vdisplay);
  
  			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
  					     bits << PFIT_VERT_SCALE_SHIFT);
  			*pfit_control |= (PFIT_ENABLE |
  					  VERT_INTERP_BILINEAR |
  					  HORIZ_INTERP_BILINEAR);
  		}
  	} else if (scaled_width < scaled_height) { /* letter */
  		centre_vertically(adjusted_mode,
  				  scaled_width /
  				  pipe_config->pipe_src_w);
  
  		*border = LVDS_BORDER_ENABLE;
  		if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
  			bits = panel_fitter_scaling(pipe_config->pipe_src_w,
  						    adjusted_mode->hdisplay);
  
  			*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
  					     bits << PFIT_VERT_SCALE_SHIFT);
  			*pfit_control |= (PFIT_ENABLE |
  					  VERT_INTERP_BILINEAR |
  					  HORIZ_INTERP_BILINEAR);
  		}
  	} else {
  		/* Aspects match, Let hw scale both directions */
  		*pfit_control |= (PFIT_ENABLE |
  				  VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
  				  VERT_INTERP_BILINEAR |
  				  HORIZ_INTERP_BILINEAR);
  	}
  }
2dd24552c   Jesse Barnes   drm/i915: factor ...
295
296
297
298
299
  void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
  			      struct intel_crtc_config *pipe_config,
  			      int fitting_mode)
  {
  	struct drm_device *dev = intel_crtc->base.dev;
2dd24552c   Jesse Barnes   drm/i915: factor ...
300
  	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
37327abdf   Ville Syrjälä   drm/i915: Add exp...
301
  	struct drm_display_mode *adjusted_mode;
2dd24552c   Jesse Barnes   drm/i915: factor ...
302

2dd24552c   Jesse Barnes   drm/i915: factor ...
303
304
305
  	adjusted_mode = &pipe_config->adjusted_mode;
  
  	/* Native modes don't need fitting */
37327abdf   Ville Syrjälä   drm/i915: Add exp...
306
307
  	if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
  	    adjusted_mode->vdisplay == pipe_config->pipe_src_h)
2dd24552c   Jesse Barnes   drm/i915: factor ...
308
309
310
311
312
313
314
315
  		goto out;
  
  	switch (fitting_mode) {
  	case DRM_MODE_SCALE_CENTER:
  		/*
  		 * For centered modes, we have to calculate border widths &
  		 * heights and modify the values programmed into the CRTC.
  		 */
37327abdf   Ville Syrjälä   drm/i915: Add exp...
316
317
  		centre_horizontally(adjusted_mode, pipe_config->pipe_src_w);
  		centre_vertically(adjusted_mode, pipe_config->pipe_src_h);
2dd24552c   Jesse Barnes   drm/i915: factor ...
318
319
320
321
  		border = LVDS_BORDER_ENABLE;
  		break;
  	case DRM_MODE_SCALE_ASPECT:
  		/* Scale but preserve the aspect ratio */
9084e7d27   Daniel Vetter   drm/i915: re-layo...
322
323
324
325
326
  		if (INTEL_INFO(dev)->gen >= 4)
  			i965_scale_aspect(pipe_config, &pfit_control);
  		else
  			i9xx_scale_aspect(pipe_config, &pfit_control,
  					  &pfit_pgm_ratios, &border);
2dd24552c   Jesse Barnes   drm/i915: factor ...
327
  		break;
2dd24552c   Jesse Barnes   drm/i915: factor ...
328
329
330
331
332
  	case DRM_MODE_SCALE_FULLSCREEN:
  		/*
  		 * Full scaling, even if it changes the aspect ratio.
  		 * Fortunately this is all done for us in hw.
  		 */
37327abdf   Ville Syrjälä   drm/i915: Add exp...
333
334
  		if (pipe_config->pipe_src_h != adjusted_mode->vdisplay ||
  		    pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
2dd24552c   Jesse Barnes   drm/i915: factor ...
335
336
337
338
339
340
341
342
343
344
  			pfit_control |= PFIT_ENABLE;
  			if (INTEL_INFO(dev)->gen >= 4)
  				pfit_control |= PFIT_SCALING_AUTO;
  			else
  				pfit_control |= (VERT_AUTO_SCALE |
  						 VERT_INTERP_BILINEAR |
  						 HORIZ_AUTO_SCALE |
  						 HORIZ_INTERP_BILINEAR);
  		}
  		break;
ab3e67f43   Jesse Barnes   drm/i915: warn ab...
345
346
347
348
  	default:
  		WARN(1, "bad panel fit mode: %d
  ", fitting_mode);
  		return;
2dd24552c   Jesse Barnes   drm/i915: factor ...
349
350
351
352
353
354
355
356
357
358
359
360
361
  	}
  
  	/* 965+ wants fuzzy fitting */
  	/* FIXME: handle multiple panels by failing gracefully */
  	if (INTEL_INFO(dev)->gen >= 4)
  		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
  				 PFIT_FILTER_FUZZY);
  
  out:
  	if ((pfit_control & PFIT_ENABLE) == 0) {
  		pfit_control = 0;
  		pfit_pgm_ratios = 0;
  	}
6b89cddee   Daniel Vetter   Revert "drm/i915:...
362
363
364
  	/* Make sure pre-965 set dither correctly for 18bpp panels. */
  	if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
  		pfit_control |= PANEL_8TO6_DITHER_ENABLE;
2deefda54   Daniel Vetter   drm/i915: rip out...
365
366
  	pipe_config->gmch_pfit.control = pfit_control;
  	pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
68fc87428   Daniel Vetter   drm/i915: move lv...
367
  	pipe_config->gmch_pfit.lvds_border_bits = border;
2dd24552c   Jesse Barnes   drm/i915: factor ...
368
  }
525997e00   Jani Nikula   drm/i915: shuffle...
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  enum drm_connector_status
  intel_panel_detect(struct drm_device *dev)
  {
  	struct drm_i915_private *dev_priv = dev->dev_private;
  
  	/* Assume that the BIOS does not lie through the OpRegion... */
  	if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) {
  		return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
  			connector_status_connected :
  			connector_status_disconnected;
  	}
  
  	switch (i915.panel_ignore_lid) {
  	case -2:
  		return connector_status_connected;
  	case -1:
  		return connector_status_disconnected;
  	default:
  		return connector_status_unknown;
  	}
  }
6dda730e5   Jani Nikula   drm/i915: respect...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  /**
   * scale - scale values from one range to another
   *
   * @source_val: value in range [@source_min..@source_max]
   *
   * Return @source_val in range [@source_min..@source_max] scaled to range
   * [@target_min..@target_max].
   */
  static uint32_t scale(uint32_t source_val,
  		      uint32_t source_min, uint32_t source_max,
  		      uint32_t target_min, uint32_t target_max)
  {
  	uint64_t target_val;
  
  	WARN_ON(source_min > source_max);
  	WARN_ON(target_min > target_max);
  
  	/* defensive */
  	source_val = clamp(source_val, source_min, source_max);
  
  	/* avoid overflows */
673e7bbdb   U. Artie Eoff   drm/i915: intel_b...
411
412
  	target_val = DIV_ROUND_CLOSEST_ULL((uint64_t)(source_val - source_min) *
  			(target_max - target_min), source_max - source_min);
6dda730e5   Jani Nikula   drm/i915: respect...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  	target_val += target_min;
  
  	return target_val;
  }
  
  /* Scale user_level in range [0..user_max] to [hw_min..hw_max]. */
  static inline u32 scale_user_to_hw(struct intel_connector *connector,
  				   u32 user_level, u32 user_max)
  {
  	struct intel_panel *panel = &connector->panel;
  
  	return scale(user_level, 0, user_max,
  		     panel->backlight.min, panel->backlight.max);
  }
  
  /* Scale user_level in range [0..user_max] to [0..hw_max], clamping the result
   * to [hw_min..hw_max]. */
  static inline u32 clamp_user_to_hw(struct intel_connector *connector,
  				   u32 user_level, u32 user_max)
  {
  	struct intel_panel *panel = &connector->panel;
  	u32 hw_level;
  
  	hw_level = scale(user_level, 0, user_max, 0, panel->backlight.max);
  	hw_level = clamp(hw_level, panel->backlight.min, panel->backlight.max);
  
  	return hw_level;
  }
  
  /* Scale hw_level in range [hw_min..hw_max] to [0..user_max]. */
  static inline u32 scale_hw_to_user(struct intel_connector *connector,
  				   u32 hw_level, u32 user_max)
  {
  	struct intel_panel *panel = &connector->panel;
  
  	return scale(hw_level, panel->backlight.min, panel->backlight.max,
  		     0, user_max);
  }
7bd688cd6   Jani Nikula   drm/i915: handle ...
451
452
  static u32 intel_panel_compute_brightness(struct intel_connector *connector,
  					  u32 val)
7bd90909b   Carsten Emde   drm/i915: panel: ...
453
  {
7bd688cd6   Jani Nikula   drm/i915: handle ...
454
  	struct drm_device *dev = connector->base.dev;
4dca20efb   Carsten Emde   drm/i915: panel: ...
455
  	struct drm_i915_private *dev_priv = dev->dev_private;
f91c15e08   Jani Nikula   drm/i915: use the...
456
457
458
  	struct intel_panel *panel = &connector->panel;
  
  	WARN_ON(panel->backlight.max == 0);
4dca20efb   Carsten Emde   drm/i915: panel: ...
459

d330a9530   Jani Nikula   drm/i915: move mo...
460
  	if (i915.invert_brightness < 0)
4dca20efb   Carsten Emde   drm/i915: panel: ...
461
  		return val;
d330a9530   Jani Nikula   drm/i915: move mo...
462
  	if (i915.invert_brightness > 0 ||
d65406327   Jani Nikula   drm/i915: keep ma...
463
  	    dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
f91c15e08   Jani Nikula   drm/i915: use the...
464
  		return panel->backlight.max - val;
d65406327   Jani Nikula   drm/i915: keep ma...
465
  	}
7bd90909b   Carsten Emde   drm/i915: panel: ...
466
467
468
  
  	return val;
  }
96ab4c703   Daniel Vetter   Merge branch 'bdw...
469
  static u32 bdw_get_backlight(struct intel_connector *connector)
0b0b053a3   Chris Wilson   drm/i915/panel: R...
470
  {
96ab4c703   Daniel Vetter   Merge branch 'bdw...
471
  	struct drm_device *dev = connector->base.dev;
bfd7590d3   Jani Nikula   drm/i915: do not ...
472
  	struct drm_i915_private *dev_priv = dev->dev_private;
0b0b053a3   Chris Wilson   drm/i915/panel: R...
473

96ab4c703   Daniel Vetter   Merge branch 'bdw...
474
475
  	return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
  }
07bf139b9   Jesse Barnes   drm/i915/vlv: use...
476

7bd688cd6   Jani Nikula   drm/i915: handle ...
477
  static u32 pch_get_backlight(struct intel_connector *connector)
a95735569   Chris Wilson   drm/i915: Refacto...
478
  {
7bd688cd6   Jani Nikula   drm/i915: handle ...
479
  	struct drm_device *dev = connector->base.dev;
a95735569   Chris Wilson   drm/i915: Refacto...
480
  	struct drm_i915_private *dev_priv = dev->dev_private;
8ba2d1852   Jani Nikula   drm/i915: protect...
481

7bd688cd6   Jani Nikula   drm/i915: handle ...
482
483
  	return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
  }
a95735569   Chris Wilson   drm/i915: Refacto...
484

7bd688cd6   Jani Nikula   drm/i915: handle ...
485
486
487
488
  static u32 i9xx_get_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
636baebfa   Jani Nikula   drm/i915: gather ...
489
  	struct intel_panel *panel = &connector->panel;
7bd688cd6   Jani Nikula   drm/i915: handle ...
490
  	u32 val;
07bf139b9   Jesse Barnes   drm/i915/vlv: use...
491

7bd688cd6   Jani Nikula   drm/i915: handle ...
492
493
494
  	val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
  	if (INTEL_INFO(dev)->gen < 4)
  		val >>= 1;
ba3820ade   Takashi Iwai   drm/i915: Revive ...
495

636baebfa   Jani Nikula   drm/i915: gather ...
496
  	if (panel->backlight.combination_mode) {
7bd688cd6   Jani Nikula   drm/i915: handle ...
497
  		u8 lbpc;
ba3820ade   Takashi Iwai   drm/i915: Revive ...
498

7bd688cd6   Jani Nikula   drm/i915: handle ...
499
500
  		pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
  		val *= lbpc;
a95735569   Chris Wilson   drm/i915: Refacto...
501
  	}
7bd688cd6   Jani Nikula   drm/i915: handle ...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  	return val;
  }
  
  static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe)
  {
  	struct drm_i915_private *dev_priv = dev->dev_private;
  
  	return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
  }
  
  static u32 vlv_get_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
  
  	return _vlv_get_backlight(dev, pipe);
  }
  
  static u32 intel_panel_get_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	u32 val;
  	unsigned long flags;
  
  	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
  
  	val = dev_priv->display.get_backlight(connector);
  	val = intel_panel_compute_brightness(connector, val);
8ba2d1852   Jani Nikula   drm/i915: protect...
531

58c68779e   Jani Nikula   drm/i915: make ba...
532
  	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
8ba2d1852   Jani Nikula   drm/i915: protect...
533

a95735569   Chris Wilson   drm/i915: Refacto...
534
535
536
537
  	DRM_DEBUG_DRIVER("get backlight PWM = %d
  ", val);
  	return val;
  }
96ab4c703   Daniel Vetter   Merge branch 'bdw...
538
  static void bdw_set_backlight(struct intel_connector *connector, u32 level)
f8e100621   Ben Widawsky   drm/i915/bdw: GEN...
539
  {
96ab4c703   Daniel Vetter   Merge branch 'bdw...
540
  	struct drm_device *dev = connector->base.dev;
f8e100621   Ben Widawsky   drm/i915/bdw: GEN...
541
542
543
544
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
  	I915_WRITE(BLC_PWM_PCH_CTL2, val | level);
  }
7bd688cd6   Jani Nikula   drm/i915: handle ...
545
  static void pch_set_backlight(struct intel_connector *connector, u32 level)
a95735569   Chris Wilson   drm/i915: Refacto...
546
  {
7bd688cd6   Jani Nikula   drm/i915: handle ...
547
  	struct drm_device *dev = connector->base.dev;
a95735569   Chris Wilson   drm/i915: Refacto...
548
  	struct drm_i915_private *dev_priv = dev->dev_private;
7bd688cd6   Jani Nikula   drm/i915: handle ...
549
550
551
552
  	u32 tmp;
  
  	tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
  	I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
a95735569   Chris Wilson   drm/i915: Refacto...
553
  }
7bd688cd6   Jani Nikula   drm/i915: handle ...
554
  static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
a95735569   Chris Wilson   drm/i915: Refacto...
555
  {
7bd688cd6   Jani Nikula   drm/i915: handle ...
556
  	struct drm_device *dev = connector->base.dev;
a95735569   Chris Wilson   drm/i915: Refacto...
557
  	struct drm_i915_private *dev_priv = dev->dev_private;
f91c15e08   Jani Nikula   drm/i915: use the...
558
  	struct intel_panel *panel = &connector->panel;
b329b3285   Jani Nikula   drm/i915: fix gen...
559
  	u32 tmp, mask;
ba3820ade   Takashi Iwai   drm/i915: Revive ...
560

f91c15e08   Jani Nikula   drm/i915: use the...
561
  	WARN_ON(panel->backlight.max == 0);
636baebfa   Jani Nikula   drm/i915: gather ...
562
  	if (panel->backlight.combination_mode) {
ba3820ade   Takashi Iwai   drm/i915: Revive ...
563
  		u8 lbpc;
f91c15e08   Jani Nikula   drm/i915: use the...
564
  		lbpc = level * 0xfe / panel->backlight.max + 1;
ba3820ade   Takashi Iwai   drm/i915: Revive ...
565
566
567
  		level /= lbpc;
  		pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
  	}
b329b3285   Jani Nikula   drm/i915: fix gen...
568
569
570
  	if (IS_GEN4(dev)) {
  		mask = BACKLIGHT_DUTY_CYCLE_MASK;
  	} else {
a95735569   Chris Wilson   drm/i915: Refacto...
571
  		level <<= 1;
b329b3285   Jani Nikula   drm/i915: fix gen...
572
573
  		mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
  	}
7bd688cd6   Jani Nikula   drm/i915: handle ...
574

b329b3285   Jani Nikula   drm/i915: fix gen...
575
  	tmp = I915_READ(BLC_PWM_CTL) & ~mask;
7bd688cd6   Jani Nikula   drm/i915: handle ...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
  	I915_WRITE(BLC_PWM_CTL, tmp | level);
  }
  
  static void vlv_set_backlight(struct intel_connector *connector, u32 level)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
  	u32 tmp;
  
  	tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
  	I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level);
  }
  
  static void
  intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  
  	DRM_DEBUG_DRIVER("set backlight PWM = %d
  ", level);
  
  	level = intel_panel_compute_brightness(connector, level);
  	dev_priv->display.set_backlight(connector, level);
a95735569   Chris Wilson   drm/i915: Refacto...
601
  }
47356eb67   Chris Wilson   drm/i915/panel: O...
602

6dda730e5   Jani Nikula   drm/i915: respect...
603
604
605
  /* set backlight brightness to level in range [0..max], scaling wrt hw min */
  static void intel_panel_set_backlight(struct intel_connector *connector,
  				      u32 user_level, u32 user_max)
47356eb67   Chris Wilson   drm/i915/panel: O...
606
  {
752aa88a1   Jesse Barnes   drm/i915: make ba...
607
  	struct drm_device *dev = connector->base.dev;
47356eb67   Chris Wilson   drm/i915/panel: O...
608
  	struct drm_i915_private *dev_priv = dev->dev_private;
58c68779e   Jani Nikula   drm/i915: make ba...
609
  	struct intel_panel *panel = &connector->panel;
752aa88a1   Jesse Barnes   drm/i915: make ba...
610
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
6dda730e5   Jani Nikula   drm/i915: respect...
611
  	u32 hw_level;
8ba2d1852   Jani Nikula   drm/i915: protect...
612
  	unsigned long flags;
dc5a43636   Ville Syrjälä   drm/i915: Elimina...
613
  	if (!panel->backlight.present || pipe == INVALID_PIPE)
752aa88a1   Jesse Barnes   drm/i915: make ba...
614
  		return;
58c68779e   Jani Nikula   drm/i915: make ba...
615
  	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
d65406327   Jani Nikula   drm/i915: keep ma...
616

f91c15e08   Jani Nikula   drm/i915: use the...
617
  	WARN_ON(panel->backlight.max == 0);
d65406327   Jani Nikula   drm/i915: keep ma...
618

6dda730e5   Jani Nikula   drm/i915: respect...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
  	hw_level = scale_user_to_hw(connector, user_level, user_max);
  	panel->backlight.level = hw_level;
  
  	if (panel->backlight.enabled)
  		intel_panel_actually_set_backlight(connector, hw_level);
  
  	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
  }
  
  /* set backlight brightness to level in range [0..max], assuming hw min is
   * respected.
   */
  void intel_panel_set_backlight_acpi(struct intel_connector *connector,
  				    u32 user_level, u32 user_max)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	struct intel_panel *panel = &connector->panel;
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
  	u32 hw_level;
  	unsigned long flags;
  
  	if (!panel->backlight.present || pipe == INVALID_PIPE)
  		return;
  
  	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
  
  	WARN_ON(panel->backlight.max == 0);
  
  	hw_level = clamp_user_to_hw(connector, user_level, user_max);
  	panel->backlight.level = hw_level;
47356eb67   Chris Wilson   drm/i915/panel: O...
650

58c68779e   Jani Nikula   drm/i915: make ba...
651
  	if (panel->backlight.device)
6dda730e5   Jani Nikula   drm/i915: respect...
652
653
654
655
  		panel->backlight.device->props.brightness =
  			scale_hw_to_user(connector,
  					 panel->backlight.level,
  					 panel->backlight.device->props.max_brightness);
b6b3ba5b2   Jani Nikula   drm/i915: keep ba...
656

58c68779e   Jani Nikula   drm/i915: make ba...
657
  	if (panel->backlight.enabled)
6dda730e5   Jani Nikula   drm/i915: respect...
658
  		intel_panel_actually_set_backlight(connector, hw_level);
f91c15e08   Jani Nikula   drm/i915: use the...
659

58c68779e   Jani Nikula   drm/i915: make ba...
660
  	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
f52c619a5   Takashi Iwai   drm/i915/panel: A...
661
  }
7bd688cd6   Jani Nikula   drm/i915: handle ...
662
663
664
665
666
  static void pch_disable_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	u32 tmp;
3bd712e54   Jani Nikula   drm/i915: move ba...
667
  	intel_panel_actually_set_backlight(connector, 0);
7bd688cd6   Jani Nikula   drm/i915: handle ...
668
669
670
671
672
673
  	tmp = I915_READ(BLC_PWM_CPU_CTL2);
  	I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
  
  	tmp = I915_READ(BLC_PWM_PCH_CTL1);
  	I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
  }
3bd712e54   Jani Nikula   drm/i915: move ba...
674
675
676
677
  static void i9xx_disable_backlight(struct intel_connector *connector)
  {
  	intel_panel_actually_set_backlight(connector, 0);
  }
7bd688cd6   Jani Nikula   drm/i915: handle ...
678
679
680
681
682
  static void i965_disable_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	u32 tmp;
3bd712e54   Jani Nikula   drm/i915: move ba...
683
  	intel_panel_actually_set_backlight(connector, 0);
7bd688cd6   Jani Nikula   drm/i915: handle ...
684
685
686
687
688
689
690
691
692
693
  	tmp = I915_READ(BLC_PWM_CTL2);
  	I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
  }
  
  static void vlv_disable_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
  	u32 tmp;
3bd712e54   Jani Nikula   drm/i915: move ba...
694
  	intel_panel_actually_set_backlight(connector, 0);
7bd688cd6   Jani Nikula   drm/i915: handle ...
695
696
697
  	tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe));
  	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
  }
752aa88a1   Jesse Barnes   drm/i915: make ba...
698
  void intel_panel_disable_backlight(struct intel_connector *connector)
f52c619a5   Takashi Iwai   drm/i915/panel: A...
699
  {
752aa88a1   Jesse Barnes   drm/i915: make ba...
700
  	struct drm_device *dev = connector->base.dev;
f52c619a5   Takashi Iwai   drm/i915/panel: A...
701
  	struct drm_i915_private *dev_priv = dev->dev_private;
58c68779e   Jani Nikula   drm/i915: make ba...
702
  	struct intel_panel *panel = &connector->panel;
752aa88a1   Jesse Barnes   drm/i915: make ba...
703
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
8ba2d1852   Jani Nikula   drm/i915: protect...
704
  	unsigned long flags;
dc5a43636   Ville Syrjälä   drm/i915: Elimina...
705
  	if (!panel->backlight.present || pipe == INVALID_PIPE)
752aa88a1   Jesse Barnes   drm/i915: make ba...
706
  		return;
3f577573c   Jani Nikula   drm/i915: do not ...
707
708
709
710
711
712
713
714
715
716
717
  	/*
  	 * Do not disable backlight on the vgaswitcheroo path. When switching
  	 * away from i915, the other client may depend on i915 to handle the
  	 * backlight. This will leave the backlight on unnecessarily when
  	 * another client is not activated.
  	 */
  	if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
  		DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch
  ");
  		return;
  	}
58c68779e   Jani Nikula   drm/i915: make ba...
718
  	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
47356eb67   Chris Wilson   drm/i915/panel: O...
719

ab656bb90   Jani Nikula   drm/i915: add som...
720
721
  	if (panel->backlight.device)
  		panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
58c68779e   Jani Nikula   drm/i915: make ba...
722
  	panel->backlight.enabled = false;
3bd712e54   Jani Nikula   drm/i915: move ba...
723
  	dev_priv->display.disable_backlight(connector);
24ded2044   Daniel Vetter   drm/i915: properl...
724

7bd688cd6   Jani Nikula   drm/i915: handle ...
725
726
  	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
  }
24ded2044   Daniel Vetter   drm/i915: properl...
727

96ab4c703   Daniel Vetter   Merge branch 'bdw...
728
729
730
731
732
733
734
735
736
737
738
739
740
741
  static void bdw_enable_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	struct intel_panel *panel = &connector->panel;
  	u32 pch_ctl1, pch_ctl2;
  
  	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
  	if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
  		DRM_DEBUG_KMS("pch backlight already enabled
  ");
  		pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
  		I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
  	}
24ded2044   Daniel Vetter   drm/i915: properl...
742

96ab4c703   Daniel Vetter   Merge branch 'bdw...
743
744
  	pch_ctl2 = panel->backlight.max << 16;
  	I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
a4f32fc3a   Paulo Zanoni   drm/i915: don't f...
745

96ab4c703   Daniel Vetter   Merge branch 'bdw...
746
747
748
  	pch_ctl1 = 0;
  	if (panel->backlight.active_low_pwm)
  		pch_ctl1 |= BLM_PCH_POLARITY;
8ba2d1852   Jani Nikula   drm/i915: protect...
749

96ab4c703   Daniel Vetter   Merge branch 'bdw...
750
751
752
753
754
755
756
757
758
  	/* BDW always uses the pch pwm controls. */
  	pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
  
  	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
  	POSTING_READ(BLC_PWM_PCH_CTL1);
  	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
  
  	/* This won't stick until the above enable. */
  	intel_panel_actually_set_backlight(connector, panel->backlight.level);
47356eb67   Chris Wilson   drm/i915/panel: O...
759
  }
7bd688cd6   Jani Nikula   drm/i915: handle ...
760
761
762
763
  static void pch_enable_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
3bd712e54   Jani Nikula   drm/i915: move ba...
764
  	struct intel_panel *panel = &connector->panel;
7bd688cd6   Jani Nikula   drm/i915: handle ...
765
766
767
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
  	enum transcoder cpu_transcoder =
  		intel_pipe_to_cpu_transcoder(dev_priv, pipe);
b35684b8f   Jani Nikula   drm/i915: do full...
768
  	u32 cpu_ctl2, pch_ctl1, pch_ctl2;
7bd688cd6   Jani Nikula   drm/i915: handle ...
769

b35684b8f   Jani Nikula   drm/i915: do full...
770
771
  	cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
  	if (cpu_ctl2 & BLM_PWM_ENABLE) {
813008cd3   Scot Doyle   drm/i915: don't w...
772
773
  		DRM_DEBUG_KMS("cpu backlight already enabled
  ");
b35684b8f   Jani Nikula   drm/i915: do full...
774
775
776
  		cpu_ctl2 &= ~BLM_PWM_ENABLE;
  		I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
  	}
7bd688cd6   Jani Nikula   drm/i915: handle ...
777

b35684b8f   Jani Nikula   drm/i915: do full...
778
779
780
781
782
783
784
  	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
  	if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
  		DRM_DEBUG_KMS("pch backlight already enabled
  ");
  		pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
  		I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
  	}
7bd688cd6   Jani Nikula   drm/i915: handle ...
785
786
  
  	if (cpu_transcoder == TRANSCODER_EDP)
b35684b8f   Jani Nikula   drm/i915: do full...
787
  		cpu_ctl2 = BLM_TRANSCODER_EDP;
7bd688cd6   Jani Nikula   drm/i915: handle ...
788
  	else
b35684b8f   Jani Nikula   drm/i915: do full...
789
790
  		cpu_ctl2 = BLM_PIPE(cpu_transcoder);
  	I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
7bd688cd6   Jani Nikula   drm/i915: handle ...
791
  	POSTING_READ(BLC_PWM_CPU_CTL2);
b35684b8f   Jani Nikula   drm/i915: do full...
792
  	I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
3bd712e54   Jani Nikula   drm/i915: move ba...
793

b35684b8f   Jani Nikula   drm/i915: do full...
794
  	/* This won't stick until the above enable. */
3bd712e54   Jani Nikula   drm/i915: move ba...
795
  	intel_panel_actually_set_backlight(connector, panel->backlight.level);
b35684b8f   Jani Nikula   drm/i915: do full...
796
797
798
  
  	pch_ctl2 = panel->backlight.max << 16;
  	I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
b35684b8f   Jani Nikula   drm/i915: do full...
799
800
801
  	pch_ctl1 = 0;
  	if (panel->backlight.active_low_pwm)
  		pch_ctl1 |= BLM_PCH_POLARITY;
96ab4c703   Daniel Vetter   Merge branch 'bdw...
802

b35684b8f   Jani Nikula   drm/i915: do full...
803
804
805
  	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
  	POSTING_READ(BLC_PWM_PCH_CTL1);
  	I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
3bd712e54   Jani Nikula   drm/i915: move ba...
806
807
808
809
  }
  
  static void i9xx_enable_backlight(struct intel_connector *connector)
  {
b35684b8f   Jani Nikula   drm/i915: do full...
810
811
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
3bd712e54   Jani Nikula   drm/i915: move ba...
812
  	struct intel_panel *panel = &connector->panel;
b35684b8f   Jani Nikula   drm/i915: do full...
813
814
815
816
  	u32 ctl, freq;
  
  	ctl = I915_READ(BLC_PWM_CTL);
  	if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
813008cd3   Scot Doyle   drm/i915: don't w...
817
818
  		DRM_DEBUG_KMS("backlight already enabled
  ");
b35684b8f   Jani Nikula   drm/i915: do full...
819
820
  		I915_WRITE(BLC_PWM_CTL, 0);
  	}
3bd712e54   Jani Nikula   drm/i915: move ba...
821

b35684b8f   Jani Nikula   drm/i915: do full...
822
823
824
825
826
  	freq = panel->backlight.max;
  	if (panel->backlight.combination_mode)
  		freq /= 0xff;
  
  	ctl = freq << 17;
b6ab66aa5   Jani Nikula   drm/i915: use bac...
827
  	if (panel->backlight.combination_mode)
b35684b8f   Jani Nikula   drm/i915: do full...
828
829
830
831
832
833
834
835
  		ctl |= BLM_LEGACY_MODE;
  	if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
  		ctl |= BLM_POLARITY_PNV;
  
  	I915_WRITE(BLC_PWM_CTL, ctl);
  	POSTING_READ(BLC_PWM_CTL);
  
  	/* XXX: combine this into above write? */
3bd712e54   Jani Nikula   drm/i915: move ba...
836
  	intel_panel_actually_set_backlight(connector, panel->backlight.level);
7bd688cd6   Jani Nikula   drm/i915: handle ...
837
  }
8ba2d1852   Jani Nikula   drm/i915: protect...
838

7bd688cd6   Jani Nikula   drm/i915: handle ...
839
840
841
842
  static void i965_enable_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
3bd712e54   Jani Nikula   drm/i915: move ba...
843
  	struct intel_panel *panel = &connector->panel;
7bd688cd6   Jani Nikula   drm/i915: handle ...
844
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
b35684b8f   Jani Nikula   drm/i915: do full...
845
  	u32 ctl, ctl2, freq;
7bd688cd6   Jani Nikula   drm/i915: handle ...
846

b35684b8f   Jani Nikula   drm/i915: do full...
847
848
  	ctl2 = I915_READ(BLC_PWM_CTL2);
  	if (ctl2 & BLM_PWM_ENABLE) {
813008cd3   Scot Doyle   drm/i915: don't w...
849
850
  		DRM_DEBUG_KMS("backlight already enabled
  ");
b35684b8f   Jani Nikula   drm/i915: do full...
851
852
853
  		ctl2 &= ~BLM_PWM_ENABLE;
  		I915_WRITE(BLC_PWM_CTL2, ctl2);
  	}
7bd688cd6   Jani Nikula   drm/i915: handle ...
854

b35684b8f   Jani Nikula   drm/i915: do full...
855
856
857
  	freq = panel->backlight.max;
  	if (panel->backlight.combination_mode)
  		freq /= 0xff;
7bd688cd6   Jani Nikula   drm/i915: handle ...
858

b35684b8f   Jani Nikula   drm/i915: do full...
859
860
  	ctl = freq << 16;
  	I915_WRITE(BLC_PWM_CTL, ctl);
3bd712e54   Jani Nikula   drm/i915: move ba...
861

b35684b8f   Jani Nikula   drm/i915: do full...
862
863
864
865
866
867
868
869
  	ctl2 = BLM_PIPE(pipe);
  	if (panel->backlight.combination_mode)
  		ctl2 |= BLM_COMBINATION_MODE;
  	if (panel->backlight.active_low_pwm)
  		ctl2 |= BLM_POLARITY_I965;
  	I915_WRITE(BLC_PWM_CTL2, ctl2);
  	POSTING_READ(BLC_PWM_CTL2);
  	I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
2e7eeeb59   Jani Nikula   drm/i915: set bac...
870
871
  
  	intel_panel_actually_set_backlight(connector, panel->backlight.level);
7bd688cd6   Jani Nikula   drm/i915: handle ...
872
873
874
875
876
877
  }
  
  static void vlv_enable_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
3bd712e54   Jani Nikula   drm/i915: move ba...
878
  	struct intel_panel *panel = &connector->panel;
7bd688cd6   Jani Nikula   drm/i915: handle ...
879
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
b35684b8f   Jani Nikula   drm/i915: do full...
880
  	u32 ctl, ctl2;
7bd688cd6   Jani Nikula   drm/i915: handle ...
881

b35684b8f   Jani Nikula   drm/i915: do full...
882
883
  	ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
  	if (ctl2 & BLM_PWM_ENABLE) {
813008cd3   Scot Doyle   drm/i915: don't w...
884
885
  		DRM_DEBUG_KMS("backlight already enabled
  ");
b35684b8f   Jani Nikula   drm/i915: do full...
886
887
888
  		ctl2 &= ~BLM_PWM_ENABLE;
  		I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
  	}
7bd688cd6   Jani Nikula   drm/i915: handle ...
889

b35684b8f   Jani Nikula   drm/i915: do full...
890
891
  	ctl = panel->backlight.max << 16;
  	I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl);
7bd688cd6   Jani Nikula   drm/i915: handle ...
892

b35684b8f   Jani Nikula   drm/i915: do full...
893
894
  	/* XXX: combine this into above write? */
  	intel_panel_actually_set_backlight(connector, panel->backlight.level);
7bd688cd6   Jani Nikula   drm/i915: handle ...
895

b35684b8f   Jani Nikula   drm/i915: do full...
896
897
898
899
  	ctl2 = 0;
  	if (panel->backlight.active_low_pwm)
  		ctl2 |= BLM_POLARITY_I965;
  	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
7bd688cd6   Jani Nikula   drm/i915: handle ...
900
  	POSTING_READ(VLV_BLC_PWM_CTL2(pipe));
b35684b8f   Jani Nikula   drm/i915: do full...
901
  	I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
47356eb67   Chris Wilson   drm/i915/panel: O...
902
  }
752aa88a1   Jesse Barnes   drm/i915: make ba...
903
  void intel_panel_enable_backlight(struct intel_connector *connector)
47356eb67   Chris Wilson   drm/i915/panel: O...
904
  {
752aa88a1   Jesse Barnes   drm/i915: make ba...
905
  	struct drm_device *dev = connector->base.dev;
47356eb67   Chris Wilson   drm/i915/panel: O...
906
  	struct drm_i915_private *dev_priv = dev->dev_private;
58c68779e   Jani Nikula   drm/i915: make ba...
907
  	struct intel_panel *panel = &connector->panel;
752aa88a1   Jesse Barnes   drm/i915: make ba...
908
  	enum pipe pipe = intel_get_pipe_from_connector(connector);
8ba2d1852   Jani Nikula   drm/i915: protect...
909
  	unsigned long flags;
dc5a43636   Ville Syrjälä   drm/i915: Elimina...
910
  	if (!panel->backlight.present || pipe == INVALID_PIPE)
752aa88a1   Jesse Barnes   drm/i915: make ba...
911
  		return;
6f2bcceb2   Damien Lespiau   drm/i915: Use pip...
912
913
  	DRM_DEBUG_KMS("pipe %c
  ", pipe_name(pipe));
540b5d027   Chris Wilson   drm/i915: Add bre...
914

58c68779e   Jani Nikula   drm/i915: make ba...
915
  	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
47356eb67   Chris Wilson   drm/i915/panel: O...
916

f91c15e08   Jani Nikula   drm/i915: use the...
917
  	WARN_ON(panel->backlight.max == 0);
77ca136e7   Jeremiah Mahler   drm/i915: fix inc...
918
  	if (panel->backlight.level <= panel->backlight.min) {
f91c15e08   Jani Nikula   drm/i915: use the...
919
  		panel->backlight.level = panel->backlight.max;
58c68779e   Jani Nikula   drm/i915: make ba...
920
921
  		if (panel->backlight.device)
  			panel->backlight.device->props.brightness =
6dda730e5   Jani Nikula   drm/i915: respect...
922
923
924
  				scale_hw_to_user(connector,
  						 panel->backlight.level,
  						 panel->backlight.device->props.max_brightness);
b6b3ba5b2   Jani Nikula   drm/i915: keep ba...
925
  	}
47356eb67   Chris Wilson   drm/i915/panel: O...
926

3bd712e54   Jani Nikula   drm/i915: move ba...
927
  	dev_priv->display.enable_backlight(connector);
58c68779e   Jani Nikula   drm/i915: make ba...
928
  	panel->backlight.enabled = true;
ab656bb90   Jani Nikula   drm/i915: add som...
929
930
  	if (panel->backlight.device)
  		panel->backlight.device->props.power = FB_BLANK_UNBLANK;
8ba2d1852   Jani Nikula   drm/i915: protect...
931

58c68779e   Jani Nikula   drm/i915: make ba...
932
  	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
47356eb67   Chris Wilson   drm/i915/panel: O...
933
  }
912e8b12e   Jani Nikula   drm/i915: registe...
934
  #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
db31af1d4   Jani Nikula   drm/i915: clean u...
935
  static int intel_backlight_device_update_status(struct backlight_device *bd)
aaa6fd2a0   Matthew Garrett   Not all systems e...
936
  {
752aa88a1   Jesse Barnes   drm/i915: make ba...
937
  	struct intel_connector *connector = bl_get_data(bd);
ab656bb90   Jani Nikula   drm/i915: add som...
938
  	struct intel_panel *panel = &connector->panel;
752aa88a1   Jesse Barnes   drm/i915: make ba...
939
  	struct drm_device *dev = connector->base.dev;
51fd371bb   Rob Clark   drm: convert crtc...
940
  	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
540b5d027   Chris Wilson   drm/i915: Add bre...
941
942
943
  	DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d
  ",
  		      bd->props.brightness, bd->props.max_brightness);
752aa88a1   Jesse Barnes   drm/i915: make ba...
944
  	intel_panel_set_backlight(connector, bd->props.brightness,
d65406327   Jani Nikula   drm/i915: keep ma...
945
  				  bd->props.max_brightness);
ab656bb90   Jani Nikula   drm/i915: add som...
946
947
948
949
950
951
952
953
954
  
  	/*
  	 * Allow flipping bl_power as a sub-state of enabled. Sadly the
  	 * backlight class device does not make it easy to to differentiate
  	 * between callbacks for brightness and bl_power, so our backlight_power
  	 * callback needs to take this into account.
  	 */
  	if (panel->backlight.enabled) {
  		if (panel->backlight_power) {
e6755fb78   Jani Nikula   drm/i915: switch ...
955
956
  			bool enable = bd->props.power == FB_BLANK_UNBLANK &&
  				bd->props.brightness != 0;
ab656bb90   Jani Nikula   drm/i915: add som...
957
958
959
960
961
  			panel->backlight_power(connector, enable);
  		}
  	} else {
  		bd->props.power = FB_BLANK_POWERDOWN;
  	}
51fd371bb   Rob Clark   drm: convert crtc...
962
  	drm_modeset_unlock(&dev->mode_config.connection_mutex);
aaa6fd2a0   Matthew Garrett   Not all systems e...
963
964
  	return 0;
  }
db31af1d4   Jani Nikula   drm/i915: clean u...
965
  static int intel_backlight_device_get_brightness(struct backlight_device *bd)
aaa6fd2a0   Matthew Garrett   Not all systems e...
966
  {
752aa88a1   Jesse Barnes   drm/i915: make ba...
967
968
  	struct intel_connector *connector = bl_get_data(bd);
  	struct drm_device *dev = connector->base.dev;
c8c8fb33b   Paulo Zanoni   drm/i915: add som...
969
  	struct drm_i915_private *dev_priv = dev->dev_private;
6dda730e5   Jani Nikula   drm/i915: respect...
970
  	u32 hw_level;
7bd688cd6   Jani Nikula   drm/i915: handle ...
971
  	int ret;
752aa88a1   Jesse Barnes   drm/i915: make ba...
972

c8c8fb33b   Paulo Zanoni   drm/i915: add som...
973
  	intel_runtime_pm_get(dev_priv);
51fd371bb   Rob Clark   drm: convert crtc...
974
  	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
6dda730e5   Jani Nikula   drm/i915: respect...
975
976
977
  
  	hw_level = intel_panel_get_backlight(connector);
  	ret = scale_hw_to_user(connector, hw_level, bd->props.max_brightness);
51fd371bb   Rob Clark   drm: convert crtc...
978
  	drm_modeset_unlock(&dev->mode_config.connection_mutex);
c8c8fb33b   Paulo Zanoni   drm/i915: add som...
979
  	intel_runtime_pm_put(dev_priv);
752aa88a1   Jesse Barnes   drm/i915: make ba...
980

7bd688cd6   Jani Nikula   drm/i915: handle ...
981
  	return ret;
aaa6fd2a0   Matthew Garrett   Not all systems e...
982
  }
db31af1d4   Jani Nikula   drm/i915: clean u...
983
984
985
  static const struct backlight_ops intel_backlight_device_ops = {
  	.update_status = intel_backlight_device_update_status,
  	.get_brightness = intel_backlight_device_get_brightness,
aaa6fd2a0   Matthew Garrett   Not all systems e...
986
  };
db31af1d4   Jani Nikula   drm/i915: clean u...
987
  static int intel_backlight_device_register(struct intel_connector *connector)
aaa6fd2a0   Matthew Garrett   Not all systems e...
988
  {
58c68779e   Jani Nikula   drm/i915: make ba...
989
  	struct intel_panel *panel = &connector->panel;
aaa6fd2a0   Matthew Garrett   Not all systems e...
990
  	struct backlight_properties props;
aaa6fd2a0   Matthew Garrett   Not all systems e...
991

58c68779e   Jani Nikula   drm/i915: make ba...
992
  	if (WARN_ON(panel->backlight.device))
dc652f90e   Jani Nikula   drm/i915: ensure ...
993
  		return -ENODEV;
6dda730e5   Jani Nikula   drm/i915: respect...
994
  	WARN_ON(panel->backlight.max == 0);
7bd688cd6   Jani Nikula   drm/i915: handle ...
995

af437cfd3   Corentin Chary   drm/backlight: in...
996
  	memset(&props, 0, sizeof(props));
aaa6fd2a0   Matthew Garrett   Not all systems e...
997
  	props.type = BACKLIGHT_RAW;
6dda730e5   Jani Nikula   drm/i915: respect...
998
999
1000
1001
1002
  
  	/*
  	 * Note: Everything should work even if the backlight device max
  	 * presented to the userspace is arbitrarily chosen.
  	 */
7bd688cd6   Jani Nikula   drm/i915: handle ...
1003
  	props.max_brightness = panel->backlight.max;
6dda730e5   Jani Nikula   drm/i915: respect...
1004
1005
1006
  	props.brightness = scale_hw_to_user(connector,
  					    panel->backlight.level,
  					    props.max_brightness);
58c68779e   Jani Nikula   drm/i915: make ba...
1007

ab656bb90   Jani Nikula   drm/i915: add som...
1008
1009
1010
1011
  	if (panel->backlight.enabled)
  		props.power = FB_BLANK_UNBLANK;
  	else
  		props.power = FB_BLANK_POWERDOWN;
58c68779e   Jani Nikula   drm/i915: make ba...
1012
1013
1014
1015
1016
  	/*
  	 * Note: using the same name independent of the connector prevents
  	 * registration of multiple backlight devices in the driver.
  	 */
  	panel->backlight.device =
aaa6fd2a0   Matthew Garrett   Not all systems e...
1017
  		backlight_device_register("intel_backlight",
db31af1d4   Jani Nikula   drm/i915: clean u...
1018
1019
1020
  					  connector->base.kdev,
  					  connector,
  					  &intel_backlight_device_ops, &props);
aaa6fd2a0   Matthew Garrett   Not all systems e...
1021

58c68779e   Jani Nikula   drm/i915: make ba...
1022
  	if (IS_ERR(panel->backlight.device)) {
aaa6fd2a0   Matthew Garrett   Not all systems e...
1023
1024
  		DRM_ERROR("Failed to register backlight: %ld
  ",
58c68779e   Jani Nikula   drm/i915: make ba...
1025
1026
  			  PTR_ERR(panel->backlight.device));
  		panel->backlight.device = NULL;
aaa6fd2a0   Matthew Garrett   Not all systems e...
1027
1028
  		return -ENODEV;
  	}
aaa6fd2a0   Matthew Garrett   Not all systems e...
1029
1030
  	return 0;
  }
db31af1d4   Jani Nikula   drm/i915: clean u...
1031
  static void intel_backlight_device_unregister(struct intel_connector *connector)
aaa6fd2a0   Matthew Garrett   Not all systems e...
1032
  {
58c68779e   Jani Nikula   drm/i915: make ba...
1033
1034
1035
1036
1037
  	struct intel_panel *panel = &connector->panel;
  
  	if (panel->backlight.device) {
  		backlight_device_unregister(panel->backlight.device);
  		panel->backlight.device = NULL;
dc652f90e   Jani Nikula   drm/i915: ensure ...
1038
  	}
aaa6fd2a0   Matthew Garrett   Not all systems e...
1039
  }
db31af1d4   Jani Nikula   drm/i915: clean u...
1040
1041
1042
1043
1044
1045
1046
1047
1048
  #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
  static int intel_backlight_device_register(struct intel_connector *connector)
  {
  	return 0;
  }
  static void intel_backlight_device_unregister(struct intel_connector *connector)
  {
  }
  #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
f91c15e08   Jani Nikula   drm/i915: use the...
1049
1050
1051
1052
1053
1054
  /*
   * Note: The setup hooks can't assume pipe is set!
   *
   * XXX: Query mode clock or hardware clock and program PWM modulation frequency
   * appropriately when it's 0. Use VBT and/or sane defaults.
   */
6dda730e5   Jani Nikula   drm/i915: respect...
1055
1056
1057
1058
1059
  static u32 get_backlight_min_vbt(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	struct intel_panel *panel = &connector->panel;
e1c412e75   Jani Nikula   drm/i915: safegua...
1060
  	int min;
6dda730e5   Jani Nikula   drm/i915: respect...
1061
1062
  
  	WARN_ON(panel->backlight.max == 0);
e1c412e75   Jani Nikula   drm/i915: safegua...
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  	/*
  	 * XXX: If the vbt value is 255, it makes min equal to max, which leads
  	 * to problems. There are such machines out there. Either our
  	 * interpretation is wrong or the vbt has bogus data. Or both. Safeguard
  	 * against this by letting the minimum be at most (arbitrarily chosen)
  	 * 25% of the max.
  	 */
  	min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64);
  	if (min != dev_priv->vbt.backlight.min_brightness) {
  		DRM_DEBUG_KMS("clamping VBT min backlight %d/255 to %d/255
  ",
  			      dev_priv->vbt.backlight.min_brightness, min);
  	}
6dda730e5   Jani Nikula   drm/i915: respect...
1076
  	/* vbt value is a coefficient in range [0..255] */
e1c412e75   Jani Nikula   drm/i915: safegua...
1077
  	return scale(min, 0, 255, 0, panel->backlight.max);
6dda730e5   Jani Nikula   drm/i915: respect...
1078
  }
96ab4c703   Daniel Vetter   Merge branch 'bdw...
1079
  static int bdw_setup_backlight(struct intel_connector *connector)
aaa6fd2a0   Matthew Garrett   Not all systems e...
1080
  {
96ab4c703   Daniel Vetter   Merge branch 'bdw...
1081
  	struct drm_device *dev = connector->base.dev;
aaa6fd2a0   Matthew Garrett   Not all systems e...
1082
  	struct drm_i915_private *dev_priv = dev->dev_private;
96ab4c703   Daniel Vetter   Merge branch 'bdw...
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  	struct intel_panel *panel = &connector->panel;
  	u32 pch_ctl1, pch_ctl2, val;
  
  	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
  	panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
  
  	pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
  	panel->backlight.max = pch_ctl2 >> 16;
  	if (!panel->backlight.max)
  		return -ENODEV;
6dda730e5   Jani Nikula   drm/i915: respect...
1093
  	panel->backlight.min = get_backlight_min_vbt(connector);
96ab4c703   Daniel Vetter   Merge branch 'bdw...
1094
1095
1096
1097
1098
1099
1100
1101
  	val = bdw_get_backlight(connector);
  	panel->backlight.level = intel_panel_compute_brightness(connector, val);
  
  	panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) &&
  		panel->backlight.level != 0;
  
  	return 0;
  }
7bd688cd6   Jani Nikula   drm/i915: handle ...
1102
1103
  static int pch_setup_backlight(struct intel_connector *connector)
  {
636baebfa   Jani Nikula   drm/i915: gather ...
1104
1105
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1106
  	struct intel_panel *panel = &connector->panel;
636baebfa   Jani Nikula   drm/i915: gather ...
1107
  	u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1108

636baebfa   Jani Nikula   drm/i915: gather ...
1109
1110
1111
1112
1113
  	pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
  	panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
  
  	pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
  	panel->backlight.max = pch_ctl2 >> 16;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1114
1115
  	if (!panel->backlight.max)
  		return -ENODEV;
6dda730e5   Jani Nikula   drm/i915: respect...
1116
  	panel->backlight.min = get_backlight_min_vbt(connector);
7bd688cd6   Jani Nikula   drm/i915: handle ...
1117
1118
  	val = pch_get_backlight(connector);
  	panel->backlight.level = intel_panel_compute_brightness(connector, val);
636baebfa   Jani Nikula   drm/i915: gather ...
1119
1120
1121
  	cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
  	panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
  		(pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1122
1123
1124
1125
1126
  	return 0;
  }
  
  static int i9xx_setup_backlight(struct intel_connector *connector)
  {
636baebfa   Jani Nikula   drm/i915: gather ...
1127
1128
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1129
  	struct intel_panel *panel = &connector->panel;
636baebfa   Jani Nikula   drm/i915: gather ...
1130
1131
1132
  	u32 ctl, val;
  
  	ctl = I915_READ(BLC_PWM_CTL);
b6ab66aa5   Jani Nikula   drm/i915: use bac...
1133
  	if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
636baebfa   Jani Nikula   drm/i915: gather ...
1134
1135
1136
1137
1138
1139
1140
1141
  		panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
  
  	if (IS_PINEVIEW(dev))
  		panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
  
  	panel->backlight.max = ctl >> 17;
  	if (panel->backlight.combination_mode)
  		panel->backlight.max *= 0xff;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1142

7bd688cd6   Jani Nikula   drm/i915: handle ...
1143
1144
  	if (!panel->backlight.max)
  		return -ENODEV;
6dda730e5   Jani Nikula   drm/i915: respect...
1145
  	panel->backlight.min = get_backlight_min_vbt(connector);
7bd688cd6   Jani Nikula   drm/i915: handle ...
1146
1147
  	val = i9xx_get_backlight(connector);
  	panel->backlight.level = intel_panel_compute_brightness(connector, val);
636baebfa   Jani Nikula   drm/i915: gather ...
1148
  	panel->backlight.enabled = panel->backlight.level != 0;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1149
1150
1151
1152
1153
  	return 0;
  }
  
  static int i965_setup_backlight(struct intel_connector *connector)
  {
636baebfa   Jani Nikula   drm/i915: gather ...
1154
1155
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1156
  	struct intel_panel *panel = &connector->panel;
636baebfa   Jani Nikula   drm/i915: gather ...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
  	u32 ctl, ctl2, val;
  
  	ctl2 = I915_READ(BLC_PWM_CTL2);
  	panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
  	panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
  
  	ctl = I915_READ(BLC_PWM_CTL);
  	panel->backlight.max = ctl >> 16;
  	if (panel->backlight.combination_mode)
  		panel->backlight.max *= 0xff;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1167

7bd688cd6   Jani Nikula   drm/i915: handle ...
1168
1169
  	if (!panel->backlight.max)
  		return -ENODEV;
6dda730e5   Jani Nikula   drm/i915: respect...
1170
  	panel->backlight.min = get_backlight_min_vbt(connector);
7bd688cd6   Jani Nikula   drm/i915: handle ...
1171
1172
  	val = i9xx_get_backlight(connector);
  	panel->backlight.level = intel_panel_compute_brightness(connector, val);
636baebfa   Jani Nikula   drm/i915: gather ...
1173
1174
  	panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
  		panel->backlight.level != 0;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1175
1176
1177
1178
1179
1180
1181
1182
1183
  	return 0;
  }
  
  static int vlv_setup_backlight(struct intel_connector *connector)
  {
  	struct drm_device *dev = connector->base.dev;
  	struct drm_i915_private *dev_priv = dev->dev_private;
  	struct intel_panel *panel = &connector->panel;
  	enum pipe pipe;
636baebfa   Jani Nikula   drm/i915: gather ...
1184
  	u32 ctl, ctl2, val;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1185

055e393fa   Damien Lespiau   drm/i915: Use dev...
1186
  	for_each_pipe(dev_priv, pipe) {
7bd688cd6   Jani Nikula   drm/i915: handle ...
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
  		u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));
  
  		/* Skip if the modulation freq is already set */
  		if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK)
  			continue;
  
  		cur_val &= BACKLIGHT_DUTY_CYCLE_MASK;
  		I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) |
  			   cur_val);
  	}
636baebfa   Jani Nikula   drm/i915: gather ...
1197
1198
1199
1200
1201
  	ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A));
  	panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
  
  	ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A));
  	panel->backlight.max = ctl >> 16;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1202
1203
  	if (!panel->backlight.max)
  		return -ENODEV;
6dda730e5   Jani Nikula   drm/i915: respect...
1204
  	panel->backlight.min = get_backlight_min_vbt(connector);
7bd688cd6   Jani Nikula   drm/i915: handle ...
1205
1206
  	val = _vlv_get_backlight(dev, PIPE_A);
  	panel->backlight.level = intel_panel_compute_brightness(connector, val);
636baebfa   Jani Nikula   drm/i915: gather ...
1207
1208
  	panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
  		panel->backlight.level != 0;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1209
1210
  	return 0;
  }
0657b6b11   Jani Nikula   drm/i915: Backlig...
1211
  int intel_panel_setup_backlight(struct drm_connector *connector)
aaa6fd2a0   Matthew Garrett   Not all systems e...
1212
  {
db31af1d4   Jani Nikula   drm/i915: clean u...
1213
  	struct drm_device *dev = connector->dev;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1214
  	struct drm_i915_private *dev_priv = dev->dev_private;
db31af1d4   Jani Nikula   drm/i915: clean u...
1215
  	struct intel_connector *intel_connector = to_intel_connector(connector);
58c68779e   Jani Nikula   drm/i915: make ba...
1216
  	struct intel_panel *panel = &intel_connector->panel;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1217
1218
  	unsigned long flags;
  	int ret;
db31af1d4   Jani Nikula   drm/i915: clean u...
1219

c675949ec   Jani Nikula   drm/i915: do not ...
1220
  	if (!dev_priv->vbt.backlight.present) {
9c72cc6f0   Scot Doyle   drm/i915: quirk a...
1221
1222
1223
1224
1225
1226
1227
1228
  		if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
  			DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk
  ");
  		} else {
  			DRM_DEBUG_KMS("no backlight present per VBT
  ");
  			return 0;
  		}
c675949ec   Jani Nikula   drm/i915: do not ...
1229
  	}
7bd688cd6   Jani Nikula   drm/i915: handle ...
1230
1231
1232
1233
1234
1235
1236
1237
  	/* set level and max in panel struct */
  	spin_lock_irqsave(&dev_priv->backlight_lock, flags);
  	ret = dev_priv->display.setup_backlight(intel_connector);
  	spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
  
  	if (ret) {
  		DRM_DEBUG_KMS("failed to setup backlight for connector %s
  ",
c23cc4178   Jani Nikula   drm/i915: replace...
1238
  			      connector->name);
7bd688cd6   Jani Nikula   drm/i915: handle ...
1239
1240
  		return ret;
  	}
db31af1d4   Jani Nikula   drm/i915: clean u...
1241

db31af1d4   Jani Nikula   drm/i915: clean u...
1242
  	intel_backlight_device_register(intel_connector);
c91c9f328   Jani Nikula   drm/i915: make as...
1243
  	panel->backlight.present = true;
c445b3b1e   Jani Nikula   drm/i915: debug p...
1244
1245
1246
1247
1248
1249
  	DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, "
  		      "sysfs interface %sregistered
  ",
  		      panel->backlight.enabled ? "enabled" : "disabled",
  		      panel->backlight.level, panel->backlight.max,
  		      panel->backlight.device ? "" : "not ");
aaa6fd2a0   Matthew Garrett   Not all systems e...
1250
1251
  	return 0;
  }
db31af1d4   Jani Nikula   drm/i915: clean u...
1252
  void intel_panel_destroy_backlight(struct drm_connector *connector)
aaa6fd2a0   Matthew Garrett   Not all systems e...
1253
  {
db31af1d4   Jani Nikula   drm/i915: clean u...
1254
  	struct intel_connector *intel_connector = to_intel_connector(connector);
c91c9f328   Jani Nikula   drm/i915: make as...
1255
  	struct intel_panel *panel = &intel_connector->panel;
db31af1d4   Jani Nikula   drm/i915: clean u...
1256

c91c9f328   Jani Nikula   drm/i915: make as...
1257
  	panel->backlight.present = false;
db31af1d4   Jani Nikula   drm/i915: clean u...
1258
  	intel_backlight_device_unregister(intel_connector);
aaa6fd2a0   Matthew Garrett   Not all systems e...
1259
  }
1d508706e   Jani Nikula   drm/i915: Create ...
1260

7bd688cd6   Jani Nikula   drm/i915: handle ...
1261
1262
1263
1264
  /* Set up chip specific backlight functions */
  void intel_panel_init_backlight_funcs(struct drm_device *dev)
  {
  	struct drm_i915_private *dev_priv = dev->dev_private;
96ab4c703   Daniel Vetter   Merge branch 'bdw...
1265
1266
1267
1268
1269
1270
1271
  	if (IS_BROADWELL(dev)) {
  		dev_priv->display.setup_backlight = bdw_setup_backlight;
  		dev_priv->display.enable_backlight = bdw_enable_backlight;
  		dev_priv->display.disable_backlight = pch_disable_backlight;
  		dev_priv->display.set_backlight = bdw_set_backlight;
  		dev_priv->display.get_backlight = bdw_get_backlight;
  	} else if (HAS_PCH_SPLIT(dev)) {
7bd688cd6   Jani Nikula   drm/i915: handle ...
1272
1273
1274
1275
1276
  		dev_priv->display.setup_backlight = pch_setup_backlight;
  		dev_priv->display.enable_backlight = pch_enable_backlight;
  		dev_priv->display.disable_backlight = pch_disable_backlight;
  		dev_priv->display.set_backlight = pch_set_backlight;
  		dev_priv->display.get_backlight = pch_get_backlight;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1277
1278
1279
1280
1281
1282
  	} else if (IS_VALLEYVIEW(dev)) {
  		dev_priv->display.setup_backlight = vlv_setup_backlight;
  		dev_priv->display.enable_backlight = vlv_enable_backlight;
  		dev_priv->display.disable_backlight = vlv_disable_backlight;
  		dev_priv->display.set_backlight = vlv_set_backlight;
  		dev_priv->display.get_backlight = vlv_get_backlight;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1283
1284
1285
1286
1287
1288
  	} else if (IS_GEN4(dev)) {
  		dev_priv->display.setup_backlight = i965_setup_backlight;
  		dev_priv->display.enable_backlight = i965_enable_backlight;
  		dev_priv->display.disable_backlight = i965_disable_backlight;
  		dev_priv->display.set_backlight = i9xx_set_backlight;
  		dev_priv->display.get_backlight = i9xx_get_backlight;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1289
1290
  	} else {
  		dev_priv->display.setup_backlight = i9xx_setup_backlight;
3bd712e54   Jani Nikula   drm/i915: move ba...
1291
1292
  		dev_priv->display.enable_backlight = i9xx_enable_backlight;
  		dev_priv->display.disable_backlight = i9xx_disable_backlight;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1293
1294
  		dev_priv->display.set_backlight = i9xx_set_backlight;
  		dev_priv->display.get_backlight = i9xx_get_backlight;
7bd688cd6   Jani Nikula   drm/i915: handle ...
1295
1296
  	}
  }
dd06f90ee   Jani Nikula   drm/i915: Move th...
1297
  int intel_panel_init(struct intel_panel *panel,
4b6ed685e   Vandana Kannan   drm/i915: Initial...
1298
1299
  		     struct drm_display_mode *fixed_mode,
  		     struct drm_display_mode *downclock_mode)
1d508706e   Jani Nikula   drm/i915: Create ...
1300
  {
dd06f90ee   Jani Nikula   drm/i915: Move th...
1301
  	panel->fixed_mode = fixed_mode;
4b6ed685e   Vandana Kannan   drm/i915: Initial...
1302
  	panel->downclock_mode = downclock_mode;
dd06f90ee   Jani Nikula   drm/i915: Move th...
1303

1d508706e   Jani Nikula   drm/i915: Create ...
1304
1305
1306
1307
1308
  	return 0;
  }
  
  void intel_panel_fini(struct intel_panel *panel)
  {
dd06f90ee   Jani Nikula   drm/i915: Move th...
1309
1310
1311
1312
1313
  	struct intel_connector *intel_connector =
  		container_of(panel, struct intel_connector, panel);
  
  	if (panel->fixed_mode)
  		drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
ec9ed1976   Vandana Kannan   drm/i915: Make do...
1314
1315
1316
1317
  
  	if (panel->downclock_mode)
  		drm_mode_destroy(intel_connector->base.dev,
  				panel->downclock_mode);
1d508706e   Jani Nikula   drm/i915: Create ...
1318
  }