Rev 4104 | Rev 4560 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4104 | Rev 4293 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright © 2006-2010 Intel Corporation |
2 | * Copyright © 2006-2010 Intel Corporation |
3 | * Copyright (c) 2006 Dave Airlie |
3 | * Copyright (c) 2006 Dave Airlie |
4 | * |
4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * copy of this software and associated documentation files (the "Software"), |
6 | * copy of this software and associated documentation files (the "Software"), |
7 | * to deal in the Software without restriction, including without limitation |
7 | * to deal in the Software without restriction, including without limitation |
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
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 |
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: |
10 | * Software is furnished to do so, subject to the following conditions: |
11 | * |
11 | * |
12 | * The above copyright notice and this permission notice (including the next |
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 |
13 | * paragraph) shall be included in all copies or substantial portions of the |
14 | * Software. |
14 | * Software. |
15 | * |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
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, |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
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 |
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 |
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 |
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
22 | * DEALINGS IN THE SOFTWARE. |
22 | * DEALINGS IN THE SOFTWARE. |
23 | * |
23 | * |
24 | * Authors: |
24 | * Authors: |
25 | * Eric Anholt |
25 | * Eric Anholt |
26 | * Dave Airlie |
26 | * Dave Airlie |
27 | * Jesse Barnes |
27 | * Jesse Barnes |
28 | * Chris Wilson |
28 | * Chris Wilson |
29 | */ |
29 | */ |
30 | 30 | ||
31 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
31 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
32 | 32 | ||
33 | #include |
33 | #include |
34 | #include "intel_drv.h" |
34 | #include "intel_drv.h" |
35 | 35 | ||
36 | #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ |
36 | #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ |
37 | 37 | ||
38 | void |
38 | void |
39 | intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, |
39 | intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, |
40 | struct drm_display_mode *adjusted_mode) |
40 | struct drm_display_mode *adjusted_mode) |
41 | { |
41 | { |
42 | drm_mode_copy(adjusted_mode, fixed_mode); |
42 | drm_mode_copy(adjusted_mode, fixed_mode); |
43 | 43 | ||
44 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
44 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
45 | } |
45 | } |
46 | 46 | ||
47 | /* adjusted_mode has been preset to be the panel's fixed mode */ |
47 | /* adjusted_mode has been preset to be the panel's fixed mode */ |
48 | void |
48 | void |
49 | intel_pch_panel_fitting(struct intel_crtc *intel_crtc, |
49 | intel_pch_panel_fitting(struct intel_crtc *intel_crtc, |
50 | struct intel_crtc_config *pipe_config, |
50 | struct intel_crtc_config *pipe_config, |
51 | int fitting_mode) |
51 | int fitting_mode) |
52 | { |
52 | { |
53 | struct drm_display_mode *mode, *adjusted_mode; |
53 | struct drm_display_mode *mode, *adjusted_mode; |
54 | int x, y, width, height; |
54 | int x, y, width, height; |
55 | 55 | ||
56 | mode = &pipe_config->requested_mode; |
56 | mode = &pipe_config->requested_mode; |
57 | adjusted_mode = &pipe_config->adjusted_mode; |
57 | adjusted_mode = &pipe_config->adjusted_mode; |
58 | 58 | ||
59 | x = y = width = height = 0; |
59 | x = y = width = height = 0; |
60 | 60 | ||
61 | /* Native modes don't need fitting */ |
61 | /* Native modes don't need fitting */ |
62 | if (adjusted_mode->hdisplay == mode->hdisplay && |
62 | if (adjusted_mode->hdisplay == mode->hdisplay && |
63 | adjusted_mode->vdisplay == mode->vdisplay) |
63 | adjusted_mode->vdisplay == mode->vdisplay) |
64 | goto done; |
64 | goto done; |
65 | 65 | ||
66 | switch (fitting_mode) { |
66 | switch (fitting_mode) { |
67 | case DRM_MODE_SCALE_CENTER: |
67 | case DRM_MODE_SCALE_CENTER: |
68 | width = mode->hdisplay; |
68 | width = mode->hdisplay; |
69 | height = mode->vdisplay; |
69 | height = mode->vdisplay; |
70 | x = (adjusted_mode->hdisplay - width + 1)/2; |
70 | x = (adjusted_mode->hdisplay - width + 1)/2; |
71 | y = (adjusted_mode->vdisplay - height + 1)/2; |
71 | y = (adjusted_mode->vdisplay - height + 1)/2; |
72 | break; |
72 | break; |
73 | 73 | ||
74 | case DRM_MODE_SCALE_ASPECT: |
74 | case DRM_MODE_SCALE_ASPECT: |
75 | /* Scale but preserve the aspect ratio */ |
75 | /* Scale but preserve the aspect ratio */ |
76 | { |
76 | { |
77 | u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; |
77 | u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; |
78 | u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; |
78 | u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; |
79 | if (scaled_width > scaled_height) { /* pillar */ |
79 | if (scaled_width > scaled_height) { /* pillar */ |
80 | width = scaled_height / mode->vdisplay; |
80 | width = scaled_height / mode->vdisplay; |
81 | if (width & 1) |
81 | if (width & 1) |
82 | width++; |
82 | width++; |
83 | x = (adjusted_mode->hdisplay - width + 1) / 2; |
83 | x = (adjusted_mode->hdisplay - width + 1) / 2; |
84 | y = 0; |
84 | y = 0; |
85 | height = adjusted_mode->vdisplay; |
85 | height = adjusted_mode->vdisplay; |
86 | } else if (scaled_width < scaled_height) { /* letter */ |
86 | } else if (scaled_width < scaled_height) { /* letter */ |
87 | height = scaled_width / mode->hdisplay; |
87 | height = scaled_width / mode->hdisplay; |
88 | if (height & 1) |
88 | if (height & 1) |
89 | height++; |
89 | height++; |
90 | y = (adjusted_mode->vdisplay - height + 1) / 2; |
90 | y = (adjusted_mode->vdisplay - height + 1) / 2; |
91 | x = 0; |
91 | x = 0; |
92 | width = adjusted_mode->hdisplay; |
92 | width = adjusted_mode->hdisplay; |
93 | } else { |
93 | } else { |
94 | x = y = 0; |
94 | x = y = 0; |
95 | width = adjusted_mode->hdisplay; |
95 | width = adjusted_mode->hdisplay; |
96 | height = adjusted_mode->vdisplay; |
96 | height = adjusted_mode->vdisplay; |
97 | } |
97 | } |
98 | } |
98 | } |
99 | break; |
99 | break; |
100 | 100 | ||
101 | case DRM_MODE_SCALE_FULLSCREEN: |
101 | case DRM_MODE_SCALE_FULLSCREEN: |
102 | x = y = 0; |
102 | x = y = 0; |
103 | width = adjusted_mode->hdisplay; |
103 | width = adjusted_mode->hdisplay; |
104 | height = adjusted_mode->vdisplay; |
104 | height = adjusted_mode->vdisplay; |
105 | break; |
105 | break; |
106 | 106 | ||
107 | default: |
107 | default: |
108 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
108 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
109 | return; |
109 | return; |
110 | } |
110 | } |
111 | 111 | ||
112 | done: |
112 | done: |
113 | pipe_config->pch_pfit.pos = (x << 16) | y; |
113 | pipe_config->pch_pfit.pos = (x << 16) | y; |
114 | pipe_config->pch_pfit.size = (width << 16) | height; |
114 | pipe_config->pch_pfit.size = (width << 16) | height; |
115 | pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; |
115 | pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; |
116 | } |
116 | } |
117 | 117 | ||
118 | static void |
118 | static void |
119 | centre_horizontally(struct drm_display_mode *mode, |
119 | centre_horizontally(struct drm_display_mode *mode, |
120 | int width) |
120 | int width) |
121 | { |
121 | { |
122 | u32 border, sync_pos, blank_width, sync_width; |
122 | u32 border, sync_pos, blank_width, sync_width; |
123 | 123 | ||
124 | /* keep the hsync and hblank widths constant */ |
124 | /* keep the hsync and hblank widths constant */ |
125 | sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; |
125 | sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; |
126 | blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; |
126 | blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; |
127 | sync_pos = (blank_width - sync_width + 1) / 2; |
127 | sync_pos = (blank_width - sync_width + 1) / 2; |
128 | 128 | ||
129 | border = (mode->hdisplay - width + 1) / 2; |
129 | border = (mode->hdisplay - width + 1) / 2; |
130 | border += border & 1; /* make the border even */ |
130 | border += border & 1; /* make the border even */ |
131 | 131 | ||
132 | mode->crtc_hdisplay = width; |
132 | mode->crtc_hdisplay = width; |
133 | mode->crtc_hblank_start = width + border; |
133 | mode->crtc_hblank_start = width + border; |
134 | mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; |
134 | mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; |
135 | 135 | ||
136 | mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; |
136 | mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; |
137 | mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; |
137 | mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; |
138 | } |
138 | } |
139 | 139 | ||
140 | static void |
140 | static void |
141 | centre_vertically(struct drm_display_mode *mode, |
141 | centre_vertically(struct drm_display_mode *mode, |
142 | int height) |
142 | int height) |
143 | { |
143 | { |
144 | u32 border, sync_pos, blank_width, sync_width; |
144 | u32 border, sync_pos, blank_width, sync_width; |
145 | 145 | ||
146 | /* keep the vsync and vblank widths constant */ |
146 | /* keep the vsync and vblank widths constant */ |
147 | sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; |
147 | sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; |
148 | blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; |
148 | blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; |
149 | sync_pos = (blank_width - sync_width + 1) / 2; |
149 | sync_pos = (blank_width - sync_width + 1) / 2; |
150 | 150 | ||
151 | border = (mode->vdisplay - height + 1) / 2; |
151 | border = (mode->vdisplay - height + 1) / 2; |
152 | 152 | ||
153 | mode->crtc_vdisplay = height; |
153 | mode->crtc_vdisplay = height; |
154 | mode->crtc_vblank_start = height + border; |
154 | mode->crtc_vblank_start = height + border; |
155 | mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; |
155 | mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; |
156 | 156 | ||
157 | mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; |
157 | mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; |
158 | mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; |
158 | mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; |
159 | } |
159 | } |
160 | 160 | ||
161 | static inline u32 panel_fitter_scaling(u32 source, u32 target) |
161 | static inline u32 panel_fitter_scaling(u32 source, u32 target) |
162 | { |
162 | { |
163 | /* |
163 | /* |
164 | * Floating point operation is not supported. So the FACTOR |
164 | * Floating point operation is not supported. So the FACTOR |
165 | * is defined, which can avoid the floating point computation |
165 | * is defined, which can avoid the floating point computation |
166 | * when calculating the panel ratio. |
166 | * when calculating the panel ratio. |
167 | */ |
167 | */ |
168 | #define ACCURACY 12 |
168 | #define ACCURACY 12 |
169 | #define FACTOR (1 << ACCURACY) |
169 | #define FACTOR (1 << ACCURACY) |
170 | u32 ratio = source * FACTOR / target; |
170 | u32 ratio = source * FACTOR / target; |
171 | return (FACTOR * ratio + FACTOR/2) / FACTOR; |
171 | return (FACTOR * ratio + FACTOR/2) / FACTOR; |
172 | } |
172 | } |
173 | 173 | ||
174 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, |
174 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, |
175 | struct intel_crtc_config *pipe_config, |
175 | struct intel_crtc_config *pipe_config, |
176 | int fitting_mode) |
176 | int fitting_mode) |
177 | { |
177 | { |
178 | struct drm_device *dev = intel_crtc->base.dev; |
178 | struct drm_device *dev = intel_crtc->base.dev; |
179 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
179 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
180 | struct drm_display_mode *mode, *adjusted_mode; |
180 | struct drm_display_mode *mode, *adjusted_mode; |
181 | 181 | ||
182 | mode = &pipe_config->requested_mode; |
182 | mode = &pipe_config->requested_mode; |
183 | adjusted_mode = &pipe_config->adjusted_mode; |
183 | adjusted_mode = &pipe_config->adjusted_mode; |
184 | 184 | ||
185 | /* Native modes don't need fitting */ |
185 | /* Native modes don't need fitting */ |
186 | if (adjusted_mode->hdisplay == mode->hdisplay && |
186 | if (adjusted_mode->hdisplay == mode->hdisplay && |
187 | adjusted_mode->vdisplay == mode->vdisplay) |
187 | adjusted_mode->vdisplay == mode->vdisplay) |
188 | goto out; |
188 | goto out; |
189 | 189 | ||
190 | switch (fitting_mode) { |
190 | switch (fitting_mode) { |
191 | case DRM_MODE_SCALE_CENTER: |
191 | case DRM_MODE_SCALE_CENTER: |
192 | /* |
192 | /* |
193 | * For centered modes, we have to calculate border widths & |
193 | * For centered modes, we have to calculate border widths & |
194 | * heights and modify the values programmed into the CRTC. |
194 | * heights and modify the values programmed into the CRTC. |
195 | */ |
195 | */ |
196 | centre_horizontally(adjusted_mode, mode->hdisplay); |
196 | centre_horizontally(adjusted_mode, mode->hdisplay); |
197 | centre_vertically(adjusted_mode, mode->vdisplay); |
197 | centre_vertically(adjusted_mode, mode->vdisplay); |
198 | border = LVDS_BORDER_ENABLE; |
198 | border = LVDS_BORDER_ENABLE; |
199 | break; |
199 | break; |
200 | case DRM_MODE_SCALE_ASPECT: |
200 | case DRM_MODE_SCALE_ASPECT: |
201 | /* Scale but preserve the aspect ratio */ |
201 | /* Scale but preserve the aspect ratio */ |
202 | if (INTEL_INFO(dev)->gen >= 4) { |
202 | if (INTEL_INFO(dev)->gen >= 4) { |
203 | u32 scaled_width = adjusted_mode->hdisplay * |
203 | u32 scaled_width = adjusted_mode->hdisplay * |
204 | mode->vdisplay; |
204 | mode->vdisplay; |
205 | u32 scaled_height = mode->hdisplay * |
205 | u32 scaled_height = mode->hdisplay * |
206 | adjusted_mode->vdisplay; |
206 | adjusted_mode->vdisplay; |
207 | 207 | ||
208 | /* 965+ is easy, it does everything in hw */ |
208 | /* 965+ is easy, it does everything in hw */ |
209 | if (scaled_width > scaled_height) |
209 | if (scaled_width > scaled_height) |
210 | pfit_control |= PFIT_ENABLE | |
210 | pfit_control |= PFIT_ENABLE | |
211 | PFIT_SCALING_PILLAR; |
211 | PFIT_SCALING_PILLAR; |
212 | else if (scaled_width < scaled_height) |
212 | else if (scaled_width < scaled_height) |
213 | pfit_control |= PFIT_ENABLE | |
213 | pfit_control |= PFIT_ENABLE | |
214 | PFIT_SCALING_LETTER; |
214 | PFIT_SCALING_LETTER; |
215 | else if (adjusted_mode->hdisplay != mode->hdisplay) |
215 | else if (adjusted_mode->hdisplay != mode->hdisplay) |
216 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; |
216 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; |
217 | } else { |
217 | } else { |
218 | u32 scaled_width = adjusted_mode->hdisplay * |
218 | u32 scaled_width = adjusted_mode->hdisplay * |
219 | mode->vdisplay; |
219 | mode->vdisplay; |
220 | u32 scaled_height = mode->hdisplay * |
220 | u32 scaled_height = mode->hdisplay * |
221 | adjusted_mode->vdisplay; |
221 | adjusted_mode->vdisplay; |
222 | /* |
222 | /* |
223 | * For earlier chips we have to calculate the scaling |
223 | * For earlier chips we have to calculate the scaling |
224 | * ratio by hand and program it into the |
224 | * ratio by hand and program it into the |
225 | * PFIT_PGM_RATIO register |
225 | * PFIT_PGM_RATIO register |
226 | */ |
226 | */ |
227 | if (scaled_width > scaled_height) { /* pillar */ |
227 | if (scaled_width > scaled_height) { /* pillar */ |
228 | centre_horizontally(adjusted_mode, |
228 | centre_horizontally(adjusted_mode, |
229 | scaled_height / |
229 | scaled_height / |
230 | mode->vdisplay); |
230 | mode->vdisplay); |
231 | 231 | ||
232 | border = LVDS_BORDER_ENABLE; |
232 | border = LVDS_BORDER_ENABLE; |
233 | if (mode->vdisplay != adjusted_mode->vdisplay) { |
233 | if (mode->vdisplay != adjusted_mode->vdisplay) { |
234 | u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); |
234 | u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); |
235 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
235 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
236 | bits << PFIT_VERT_SCALE_SHIFT); |
236 | bits << PFIT_VERT_SCALE_SHIFT); |
237 | pfit_control |= (PFIT_ENABLE | |
237 | pfit_control |= (PFIT_ENABLE | |
238 | VERT_INTERP_BILINEAR | |
238 | VERT_INTERP_BILINEAR | |
239 | HORIZ_INTERP_BILINEAR); |
239 | HORIZ_INTERP_BILINEAR); |
240 | } |
240 | } |
241 | } else if (scaled_width < scaled_height) { /* letter */ |
241 | } else if (scaled_width < scaled_height) { /* letter */ |
242 | centre_vertically(adjusted_mode, |
242 | centre_vertically(adjusted_mode, |
243 | scaled_width / |
243 | scaled_width / |
244 | mode->hdisplay); |
244 | mode->hdisplay); |
245 | 245 | ||
246 | border = LVDS_BORDER_ENABLE; |
246 | border = LVDS_BORDER_ENABLE; |
247 | if (mode->hdisplay != adjusted_mode->hdisplay) { |
247 | if (mode->hdisplay != adjusted_mode->hdisplay) { |
248 | u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); |
248 | u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); |
249 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
249 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
250 | bits << PFIT_VERT_SCALE_SHIFT); |
250 | bits << PFIT_VERT_SCALE_SHIFT); |
251 | pfit_control |= (PFIT_ENABLE | |
251 | pfit_control |= (PFIT_ENABLE | |
252 | VERT_INTERP_BILINEAR | |
252 | VERT_INTERP_BILINEAR | |
253 | HORIZ_INTERP_BILINEAR); |
253 | HORIZ_INTERP_BILINEAR); |
254 | } |
254 | } |
255 | } else { |
255 | } else { |
256 | /* Aspects match, Let hw scale both directions */ |
256 | /* Aspects match, Let hw scale both directions */ |
257 | pfit_control |= (PFIT_ENABLE | |
257 | pfit_control |= (PFIT_ENABLE | |
258 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | |
258 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | |
259 | VERT_INTERP_BILINEAR | |
259 | VERT_INTERP_BILINEAR | |
260 | HORIZ_INTERP_BILINEAR); |
260 | HORIZ_INTERP_BILINEAR); |
261 | } |
261 | } |
262 | } |
262 | } |
263 | break; |
263 | break; |
264 | case DRM_MODE_SCALE_FULLSCREEN: |
264 | case DRM_MODE_SCALE_FULLSCREEN: |
265 | /* |
265 | /* |
266 | * Full scaling, even if it changes the aspect ratio. |
266 | * Full scaling, even if it changes the aspect ratio. |
267 | * Fortunately this is all done for us in hw. |
267 | * Fortunately this is all done for us in hw. |
268 | */ |
268 | */ |
269 | if (mode->vdisplay != adjusted_mode->vdisplay || |
269 | if (mode->vdisplay != adjusted_mode->vdisplay || |
270 | mode->hdisplay != adjusted_mode->hdisplay) { |
270 | mode->hdisplay != adjusted_mode->hdisplay) { |
271 | pfit_control |= PFIT_ENABLE; |
271 | pfit_control |= PFIT_ENABLE; |
272 | if (INTEL_INFO(dev)->gen >= 4) |
272 | if (INTEL_INFO(dev)->gen >= 4) |
273 | pfit_control |= PFIT_SCALING_AUTO; |
273 | pfit_control |= PFIT_SCALING_AUTO; |
274 | else |
274 | else |
275 | pfit_control |= (VERT_AUTO_SCALE | |
275 | pfit_control |= (VERT_AUTO_SCALE | |
276 | VERT_INTERP_BILINEAR | |
276 | VERT_INTERP_BILINEAR | |
277 | HORIZ_AUTO_SCALE | |
277 | HORIZ_AUTO_SCALE | |
278 | HORIZ_INTERP_BILINEAR); |
278 | HORIZ_INTERP_BILINEAR); |
279 | } |
279 | } |
280 | break; |
280 | break; |
281 | default: |
281 | default: |
282 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
282 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
283 | return; |
283 | return; |
284 | } |
284 | } |
285 | 285 | ||
286 | /* 965+ wants fuzzy fitting */ |
286 | /* 965+ wants fuzzy fitting */ |
287 | /* FIXME: handle multiple panels by failing gracefully */ |
287 | /* FIXME: handle multiple panels by failing gracefully */ |
288 | if (INTEL_INFO(dev)->gen >= 4) |
288 | if (INTEL_INFO(dev)->gen >= 4) |
289 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | |
289 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | |
290 | PFIT_FILTER_FUZZY); |
290 | PFIT_FILTER_FUZZY); |
291 | 291 | ||
292 | out: |
292 | out: |
293 | if ((pfit_control & PFIT_ENABLE) == 0) { |
293 | if ((pfit_control & PFIT_ENABLE) == 0) { |
294 | pfit_control = 0; |
294 | pfit_control = 0; |
295 | pfit_pgm_ratios = 0; |
295 | pfit_pgm_ratios = 0; |
296 | } |
296 | } |
297 | 297 | ||
298 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ |
298 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ |
299 | if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) |
299 | if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) |
300 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
300 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
301 | 301 | ||
302 | pipe_config->gmch_pfit.control = pfit_control; |
302 | pipe_config->gmch_pfit.control = pfit_control; |
303 | pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; |
303 | pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; |
304 | pipe_config->gmch_pfit.lvds_border_bits = border; |
304 | pipe_config->gmch_pfit.lvds_border_bits = border; |
305 | } |
305 | } |
306 | 306 | ||
307 | static int is_backlight_combination_mode(struct drm_device *dev) |
307 | static int is_backlight_combination_mode(struct drm_device *dev) |
308 | { |
308 | { |
309 | struct drm_i915_private *dev_priv = dev->dev_private; |
309 | struct drm_i915_private *dev_priv = dev->dev_private; |
310 | 310 | ||
311 | if (INTEL_INFO(dev)->gen >= 4) |
311 | if (INTEL_INFO(dev)->gen >= 4) |
312 | return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; |
312 | return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; |
313 | 313 | ||
314 | if (IS_GEN2(dev)) |
314 | if (IS_GEN2(dev)) |
315 | return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; |
315 | return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; |
316 | 316 | ||
317 | return 0; |
317 | return 0; |
318 | } |
318 | } |
319 | 319 | ||
320 | /* XXX: query mode clock or hardware clock and program max PWM appropriately |
320 | /* XXX: query mode clock or hardware clock and program max PWM appropriately |
321 | * when it's 0. |
321 | * when it's 0. |
322 | */ |
322 | */ |
323 | static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) |
323 | static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) |
324 | { |
324 | { |
325 | struct drm_i915_private *dev_priv = dev->dev_private; |
325 | struct drm_i915_private *dev_priv = dev->dev_private; |
326 | u32 val; |
326 | u32 val; |
327 | 327 | ||
328 | // WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock)); |
328 | // WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock)); |
329 | 329 | ||
330 | /* Restore the CTL value if it lost, e.g. GPU reset */ |
330 | /* Restore the CTL value if it lost, e.g. GPU reset */ |
331 | 331 | ||
332 | if (HAS_PCH_SPLIT(dev_priv->dev)) { |
332 | if (HAS_PCH_SPLIT(dev_priv->dev)) { |
333 | val = I915_READ(BLC_PWM_PCH_CTL2); |
333 | val = I915_READ(BLC_PWM_PCH_CTL2); |
334 | if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { |
334 | if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { |
335 | dev_priv->regfile.saveBLC_PWM_CTL2 = val; |
335 | dev_priv->regfile.saveBLC_PWM_CTL2 = val; |
336 | } else if (val == 0) { |
336 | } else if (val == 0) { |
337 | val = dev_priv->regfile.saveBLC_PWM_CTL2; |
337 | val = dev_priv->regfile.saveBLC_PWM_CTL2; |
338 | I915_WRITE(BLC_PWM_PCH_CTL2, val); |
338 | I915_WRITE(BLC_PWM_PCH_CTL2, val); |
339 | } |
339 | } |
340 | } else { |
340 | } else { |
341 | val = I915_READ(BLC_PWM_CTL); |
341 | val = I915_READ(BLC_PWM_CTL); |
342 | if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { |
342 | if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { |
343 | dev_priv->regfile.saveBLC_PWM_CTL = val; |
343 | dev_priv->regfile.saveBLC_PWM_CTL = val; |
344 | if (INTEL_INFO(dev)->gen >= 4) |
344 | if (INTEL_INFO(dev)->gen >= 4) |
345 | dev_priv->regfile.saveBLC_PWM_CTL2 = |
345 | dev_priv->regfile.saveBLC_PWM_CTL2 = |
346 | I915_READ(BLC_PWM_CTL2); |
346 | I915_READ(BLC_PWM_CTL2); |
347 | } else if (val == 0) { |
347 | } else if (val == 0) { |
348 | val = dev_priv->regfile.saveBLC_PWM_CTL; |
348 | val = dev_priv->regfile.saveBLC_PWM_CTL; |
349 | I915_WRITE(BLC_PWM_CTL, val); |
349 | I915_WRITE(BLC_PWM_CTL, val); |
350 | if (INTEL_INFO(dev)->gen >= 4) |
350 | if (INTEL_INFO(dev)->gen >= 4) |
351 | I915_WRITE(BLC_PWM_CTL2, |
351 | I915_WRITE(BLC_PWM_CTL2, |
352 | dev_priv->regfile.saveBLC_PWM_CTL2); |
352 | dev_priv->regfile.saveBLC_PWM_CTL2); |
353 | } |
353 | } |
354 | } |
354 | } |
355 | 355 | ||
356 | return val; |
356 | return val; |
357 | } |
357 | } |
358 | 358 | ||
359 | static u32 intel_panel_get_max_backlight(struct drm_device *dev) |
359 | static u32 intel_panel_get_max_backlight(struct drm_device *dev) |
360 | { |
360 | { |
361 | u32 max; |
361 | u32 max; |
362 | 362 | ||
363 | max = i915_read_blc_pwm_ctl(dev); |
363 | max = i915_read_blc_pwm_ctl(dev); |
364 | 364 | ||
365 | if (HAS_PCH_SPLIT(dev)) { |
365 | if (HAS_PCH_SPLIT(dev)) { |
366 | max >>= 16; |
366 | max >>= 16; |
367 | } else { |
367 | } else { |
368 | if (INTEL_INFO(dev)->gen < 4) |
368 | if (INTEL_INFO(dev)->gen < 4) |
369 | max >>= 17; |
369 | max >>= 17; |
370 | else |
370 | else |
371 | max >>= 16; |
371 | max >>= 16; |
372 | 372 | ||
373 | if (is_backlight_combination_mode(dev)) |
373 | if (is_backlight_combination_mode(dev)) |
374 | max *= 0xff; |
374 | max *= 0xff; |
375 | } |
375 | } |
376 | 376 | ||
377 | DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); |
377 | DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); |
378 | 378 | ||
379 | return max; |
379 | return max; |
380 | } |
380 | } |
381 | 381 | ||
382 | static int i915_panel_invert_brightness; |
382 | static int i915_panel_invert_brightness; |
383 | MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " |
383 | MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " |
384 | "(-1 force normal, 0 machine defaults, 1 force inversion), please " |
384 | "(-1 force normal, 0 machine defaults, 1 force inversion), please " |
385 | "report PCI device ID, subsystem vendor and subsystem device ID " |
385 | "report PCI device ID, subsystem vendor and subsystem device ID " |
386 | "to dri-devel@lists.freedesktop.org, if your machine needs it. " |
386 | "to dri-devel@lists.freedesktop.org, if your machine needs it. " |
387 | "It will then be included in an upcoming module version."); |
387 | "It will then be included in an upcoming module version."); |
388 | module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); |
388 | module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); |
389 | static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) |
389 | static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) |
390 | { |
390 | { |
391 | struct drm_i915_private *dev_priv = dev->dev_private; |
391 | struct drm_i915_private *dev_priv = dev->dev_private; |
392 | 392 | ||
393 | if (i915_panel_invert_brightness < 0) |
393 | if (i915_panel_invert_brightness < 0) |
394 | return val; |
394 | return val; |
395 | 395 | ||
396 | if (i915_panel_invert_brightness > 0 || |
396 | if (i915_panel_invert_brightness > 0 || |
397 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { |
397 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { |
398 | u32 max = intel_panel_get_max_backlight(dev); |
398 | u32 max = intel_panel_get_max_backlight(dev); |
399 | if (max) |
399 | if (max) |
400 | return max - val; |
400 | return max - val; |
401 | } |
401 | } |
402 | 402 | ||
403 | return val; |
403 | return val; |
404 | } |
404 | } |
405 | 405 | ||
406 | static u32 intel_panel_get_backlight(struct drm_device *dev) |
406 | static u32 intel_panel_get_backlight(struct drm_device *dev) |
407 | { |
407 | { |
408 | struct drm_i915_private *dev_priv = dev->dev_private; |
408 | struct drm_i915_private *dev_priv = dev->dev_private; |
409 | u32 val; |
409 | u32 val; |
410 | unsigned long flags; |
410 | unsigned long flags; |
411 | 411 | ||
412 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
412 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
413 | 413 | ||
414 | if (HAS_PCH_SPLIT(dev)) { |
414 | if (HAS_PCH_SPLIT(dev)) { |
415 | val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
415 | val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
416 | } else { |
416 | } else { |
417 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
417 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
418 | if (INTEL_INFO(dev)->gen < 4) |
418 | if (INTEL_INFO(dev)->gen < 4) |
419 | val >>= 1; |
419 | val >>= 1; |
420 | 420 | ||
421 | if (is_backlight_combination_mode(dev)) { |
421 | if (is_backlight_combination_mode(dev)) { |
422 | u8 lbpc; |
422 | u8 lbpc; |
423 | 423 | ||
424 | pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); |
424 | pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); |
425 | val *= lbpc; |
425 | val *= lbpc; |
426 | } |
426 | } |
427 | } |
427 | } |
428 | 428 | ||
429 | val = intel_panel_compute_brightness(dev, val); |
429 | val = intel_panel_compute_brightness(dev, val); |
430 | 430 | ||
431 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
431 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
432 | 432 | ||
433 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
433 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
434 | return val; |
434 | return val; |
435 | } |
435 | } |
436 | 436 | ||
437 | static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) |
437 | static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) |
438 | { |
438 | { |
439 | struct drm_i915_private *dev_priv = dev->dev_private; |
439 | struct drm_i915_private *dev_priv = dev->dev_private; |
440 | u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
440 | u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
441 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); |
441 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); |
442 | } |
442 | } |
443 | 443 | ||
444 | static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) |
444 | static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) |
445 | { |
445 | { |
446 | struct drm_i915_private *dev_priv = dev->dev_private; |
446 | struct drm_i915_private *dev_priv = dev->dev_private; |
447 | u32 tmp; |
447 | u32 tmp; |
448 | 448 | ||
449 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); |
449 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); |
450 | level = intel_panel_compute_brightness(dev, level); |
450 | level = intel_panel_compute_brightness(dev, level); |
451 | 451 | ||
452 | if (HAS_PCH_SPLIT(dev)) |
452 | if (HAS_PCH_SPLIT(dev)) |
453 | return intel_pch_panel_set_backlight(dev, level); |
453 | return intel_pch_panel_set_backlight(dev, level); |
454 | 454 | ||
455 | if (is_backlight_combination_mode(dev)) { |
455 | if (is_backlight_combination_mode(dev)) { |
456 | u32 max = intel_panel_get_max_backlight(dev); |
456 | u32 max = intel_panel_get_max_backlight(dev); |
457 | u8 lbpc; |
457 | u8 lbpc; |
458 | 458 | ||
459 | /* we're screwed, but keep behaviour backwards compatible */ |
459 | /* we're screwed, but keep behaviour backwards compatible */ |
460 | if (!max) |
460 | if (!max) |
461 | max = 1; |
461 | max = 1; |
462 | 462 | ||
463 | lbpc = level * 0xfe / max + 1; |
463 | lbpc = level * 0xfe / max + 1; |
464 | level /= lbpc; |
464 | level /= lbpc; |
465 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); |
465 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); |
466 | } |
466 | } |
467 | 467 | ||
468 | tmp = I915_READ(BLC_PWM_CTL); |
468 | tmp = I915_READ(BLC_PWM_CTL); |
469 | if (INTEL_INFO(dev)->gen < 4) |
469 | if (INTEL_INFO(dev)->gen < 4) |
470 | level <<= 1; |
470 | level <<= 1; |
471 | tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; |
471 | tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; |
472 | I915_WRITE(BLC_PWM_CTL, tmp | level); |
472 | I915_WRITE(BLC_PWM_CTL, tmp | level); |
473 | } |
473 | } |
474 | 474 | ||
475 | /* set backlight brightness to level in range [0..max] */ |
475 | /* set backlight brightness to level in range [0..max] */ |
476 | void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) |
476 | void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) |
477 | { |
477 | { |
478 | struct drm_i915_private *dev_priv = dev->dev_private; |
478 | struct drm_i915_private *dev_priv = dev->dev_private; |
479 | 479 | ||
480 | dev_priv->backlight.level = level; |
480 | dev_priv->backlight.level = level; |
481 | // if (dev_priv->backlight.device) |
481 | // if (dev_priv->backlight.device) |
482 | // dev_priv->backlight.device->props.brightness = level; |
482 | // dev_priv->backlight.device->props.brightness = level; |
483 | 483 | ||
484 | // if (dev_priv->backlight.enabled) |
484 | // if (dev_priv->backlight.enabled) |
485 | // intel_panel_actually_set_backlight(dev, level); |
485 | // intel_panel_actually_set_backlight(dev, level); |
486 | } |
486 | } |
487 | 487 | ||
488 | void intel_panel_disable_backlight(struct drm_device *dev) |
488 | void intel_panel_disable_backlight(struct drm_device *dev) |
489 | { |
489 | { |
490 | struct drm_i915_private *dev_priv = dev->dev_private; |
490 | struct drm_i915_private *dev_priv = dev->dev_private; |
491 | unsigned long flags; |
491 | unsigned long flags; |
- | 492 | ||
- | 493 | /* |
|
- | 494 | * Do not disable backlight on the vgaswitcheroo path. When switching |
|
- | 495 | * away from i915, the other client may depend on i915 to handle the |
|
- | 496 | * backlight. This will leave the backlight on unnecessarily when |
|
- | 497 | * another client is not activated. |
|
- | 498 | */ |
|
- | 499 | if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { |
|
- | 500 | DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); |
|
- | 501 | return; |
|
- | 502 | } |
|
492 | 503 | ||
493 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
504 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
494 | 505 | ||
495 | dev_priv->backlight.enabled = false; |
506 | dev_priv->backlight.enabled = false; |
496 | intel_panel_actually_set_backlight(dev, 0); |
507 | intel_panel_actually_set_backlight(dev, 0); |
497 | 508 | ||
498 | if (INTEL_INFO(dev)->gen >= 4) { |
509 | if (INTEL_INFO(dev)->gen >= 4) { |
499 | uint32_t reg, tmp; |
510 | uint32_t reg, tmp; |
500 | 511 | ||
501 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; |
512 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; |
502 | 513 | ||
503 | I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE); |
514 | I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE); |
504 | 515 | ||
505 | if (HAS_PCH_SPLIT(dev)) { |
516 | if (HAS_PCH_SPLIT(dev)) { |
506 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
517 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
507 | tmp &= ~BLM_PCH_PWM_ENABLE; |
518 | tmp &= ~BLM_PCH_PWM_ENABLE; |
508 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
519 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
509 | } |
520 | } |
510 | } |
521 | } |
511 | 522 | ||
512 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
523 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
513 | } |
524 | } |
514 | 525 | ||
515 | void intel_panel_enable_backlight(struct drm_device *dev, |
526 | void intel_panel_enable_backlight(struct drm_device *dev, |
516 | enum pipe pipe) |
527 | enum pipe pipe) |
517 | { |
528 | { |
518 | struct drm_i915_private *dev_priv = dev->dev_private; |
529 | struct drm_i915_private *dev_priv = dev->dev_private; |
519 | enum transcoder cpu_transcoder = |
530 | enum transcoder cpu_transcoder = |
520 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
531 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
521 | unsigned long flags; |
532 | unsigned long flags; |
522 | 533 | ||
523 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
534 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
524 | 535 | ||
525 | if (dev_priv->backlight.level == 0) { |
536 | if (dev_priv->backlight.level == 0) { |
526 | dev_priv->backlight.level = intel_panel_get_max_backlight(dev); |
537 | dev_priv->backlight.level = intel_panel_get_max_backlight(dev); |
527 | // if (dev_priv->backlight.device) |
538 | // if (dev_priv->backlight.device) |
528 | // dev_priv->backlight.device->props.brightness = |
539 | // dev_priv->backlight.device->props.brightness = |
529 | // dev_priv->backlight.level; |
540 | // dev_priv->backlight.level; |
530 | } |
541 | } |
531 | 542 | ||
532 | if (INTEL_INFO(dev)->gen >= 4) { |
543 | if (INTEL_INFO(dev)->gen >= 4) { |
533 | uint32_t reg, tmp; |
544 | uint32_t reg, tmp; |
534 | 545 | ||
535 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; |
546 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; |
536 | 547 | ||
537 | 548 | ||
538 | tmp = I915_READ(reg); |
549 | tmp = I915_READ(reg); |
539 | 550 | ||
540 | /* Note that this can also get called through dpms changes. And |
551 | /* Note that this can also get called through dpms changes. And |
541 | * we don't track the backlight dpms state, hence check whether |
552 | * we don't track the backlight dpms state, hence check whether |
542 | * we have to do anything first. */ |
553 | * we have to do anything first. */ |
543 | if (tmp & BLM_PWM_ENABLE) |
554 | if (tmp & BLM_PWM_ENABLE) |
544 | goto set_level; |
555 | goto set_level; |
545 | 556 | ||
546 | if (INTEL_INFO(dev)->num_pipes == 3) |
557 | if (INTEL_INFO(dev)->num_pipes == 3) |
547 | tmp &= ~BLM_PIPE_SELECT_IVB; |
558 | tmp &= ~BLM_PIPE_SELECT_IVB; |
548 | else |
559 | else |
549 | tmp &= ~BLM_PIPE_SELECT; |
560 | tmp &= ~BLM_PIPE_SELECT; |
550 | 561 | ||
551 | if (cpu_transcoder == TRANSCODER_EDP) |
562 | if (cpu_transcoder == TRANSCODER_EDP) |
552 | tmp |= BLM_TRANSCODER_EDP; |
563 | tmp |= BLM_TRANSCODER_EDP; |
553 | else |
564 | else |
554 | tmp |= BLM_PIPE(cpu_transcoder); |
565 | tmp |= BLM_PIPE(cpu_transcoder); |
555 | tmp &= ~BLM_PWM_ENABLE; |
566 | tmp &= ~BLM_PWM_ENABLE; |
556 | 567 | ||
557 | I915_WRITE(reg, tmp); |
568 | I915_WRITE(reg, tmp); |
558 | POSTING_READ(reg); |
569 | POSTING_READ(reg); |
559 | I915_WRITE(reg, tmp | BLM_PWM_ENABLE); |
570 | I915_WRITE(reg, tmp | BLM_PWM_ENABLE); |
560 | 571 | ||
561 | if (HAS_PCH_SPLIT(dev) && |
572 | if (HAS_PCH_SPLIT(dev) && |
562 | !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { |
573 | !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { |
563 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
574 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
564 | tmp |= BLM_PCH_PWM_ENABLE; |
575 | tmp |= BLM_PCH_PWM_ENABLE; |
565 | tmp &= ~BLM_PCH_OVERRIDE_ENABLE; |
576 | tmp &= ~BLM_PCH_OVERRIDE_ENABLE; |
566 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
577 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
567 | } |
578 | } |
568 | } |
579 | } |
569 | 580 | ||
570 | set_level: |
581 | set_level: |
571 | /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. |
582 | /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. |
572 | * BLC_PWM_CPU_CTL may be cleared to zero automatically when these |
583 | * BLC_PWM_CPU_CTL may be cleared to zero automatically when these |
573 | * registers are set. |
584 | * registers are set. |
574 | */ |
585 | */ |
575 | dev_priv->backlight.enabled = true; |
586 | dev_priv->backlight.enabled = true; |
576 | intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); |
587 | intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); |
577 | 588 | ||
578 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
589 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
579 | } |
590 | } |
580 | 591 | ||
581 | static void intel_panel_init_backlight(struct drm_device *dev) |
592 | static void intel_panel_init_backlight(struct drm_device *dev) |
582 | { |
593 | { |
583 | struct drm_i915_private *dev_priv = dev->dev_private; |
594 | struct drm_i915_private *dev_priv = dev->dev_private; |
584 | 595 | ||
585 | dev_priv->backlight.level = intel_panel_get_backlight(dev); |
596 | dev_priv->backlight.level = intel_panel_get_backlight(dev); |
586 | dev_priv->backlight.enabled = dev_priv->backlight.level != 0; |
597 | dev_priv->backlight.enabled = dev_priv->backlight.level != 0; |
587 | } |
598 | } |
588 | 599 | ||
589 | enum drm_connector_status |
600 | enum drm_connector_status |
590 | intel_panel_detect(struct drm_device *dev) |
601 | intel_panel_detect(struct drm_device *dev) |
591 | { |
602 | { |
592 | struct drm_i915_private *dev_priv = dev->dev_private; |
603 | struct drm_i915_private *dev_priv = dev->dev_private; |
593 | 604 | ||
594 | /* Assume that the BIOS does not lie through the OpRegion... */ |
605 | /* Assume that the BIOS does not lie through the OpRegion... */ |
595 | if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) { |
606 | if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) { |
596 | return ioread32(dev_priv->opregion.lid_state) & 0x1 ? |
607 | return ioread32(dev_priv->opregion.lid_state) & 0x1 ? |
597 | connector_status_connected : |
608 | connector_status_connected : |
598 | connector_status_disconnected; |
609 | connector_status_disconnected; |
599 | } |
610 | } |
600 | 611 | ||
601 | switch (i915_panel_ignore_lid) { |
612 | switch (i915_panel_ignore_lid) { |
602 | case -2: |
613 | case -2: |
603 | return connector_status_connected; |
614 | return connector_status_connected; |
604 | case -1: |
615 | case -1: |
605 | return connector_status_disconnected; |
616 | return connector_status_disconnected; |
606 | default: |
617 | default: |
607 | return connector_status_unknown; |
618 | return connector_status_unknown; |
608 | } |
619 | } |
609 | } |
620 | } |
610 | 621 | ||
611 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE |
622 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE |
612 | static int intel_panel_update_status(struct backlight_device *bd) |
623 | static int intel_panel_update_status(struct backlight_device *bd) |
613 | { |
624 | { |
614 | struct drm_device *dev = bl_get_data(bd); |
625 | struct drm_device *dev = bl_get_data(bd); |
615 | intel_panel_set_backlight(dev, bd->props.brightness, |
626 | intel_panel_set_backlight(dev, bd->props.brightness, |
616 | bd->props.max_brightness); |
627 | bd->props.max_brightness); |
617 | return 0; |
628 | return 0; |
618 | } |
629 | } |
619 | 630 | ||
620 | static int intel_panel_get_brightness(struct backlight_device *bd) |
631 | static int intel_panel_get_brightness(struct backlight_device *bd) |
621 | { |
632 | { |
622 | struct drm_device *dev = bl_get_data(bd); |
633 | struct drm_device *dev = bl_get_data(bd); |
623 | return intel_panel_get_backlight(dev); |
634 | return intel_panel_get_backlight(dev); |
624 | } |
635 | } |
625 | 636 | ||
626 | static const struct backlight_ops intel_panel_bl_ops = { |
637 | static const struct backlight_ops intel_panel_bl_ops = { |
627 | .update_status = intel_panel_update_status, |
638 | .update_status = intel_panel_update_status, |
628 | .get_brightness = intel_panel_get_brightness, |
639 | .get_brightness = intel_panel_get_brightness, |
629 | }; |
640 | }; |
630 | 641 | ||
631 | int intel_panel_setup_backlight(struct drm_connector *connector) |
642 | int intel_panel_setup_backlight(struct drm_connector *connector) |
632 | { |
643 | { |
633 | struct drm_device *dev = connector->dev; |
644 | struct drm_device *dev = connector->dev; |
634 | struct drm_i915_private *dev_priv = dev->dev_private; |
645 | struct drm_i915_private *dev_priv = dev->dev_private; |
635 | struct backlight_properties props; |
646 | struct backlight_properties props; |
636 | unsigned long flags; |
647 | unsigned long flags; |
637 | 648 | ||
638 | intel_panel_init_backlight(dev); |
649 | intel_panel_init_backlight(dev); |
639 | 650 | ||
640 | if (WARN_ON(dev_priv->backlight.device)) |
651 | if (WARN_ON(dev_priv->backlight.device)) |
641 | return -ENODEV; |
652 | return -ENODEV; |
642 | 653 | ||
643 | memset(&props, 0, sizeof(props)); |
654 | memset(&props, 0, sizeof(props)); |
644 | props.type = BACKLIGHT_RAW; |
655 | props.type = BACKLIGHT_RAW; |
645 | props.brightness = dev_priv->backlight.level; |
656 | props.brightness = dev_priv->backlight.level; |
646 | 657 | ||
647 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
658 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
648 | props.max_brightness = intel_panel_get_max_backlight(dev); |
659 | props.max_brightness = intel_panel_get_max_backlight(dev); |
649 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
660 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
650 | 661 | ||
651 | if (props.max_brightness == 0) { |
662 | if (props.max_brightness == 0) { |
652 | DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); |
663 | DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); |
653 | return -ENODEV; |
664 | return -ENODEV; |
654 | } |
665 | } |
655 | dev_priv->backlight.device = |
666 | dev_priv->backlight.device = |
656 | backlight_device_register("intel_backlight", |
667 | backlight_device_register("intel_backlight", |
657 | &connector->kdev, dev, |
668 | &connector->kdev, dev, |
658 | &intel_panel_bl_ops, &props); |
669 | &intel_panel_bl_ops, &props); |
659 | 670 | ||
660 | if (IS_ERR(dev_priv->backlight.device)) { |
671 | if (IS_ERR(dev_priv->backlight.device)) { |
661 | DRM_ERROR("Failed to register backlight: %ld\n", |
672 | DRM_ERROR("Failed to register backlight: %ld\n", |
662 | PTR_ERR(dev_priv->backlight.device)); |
673 | PTR_ERR(dev_priv->backlight.device)); |
663 | dev_priv->backlight.device = NULL; |
674 | dev_priv->backlight.device = NULL; |
664 | return -ENODEV; |
675 | return -ENODEV; |
665 | } |
676 | } |
666 | return 0; |
677 | return 0; |
667 | } |
678 | } |
668 | 679 | ||
669 | void intel_panel_destroy_backlight(struct drm_device *dev) |
680 | void intel_panel_destroy_backlight(struct drm_device *dev) |
670 | { |
681 | { |
671 | struct drm_i915_private *dev_priv = dev->dev_private; |
682 | struct drm_i915_private *dev_priv = dev->dev_private; |
672 | if (dev_priv->backlight.device) { |
683 | if (dev_priv->backlight.device) { |
673 | backlight_device_unregister(dev_priv->backlight.device); |
684 | backlight_device_unregister(dev_priv->backlight.device); |
674 | dev_priv->backlight.device = NULL; |
685 | dev_priv->backlight.device = NULL; |
675 | } |
686 | } |
676 | } |
687 | } |
677 | #else |
688 | #else |
678 | int intel_panel_setup_backlight(struct drm_connector *connector) |
689 | int intel_panel_setup_backlight(struct drm_connector *connector) |
679 | { |
690 | { |
680 | intel_panel_init_backlight(connector->dev); |
691 | intel_panel_init_backlight(connector->dev); |
681 | return 0; |
692 | return 0; |
682 | } |
693 | } |
683 | 694 | ||
684 | void intel_panel_destroy_backlight(struct drm_device *dev) |
695 | void intel_panel_destroy_backlight(struct drm_device *dev) |
685 | { |
696 | { |
686 | return; |
697 | return; |
687 | } |
698 | } |
688 | #endif |
699 | #endif |
689 | 700 | ||
690 | int intel_panel_init(struct intel_panel *panel, |
701 | int intel_panel_init(struct intel_panel *panel, |
691 | struct drm_display_mode *fixed_mode) |
702 | struct drm_display_mode *fixed_mode) |
692 | { |
703 | { |
693 | panel->fixed_mode = fixed_mode; |
704 | panel->fixed_mode = fixed_mode; |
694 | 705 | ||
695 | return 0; |
706 | return 0; |
696 | } |
707 | } |
697 | 708 | ||
698 | void intel_panel_fini(struct intel_panel *panel) |
709 | void intel_panel_fini(struct intel_panel *panel) |
699 | { |
710 | { |
700 | struct intel_connector *intel_connector = |
711 | struct intel_connector *intel_connector = |
701 | container_of(panel, struct intel_connector, panel); |
712 | container_of(panel, struct intel_connector, panel); |
702 | 713 | ||
703 | if (panel->fixed_mode) |
714 | if (panel->fixed_mode) |
704 | drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); |
715 | drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); |
705 | }=><=>>>>>>><>><>><>>><>><>>><>><>><>> |
716 | }=><=>>>>>>><>><>><>>><>><>>><>><>><>> |