~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/gpu/drm/i915/intel_panel.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright Ā© 2006-2010 Intel Corporation
 
3
 * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
 
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 <eric@anholt.net>
 
26
 *      Dave Airlie <airlied@linux.ie>
 
27
 *      Jesse Barnes <jesse.barnes@intel.com>
 
28
 *      Chris Wilson <chris@chris-wilson.co.uk>
 
29
 */
 
30
 
 
31
#include "intel_drv.h"
 
32
 
 
33
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
 
34
 
 
35
void
 
36
intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 
37
                       struct drm_display_mode *adjusted_mode)
 
38
{
 
39
        adjusted_mode->hdisplay = fixed_mode->hdisplay;
 
40
        adjusted_mode->hsync_start = fixed_mode->hsync_start;
 
41
        adjusted_mode->hsync_end = fixed_mode->hsync_end;
 
42
        adjusted_mode->htotal = fixed_mode->htotal;
 
43
 
 
44
        adjusted_mode->vdisplay = fixed_mode->vdisplay;
 
45
        adjusted_mode->vsync_start = fixed_mode->vsync_start;
 
46
        adjusted_mode->vsync_end = fixed_mode->vsync_end;
 
47
        adjusted_mode->vtotal = fixed_mode->vtotal;
 
48
 
 
49
        adjusted_mode->clock = fixed_mode->clock;
 
50
 
 
51
        drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
 
52
}
 
53
 
 
54
/* adjusted_mode has been preset to be the panel's fixed mode */
 
55
void
 
56
intel_pch_panel_fitting(struct drm_device *dev,
 
57
                        int fitting_mode,
 
58
                        struct drm_display_mode *mode,
 
59
                        struct drm_display_mode *adjusted_mode)
 
60
{
 
61
        struct drm_i915_private *dev_priv = dev->dev_private;
 
62
        int x, y, width, height;
 
63
 
 
64
        x = y = width = height = 0;
 
65
 
 
66
        /* Native modes don't need fitting */
 
67
        if (adjusted_mode->hdisplay == mode->hdisplay &&
 
68
            adjusted_mode->vdisplay == mode->vdisplay)
 
69
                goto done;
 
70
 
 
71
        switch (fitting_mode) {
 
72
        case DRM_MODE_SCALE_CENTER:
 
73
                width = mode->hdisplay;
 
74
                height = mode->vdisplay;
 
75
                x = (adjusted_mode->hdisplay - width + 1)/2;
 
76
                y = (adjusted_mode->vdisplay - height + 1)/2;
 
77
                break;
 
78
 
 
79
        case DRM_MODE_SCALE_ASPECT:
 
80
                /* Scale but preserve the aspect ratio */
 
81
                {
 
82
                        u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
 
83
                        u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
 
84
                        if (scaled_width > scaled_height) { /* pillar */
 
85
                                width = scaled_height / mode->vdisplay;
 
86
                                if (width & 1)
 
87
                                        width++;
 
88
                                x = (adjusted_mode->hdisplay - width + 1) / 2;
 
89
                                y = 0;
 
90
                                height = adjusted_mode->vdisplay;
 
91
                        } else if (scaled_width < scaled_height) { /* letter */
 
92
                                height = scaled_width / mode->hdisplay;
 
93
                                if (height & 1)
 
94
                                    height++;
 
95
                                y = (adjusted_mode->vdisplay - height + 1) / 2;
 
96
                                x = 0;
 
97
                                width = adjusted_mode->hdisplay;
 
98
                        } else {
 
99
                                x = y = 0;
 
100
                                width = adjusted_mode->hdisplay;
 
101
                                height = adjusted_mode->vdisplay;
 
102
                        }
 
103
                }
 
104
                break;
 
105
 
 
106
        default:
 
107
        case DRM_MODE_SCALE_FULLSCREEN:
 
108
                x = y = 0;
 
109
                width = adjusted_mode->hdisplay;
 
110
                height = adjusted_mode->vdisplay;
 
111
                break;
 
112
        }
 
113
 
 
114
done:
 
115
        dev_priv->pch_pf_pos = (x << 16) | y;
 
116
        dev_priv->pch_pf_size = (width << 16) | height;
 
117
}
 
118
 
 
119
static int is_backlight_combination_mode(struct drm_device *dev)
 
120
{
 
121
        struct drm_i915_private *dev_priv = dev->dev_private;
 
122
 
 
123
        if (INTEL_INFO(dev)->gen >= 4)
 
124
                return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
 
125
 
 
126
        if (IS_GEN2(dev))
 
127
                return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
 
128
 
 
129
        return 0;
 
130
}
 
131
 
 
132
static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
 
133
{
 
134
        u32 val;
 
135
 
 
136
        /* Restore the CTL value if it lost, e.g. GPU reset */
 
137
 
 
138
        if (HAS_PCH_SPLIT(dev_priv->dev)) {
 
139
                val = I915_READ(BLC_PWM_PCH_CTL2);
 
140
                if (dev_priv->saveBLC_PWM_CTL2 == 0) {
 
141
                        dev_priv->saveBLC_PWM_CTL2 = val;
 
142
                } else if (val == 0) {
 
143
                        I915_WRITE(BLC_PWM_PCH_CTL2,
 
144
                                   dev_priv->saveBLC_PWM_CTL);
 
145
                        val = dev_priv->saveBLC_PWM_CTL;
 
146
                }
 
147
        } else {
 
148
                val = I915_READ(BLC_PWM_CTL);
 
149
                if (dev_priv->saveBLC_PWM_CTL == 0) {
 
150
                        dev_priv->saveBLC_PWM_CTL = val;
 
151
                        dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
 
152
                } else if (val == 0) {
 
153
                        I915_WRITE(BLC_PWM_CTL,
 
154
                                   dev_priv->saveBLC_PWM_CTL);
 
155
                        I915_WRITE(BLC_PWM_CTL2,
 
156
                                   dev_priv->saveBLC_PWM_CTL2);
 
157
                        val = dev_priv->saveBLC_PWM_CTL;
 
158
                }
 
159
        }
 
160
 
 
161
        return val;
 
162
}
 
163
 
 
164
u32 intel_panel_get_max_backlight(struct drm_device *dev)
 
165
{
 
166
        struct drm_i915_private *dev_priv = dev->dev_private;
 
167
        u32 max;
 
168
 
 
169
        max = i915_read_blc_pwm_ctl(dev_priv);
 
170
        if (max == 0) {
 
171
                /* XXX add code here to query mode clock or hardware clock
 
172
                 * and program max PWM appropriately.
 
173
                 */
 
174
                printk_once(KERN_WARNING "fixme: max PWM is zero.\n");
 
175
                return 1;
 
176
        }
 
177
 
 
178
        if (HAS_PCH_SPLIT(dev)) {
 
179
                max >>= 16;
 
180
        } else {
 
181
                if (INTEL_INFO(dev)->gen < 4)
 
182
                        max >>= 17;
 
183
                else
 
184
                        max >>= 16;
 
185
 
 
186
                if (is_backlight_combination_mode(dev))
 
187
                        max *= 0xff;
 
188
        }
 
189
 
 
190
        DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
 
191
        return max;
 
192
}
 
193
 
 
194
u32 intel_panel_get_backlight(struct drm_device *dev)
 
195
{
 
196
        struct drm_i915_private *dev_priv = dev->dev_private;
 
197
        u32 val;
 
198
 
 
199
        if (HAS_PCH_SPLIT(dev)) {
 
200
                val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
 
201
        } else {
 
202
                val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
 
203
                if (INTEL_INFO(dev)->gen < 4)
 
204
                        val >>= 1;
 
205
 
 
206
                if (is_backlight_combination_mode(dev)) {
 
207
                        u8 lbpc;
 
208
 
 
209
                        pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
 
210
                        val *= lbpc;
 
211
                }
 
212
        }
 
213
 
 
214
        DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
 
215
        return val;
 
216
}
 
217
 
 
218
static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
 
219
{
 
220
        struct drm_i915_private *dev_priv = dev->dev_private;
 
221
        u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
 
222
        I915_WRITE(BLC_PWM_CPU_CTL, val | level);
 
223
}
 
224
 
 
225
static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level)
 
226
{
 
227
        struct drm_i915_private *dev_priv = dev->dev_private;
 
228
        u32 tmp;
 
229
 
 
230
        DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
 
231
 
 
232
        if (HAS_PCH_SPLIT(dev))
 
233
                return intel_pch_panel_set_backlight(dev, level);
 
234
 
 
235
        if (is_backlight_combination_mode(dev)) {
 
236
                u32 max = intel_panel_get_max_backlight(dev);
 
237
                u8 lbpc;
 
238
 
 
239
                lbpc = level * 0xfe / max + 1;
 
240
                level /= lbpc;
 
241
                pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
 
242
        }
 
243
 
 
244
        tmp = I915_READ(BLC_PWM_CTL);
 
245
        if (INTEL_INFO(dev)->gen < 4) 
 
246
                level <<= 1;
 
247
        tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
 
248
        I915_WRITE(BLC_PWM_CTL, tmp | level);
 
249
}
 
250
 
 
251
void intel_panel_set_backlight(struct drm_device *dev, u32 level)
 
252
{
 
253
        struct drm_i915_private *dev_priv = dev->dev_private;
 
254
 
 
255
        dev_priv->backlight_level = level;
 
256
        if (dev_priv->backlight_enabled)
 
257
                intel_panel_actually_set_backlight(dev, level);
 
258
}
 
259
 
 
260
void intel_panel_disable_backlight(struct drm_device *dev)
 
261
{
 
262
        struct drm_i915_private *dev_priv = dev->dev_private;
 
263
 
 
264
        dev_priv->backlight_enabled = false;
 
265
        intel_panel_actually_set_backlight(dev, 0);
 
266
}
 
267
 
 
268
void intel_panel_enable_backlight(struct drm_device *dev)
 
269
{
 
270
        struct drm_i915_private *dev_priv = dev->dev_private;
 
271
 
 
272
        if (dev_priv->backlight_level == 0)
 
273
                dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
 
274
 
 
275
        dev_priv->backlight_enabled = true;
 
276
        intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
 
277
}
 
278
 
 
279
static void intel_panel_init_backlight(struct drm_device *dev)
 
280
{
 
281
        struct drm_i915_private *dev_priv = dev->dev_private;
 
282
 
 
283
        dev_priv->backlight_level = intel_panel_get_backlight(dev);
 
284
        dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
 
285
}
 
286
 
 
287
enum drm_connector_status
 
288
intel_panel_detect(struct drm_device *dev)
 
289
{
 
290
#if 0
 
291
        struct drm_i915_private *dev_priv = dev->dev_private;
 
292
#endif
 
293
 
 
294
        if (i915_panel_ignore_lid)
 
295
                return i915_panel_ignore_lid > 0 ?
 
296
                        connector_status_connected :
 
297
                        connector_status_disconnected;
 
298
 
 
299
        /* opregion lid state on HP 2540p is wrong at boot up,
 
300
         * appears to be either the BIOS or Linux ACPI fault */
 
301
#if 0
 
302
        /* Assume that the BIOS does not lie through the OpRegion... */
 
303
        if (dev_priv->opregion.lid_state)
 
304
                return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
 
305
                        connector_status_connected :
 
306
                        connector_status_disconnected;
 
307
#endif
 
308
 
 
309
        return connector_status_unknown;
 
310
}
 
311
 
 
312
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
 
313
static int intel_panel_update_status(struct backlight_device *bd)
 
314
{
 
315
        struct drm_device *dev = bl_get_data(bd);
 
316
        intel_panel_set_backlight(dev, bd->props.brightness);
 
317
        return 0;
 
318
}
 
319
 
 
320
static int intel_panel_get_brightness(struct backlight_device *bd)
 
321
{
 
322
        struct drm_device *dev = bl_get_data(bd);
 
323
        struct drm_i915_private *dev_priv = dev->dev_private;
 
324
        return dev_priv->backlight_level;
 
325
}
 
326
 
 
327
static const struct backlight_ops intel_panel_bl_ops = {
 
328
        .update_status = intel_panel_update_status,
 
329
        .get_brightness = intel_panel_get_brightness,
 
330
};
 
331
 
 
332
int intel_panel_setup_backlight(struct drm_device *dev)
 
333
{
 
334
        struct drm_i915_private *dev_priv = dev->dev_private;
 
335
        struct backlight_properties props;
 
336
        struct drm_connector *connector;
 
337
 
 
338
        intel_panel_init_backlight(dev);
 
339
 
 
340
        if (dev_priv->int_lvds_connector)
 
341
                connector = dev_priv->int_lvds_connector;
 
342
        else if (dev_priv->int_edp_connector)
 
343
                connector = dev_priv->int_edp_connector;
 
344
        else
 
345
                return -ENODEV;
 
346
 
 
347
        props.type = BACKLIGHT_RAW;
 
348
        props.max_brightness = intel_panel_get_max_backlight(dev);
 
349
        dev_priv->backlight =
 
350
                backlight_device_register("intel_backlight",
 
351
                                          &connector->kdev, dev,
 
352
                                          &intel_panel_bl_ops, &props);
 
353
 
 
354
        if (IS_ERR(dev_priv->backlight)) {
 
355
                DRM_ERROR("Failed to register backlight: %ld\n",
 
356
                          PTR_ERR(dev_priv->backlight));
 
357
                dev_priv->backlight = NULL;
 
358
                return -ENODEV;
 
359
        }
 
360
        dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev);
 
361
        return 0;
 
362
}
 
363
 
 
364
void intel_panel_destroy_backlight(struct drm_device *dev)
 
365
{
 
366
        struct drm_i915_private *dev_priv = dev->dev_private;
 
367
        if (dev_priv->backlight)
 
368
                backlight_device_unregister(dev_priv->backlight);
 
369
}
 
370
#else
 
371
int intel_panel_setup_backlight(struct drm_device *dev)
 
372
{
 
373
        intel_panel_init_backlight(dev);
 
374
        return 0;
 
375
}
 
376
 
 
377
void intel_panel_destroy_backlight(struct drm_device *dev)
 
378
{
 
379
        return;
 
380
}
 
381
#endif