Rev 4293 | Rev 5060 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4293 | Rev 4560 | ||
---|---|---|---|
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 *adjusted_mode; |
54 | int x, y, width, height; |
54 | int x, y, width, height; |
55 | - | ||
56 | mode = &pipe_config->requested_mode; |
55 | |
57 | adjusted_mode = &pipe_config->adjusted_mode; |
56 | adjusted_mode = &pipe_config->adjusted_mode; |
58 | 57 | ||
59 | x = y = width = height = 0; |
58 | x = y = width = height = 0; |
60 | 59 | ||
61 | /* Native modes don't need fitting */ |
60 | /* Native modes don't need fitting */ |
62 | if (adjusted_mode->hdisplay == mode->hdisplay && |
61 | if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && |
63 | adjusted_mode->vdisplay == mode->vdisplay) |
62 | adjusted_mode->vdisplay == pipe_config->pipe_src_h) |
64 | goto done; |
63 | goto done; |
65 | 64 | ||
66 | switch (fitting_mode) { |
65 | switch (fitting_mode) { |
67 | case DRM_MODE_SCALE_CENTER: |
66 | case DRM_MODE_SCALE_CENTER: |
68 | width = mode->hdisplay; |
67 | width = pipe_config->pipe_src_w; |
69 | height = mode->vdisplay; |
68 | height = pipe_config->pipe_src_h; |
70 | x = (adjusted_mode->hdisplay - width + 1)/2; |
69 | x = (adjusted_mode->hdisplay - width + 1)/2; |
71 | y = (adjusted_mode->vdisplay - height + 1)/2; |
70 | y = (adjusted_mode->vdisplay - height + 1)/2; |
72 | break; |
71 | break; |
73 | 72 | ||
74 | case DRM_MODE_SCALE_ASPECT: |
73 | case DRM_MODE_SCALE_ASPECT: |
75 | /* Scale but preserve the aspect ratio */ |
74 | /* Scale but preserve the aspect ratio */ |
76 | { |
75 | { |
77 | u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; |
76 | u32 scaled_width = adjusted_mode->hdisplay |
- | 77 | * pipe_config->pipe_src_h; |
|
78 | u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; |
78 | u32 scaled_height = pipe_config->pipe_src_w |
- | 79 | * adjusted_mode->vdisplay; |
|
79 | if (scaled_width > scaled_height) { /* pillar */ |
80 | if (scaled_width > scaled_height) { /* pillar */ |
80 | width = scaled_height / mode->vdisplay; |
81 | width = scaled_height / pipe_config->pipe_src_h; |
81 | if (width & 1) |
82 | if (width & 1) |
82 | width++; |
83 | width++; |
83 | x = (adjusted_mode->hdisplay - width + 1) / 2; |
84 | x = (adjusted_mode->hdisplay - width + 1) / 2; |
84 | y = 0; |
85 | y = 0; |
85 | height = adjusted_mode->vdisplay; |
86 | height = adjusted_mode->vdisplay; |
86 | } else if (scaled_width < scaled_height) { /* letter */ |
87 | } else if (scaled_width < scaled_height) { /* letter */ |
87 | height = scaled_width / mode->hdisplay; |
88 | height = scaled_width / pipe_config->pipe_src_w; |
88 | if (height & 1) |
89 | if (height & 1) |
89 | height++; |
90 | height++; |
90 | y = (adjusted_mode->vdisplay - height + 1) / 2; |
91 | y = (adjusted_mode->vdisplay - height + 1) / 2; |
91 | x = 0; |
92 | x = 0; |
92 | width = adjusted_mode->hdisplay; |
93 | width = adjusted_mode->hdisplay; |
93 | } else { |
94 | } else { |
94 | x = y = 0; |
95 | x = y = 0; |
95 | width = adjusted_mode->hdisplay; |
96 | width = adjusted_mode->hdisplay; |
96 | height = adjusted_mode->vdisplay; |
97 | height = adjusted_mode->vdisplay; |
97 | } |
98 | } |
98 | } |
99 | } |
99 | break; |
100 | break; |
100 | 101 | ||
101 | case DRM_MODE_SCALE_FULLSCREEN: |
102 | case DRM_MODE_SCALE_FULLSCREEN: |
102 | x = y = 0; |
103 | x = y = 0; |
103 | width = adjusted_mode->hdisplay; |
104 | width = adjusted_mode->hdisplay; |
104 | height = adjusted_mode->vdisplay; |
105 | height = adjusted_mode->vdisplay; |
105 | break; |
106 | break; |
106 | 107 | ||
107 | default: |
108 | default: |
108 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
109 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
109 | return; |
110 | return; |
110 | } |
111 | } |
111 | 112 | ||
112 | done: |
113 | done: |
113 | pipe_config->pch_pfit.pos = (x << 16) | y; |
114 | pipe_config->pch_pfit.pos = (x << 16) | y; |
114 | pipe_config->pch_pfit.size = (width << 16) | height; |
115 | pipe_config->pch_pfit.size = (width << 16) | height; |
115 | pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; |
116 | pipe_config->pch_pfit.enabled = pipe_config->pch_pfit.size != 0; |
116 | } |
117 | } |
117 | 118 | ||
118 | static void |
119 | static void |
119 | centre_horizontally(struct drm_display_mode *mode, |
120 | centre_horizontally(struct drm_display_mode *mode, |
120 | int width) |
121 | int width) |
121 | { |
122 | { |
122 | u32 border, sync_pos, blank_width, sync_width; |
123 | u32 border, sync_pos, blank_width, sync_width; |
123 | 124 | ||
124 | /* keep the hsync and hblank widths constant */ |
125 | /* keep the hsync and hblank widths constant */ |
125 | sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; |
126 | sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; |
126 | blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; |
127 | blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; |
127 | sync_pos = (blank_width - sync_width + 1) / 2; |
128 | sync_pos = (blank_width - sync_width + 1) / 2; |
128 | 129 | ||
129 | border = (mode->hdisplay - width + 1) / 2; |
130 | border = (mode->hdisplay - width + 1) / 2; |
130 | border += border & 1; /* make the border even */ |
131 | border += border & 1; /* make the border even */ |
131 | 132 | ||
132 | mode->crtc_hdisplay = width; |
133 | mode->crtc_hdisplay = width; |
133 | mode->crtc_hblank_start = width + border; |
134 | mode->crtc_hblank_start = width + border; |
134 | mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; |
135 | mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; |
135 | 136 | ||
136 | mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; |
137 | mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; |
137 | mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; |
138 | mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; |
138 | } |
139 | } |
139 | 140 | ||
140 | static void |
141 | static void |
141 | centre_vertically(struct drm_display_mode *mode, |
142 | centre_vertically(struct drm_display_mode *mode, |
142 | int height) |
143 | int height) |
143 | { |
144 | { |
144 | u32 border, sync_pos, blank_width, sync_width; |
145 | u32 border, sync_pos, blank_width, sync_width; |
145 | 146 | ||
146 | /* keep the vsync and vblank widths constant */ |
147 | /* keep the vsync and vblank widths constant */ |
147 | sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; |
148 | sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; |
148 | blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; |
149 | blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; |
149 | sync_pos = (blank_width - sync_width + 1) / 2; |
150 | sync_pos = (blank_width - sync_width + 1) / 2; |
150 | 151 | ||
151 | border = (mode->vdisplay - height + 1) / 2; |
152 | border = (mode->vdisplay - height + 1) / 2; |
152 | 153 | ||
153 | mode->crtc_vdisplay = height; |
154 | mode->crtc_vdisplay = height; |
154 | mode->crtc_vblank_start = height + border; |
155 | mode->crtc_vblank_start = height + border; |
155 | mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; |
156 | mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; |
156 | 157 | ||
157 | mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; |
158 | mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; |
158 | mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; |
159 | mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; |
159 | } |
160 | } |
160 | 161 | ||
161 | static inline u32 panel_fitter_scaling(u32 source, u32 target) |
162 | static inline u32 panel_fitter_scaling(u32 source, u32 target) |
162 | { |
163 | { |
163 | /* |
164 | /* |
164 | * Floating point operation is not supported. So the FACTOR |
165 | * Floating point operation is not supported. So the FACTOR |
165 | * is defined, which can avoid the floating point computation |
166 | * is defined, which can avoid the floating point computation |
166 | * when calculating the panel ratio. |
167 | * when calculating the panel ratio. |
167 | */ |
168 | */ |
168 | #define ACCURACY 12 |
169 | #define ACCURACY 12 |
169 | #define FACTOR (1 << ACCURACY) |
170 | #define FACTOR (1 << ACCURACY) |
170 | u32 ratio = source * FACTOR / target; |
171 | u32 ratio = source * FACTOR / target; |
171 | return (FACTOR * ratio + FACTOR/2) / FACTOR; |
172 | return (FACTOR * ratio + FACTOR/2) / FACTOR; |
172 | } |
173 | } |
173 | - | ||
174 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, |
174 | |
175 | struct intel_crtc_config *pipe_config, |
175 | static void i965_scale_aspect(struct intel_crtc_config *pipe_config, |
176 | int fitting_mode) |
176 | u32 *pfit_control) |
177 | { |
- | |
178 | struct drm_device *dev = intel_crtc->base.dev; |
- | |
179 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
177 | { |
180 | struct drm_display_mode *mode, *adjusted_mode; |
- | |
181 | - | ||
182 | mode = &pipe_config->requested_mode; |
- | |
183 | adjusted_mode = &pipe_config->adjusted_mode; |
- | |
184 | - | ||
185 | /* Native modes don't need fitting */ |
- | |
186 | if (adjusted_mode->hdisplay == mode->hdisplay && |
- | |
187 | adjusted_mode->vdisplay == mode->vdisplay) |
- | |
188 | goto out; |
- | |
189 | - | ||
190 | switch (fitting_mode) { |
- | |
191 | case DRM_MODE_SCALE_CENTER: |
- | |
192 | /* |
- | |
193 | * For centered modes, we have to calculate border widths & |
- | |
194 | * heights and modify the values programmed into the CRTC. |
- | |
195 | */ |
- | |
196 | centre_horizontally(adjusted_mode, mode->hdisplay); |
- | |
197 | centre_vertically(adjusted_mode, mode->vdisplay); |
- | |
198 | border = LVDS_BORDER_ENABLE; |
- | |
199 | break; |
- | |
200 | case DRM_MODE_SCALE_ASPECT: |
- | |
201 | /* Scale but preserve the aspect ratio */ |
- | |
202 | if (INTEL_INFO(dev)->gen >= 4) { |
178 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
203 | u32 scaled_width = adjusted_mode->hdisplay * |
179 | u32 scaled_width = adjusted_mode->hdisplay * |
204 | mode->vdisplay; |
180 | pipe_config->pipe_src_h; |
205 | u32 scaled_height = mode->hdisplay * |
181 | u32 scaled_height = pipe_config->pipe_src_w * |
206 | adjusted_mode->vdisplay; |
182 | adjusted_mode->vdisplay; |
207 | 183 | ||
208 | /* 965+ is easy, it does everything in hw */ |
184 | /* 965+ is easy, it does everything in hw */ |
209 | if (scaled_width > scaled_height) |
185 | if (scaled_width > scaled_height) |
210 | pfit_control |= PFIT_ENABLE | |
186 | *pfit_control |= PFIT_ENABLE | |
211 | PFIT_SCALING_PILLAR; |
187 | PFIT_SCALING_PILLAR; |
212 | else if (scaled_width < scaled_height) |
188 | else if (scaled_width < scaled_height) |
213 | pfit_control |= PFIT_ENABLE | |
189 | *pfit_control |= PFIT_ENABLE | |
214 | PFIT_SCALING_LETTER; |
190 | PFIT_SCALING_LETTER; |
215 | else if (adjusted_mode->hdisplay != mode->hdisplay) |
191 | else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w) |
216 | pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; |
192 | *pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO; |
- | 193 | } |
|
- | 194 | ||
- | 195 | static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config, |
|
- | 196 | u32 *pfit_control, u32 *pfit_pgm_ratios, |
|
217 | } else { |
197 | u32 *border) |
- | 198 | { |
|
- | 199 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; |
|
218 | u32 scaled_width = adjusted_mode->hdisplay * |
200 | u32 scaled_width = adjusted_mode->hdisplay * |
219 | mode->vdisplay; |
201 | pipe_config->pipe_src_h; |
220 | u32 scaled_height = mode->hdisplay * |
202 | u32 scaled_height = pipe_config->pipe_src_w * |
221 | adjusted_mode->vdisplay; |
203 | adjusted_mode->vdisplay; |
- | 204 | u32 bits; |
|
- | 205 | ||
222 | /* |
206 | /* |
223 | * For earlier chips we have to calculate the scaling |
207 | * For earlier chips we have to calculate the scaling |
224 | * ratio by hand and program it into the |
208 | * ratio by hand and program it into the |
225 | * PFIT_PGM_RATIO register |
209 | * PFIT_PGM_RATIO register |
226 | */ |
210 | */ |
227 | if (scaled_width > scaled_height) { /* pillar */ |
211 | if (scaled_width > scaled_height) { /* pillar */ |
228 | centre_horizontally(adjusted_mode, |
212 | centre_horizontally(adjusted_mode, |
229 | scaled_height / |
213 | scaled_height / |
230 | mode->vdisplay); |
214 | pipe_config->pipe_src_h); |
231 | 215 | ||
232 | border = LVDS_BORDER_ENABLE; |
216 | *border = LVDS_BORDER_ENABLE; |
233 | if (mode->vdisplay != adjusted_mode->vdisplay) { |
217 | if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) { |
- | 218 | bits = panel_fitter_scaling(pipe_config->pipe_src_h, |
|
- | 219 | adjusted_mode->vdisplay); |
|
234 | u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); |
220 | |
235 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
221 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
236 | bits << PFIT_VERT_SCALE_SHIFT); |
222 | bits << PFIT_VERT_SCALE_SHIFT); |
237 | pfit_control |= (PFIT_ENABLE | |
223 | *pfit_control |= (PFIT_ENABLE | |
238 | VERT_INTERP_BILINEAR | |
224 | VERT_INTERP_BILINEAR | |
239 | HORIZ_INTERP_BILINEAR); |
225 | HORIZ_INTERP_BILINEAR); |
240 | } |
226 | } |
241 | } else if (scaled_width < scaled_height) { /* letter */ |
227 | } else if (scaled_width < scaled_height) { /* letter */ |
242 | centre_vertically(adjusted_mode, |
228 | centre_vertically(adjusted_mode, |
243 | scaled_width / |
229 | scaled_width / |
244 | mode->hdisplay); |
230 | pipe_config->pipe_src_w); |
245 | 231 | ||
246 | border = LVDS_BORDER_ENABLE; |
232 | *border = LVDS_BORDER_ENABLE; |
247 | if (mode->hdisplay != adjusted_mode->hdisplay) { |
233 | if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) { |
- | 234 | bits = panel_fitter_scaling(pipe_config->pipe_src_w, |
|
- | 235 | adjusted_mode->hdisplay); |
|
248 | u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); |
236 | |
249 | pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
237 | *pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | |
250 | bits << PFIT_VERT_SCALE_SHIFT); |
238 | bits << PFIT_VERT_SCALE_SHIFT); |
251 | pfit_control |= (PFIT_ENABLE | |
239 | *pfit_control |= (PFIT_ENABLE | |
252 | VERT_INTERP_BILINEAR | |
240 | VERT_INTERP_BILINEAR | |
253 | HORIZ_INTERP_BILINEAR); |
241 | HORIZ_INTERP_BILINEAR); |
254 | } |
242 | } |
255 | } else { |
243 | } else { |
256 | /* Aspects match, Let hw scale both directions */ |
244 | /* Aspects match, Let hw scale both directions */ |
257 | pfit_control |= (PFIT_ENABLE | |
245 | *pfit_control |= (PFIT_ENABLE | |
258 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | |
246 | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | |
259 | VERT_INTERP_BILINEAR | |
247 | VERT_INTERP_BILINEAR | |
260 | HORIZ_INTERP_BILINEAR); |
248 | HORIZ_INTERP_BILINEAR); |
261 | } |
249 | } |
262 | } |
250 | } |
- | 251 | ||
- | 252 | void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc, |
|
- | 253 | struct intel_crtc_config *pipe_config, |
|
- | 254 | int fitting_mode) |
|
- | 255 | { |
|
- | 256 | struct drm_device *dev = intel_crtc->base.dev; |
|
- | 257 | u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; |
|
- | 258 | struct drm_display_mode *adjusted_mode; |
|
- | 259 | ||
- | 260 | adjusted_mode = &pipe_config->adjusted_mode; |
|
- | 261 | ||
- | 262 | /* Native modes don't need fitting */ |
|
- | 263 | if (adjusted_mode->hdisplay == pipe_config->pipe_src_w && |
|
- | 264 | adjusted_mode->vdisplay == pipe_config->pipe_src_h) |
|
- | 265 | goto out; |
|
- | 266 | ||
- | 267 | switch (fitting_mode) { |
|
- | 268 | case DRM_MODE_SCALE_CENTER: |
|
- | 269 | /* |
|
- | 270 | * For centered modes, we have to calculate border widths & |
|
- | 271 | * heights and modify the values programmed into the CRTC. |
|
- | 272 | */ |
|
- | 273 | centre_horizontally(adjusted_mode, pipe_config->pipe_src_w); |
|
- | 274 | centre_vertically(adjusted_mode, pipe_config->pipe_src_h); |
|
- | 275 | border = LVDS_BORDER_ENABLE; |
|
- | 276 | break; |
|
- | 277 | case DRM_MODE_SCALE_ASPECT: |
|
- | 278 | /* Scale but preserve the aspect ratio */ |
|
- | 279 | if (INTEL_INFO(dev)->gen >= 4) |
|
- | 280 | i965_scale_aspect(pipe_config, &pfit_control); |
|
- | 281 | else |
|
- | 282 | i9xx_scale_aspect(pipe_config, &pfit_control, |
|
- | 283 | &pfit_pgm_ratios, &border); |
|
263 | break; |
284 | break; |
264 | case DRM_MODE_SCALE_FULLSCREEN: |
285 | case DRM_MODE_SCALE_FULLSCREEN: |
265 | /* |
286 | /* |
266 | * Full scaling, even if it changes the aspect ratio. |
287 | * Full scaling, even if it changes the aspect ratio. |
267 | * Fortunately this is all done for us in hw. |
288 | * Fortunately this is all done for us in hw. |
268 | */ |
289 | */ |
269 | if (mode->vdisplay != adjusted_mode->vdisplay || |
290 | if (pipe_config->pipe_src_h != adjusted_mode->vdisplay || |
270 | mode->hdisplay != adjusted_mode->hdisplay) { |
291 | pipe_config->pipe_src_w != adjusted_mode->hdisplay) { |
271 | pfit_control |= PFIT_ENABLE; |
292 | pfit_control |= PFIT_ENABLE; |
272 | if (INTEL_INFO(dev)->gen >= 4) |
293 | if (INTEL_INFO(dev)->gen >= 4) |
273 | pfit_control |= PFIT_SCALING_AUTO; |
294 | pfit_control |= PFIT_SCALING_AUTO; |
274 | else |
295 | else |
275 | pfit_control |= (VERT_AUTO_SCALE | |
296 | pfit_control |= (VERT_AUTO_SCALE | |
276 | VERT_INTERP_BILINEAR | |
297 | VERT_INTERP_BILINEAR | |
277 | HORIZ_AUTO_SCALE | |
298 | HORIZ_AUTO_SCALE | |
278 | HORIZ_INTERP_BILINEAR); |
299 | HORIZ_INTERP_BILINEAR); |
279 | } |
300 | } |
280 | break; |
301 | break; |
281 | default: |
302 | default: |
282 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
303 | WARN(1, "bad panel fit mode: %d\n", fitting_mode); |
283 | return; |
304 | return; |
284 | } |
305 | } |
285 | 306 | ||
286 | /* 965+ wants fuzzy fitting */ |
307 | /* 965+ wants fuzzy fitting */ |
287 | /* FIXME: handle multiple panels by failing gracefully */ |
308 | /* FIXME: handle multiple panels by failing gracefully */ |
288 | if (INTEL_INFO(dev)->gen >= 4) |
309 | if (INTEL_INFO(dev)->gen >= 4) |
289 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | |
310 | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | |
290 | PFIT_FILTER_FUZZY); |
311 | PFIT_FILTER_FUZZY); |
291 | 312 | ||
292 | out: |
313 | out: |
293 | if ((pfit_control & PFIT_ENABLE) == 0) { |
314 | if ((pfit_control & PFIT_ENABLE) == 0) { |
294 | pfit_control = 0; |
315 | pfit_control = 0; |
295 | pfit_pgm_ratios = 0; |
316 | pfit_pgm_ratios = 0; |
296 | } |
317 | } |
297 | 318 | ||
298 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ |
319 | /* Make sure pre-965 set dither correctly for 18bpp panels. */ |
299 | if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) |
320 | if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18) |
300 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
321 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
301 | 322 | ||
302 | pipe_config->gmch_pfit.control = pfit_control; |
323 | pipe_config->gmch_pfit.control = pfit_control; |
303 | pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; |
324 | pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios; |
304 | pipe_config->gmch_pfit.lvds_border_bits = border; |
325 | pipe_config->gmch_pfit.lvds_border_bits = border; |
305 | } |
326 | } |
306 | - | ||
307 | static int is_backlight_combination_mode(struct drm_device *dev) |
- | |
308 | { |
- | |
309 | struct drm_i915_private *dev_priv = dev->dev_private; |
- | |
310 | - | ||
311 | if (INTEL_INFO(dev)->gen >= 4) |
- | |
312 | return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; |
- | |
313 | - | ||
314 | if (IS_GEN2(dev)) |
- | |
315 | return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; |
- | |
316 | - | ||
317 | return 0; |
- | |
318 | } |
- | |
319 | - | ||
320 | /* XXX: query mode clock or hardware clock and program max PWM appropriately |
- | |
321 | * when it's 0. |
- | |
322 | */ |
- | |
323 | static u32 i915_read_blc_pwm_ctl(struct drm_device *dev) |
- | |
324 | { |
- | |
325 | struct drm_i915_private *dev_priv = dev->dev_private; |
- | |
326 | u32 val; |
- | |
327 | - | ||
328 | // WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock)); |
- | |
329 | - | ||
330 | /* Restore the CTL value if it lost, e.g. GPU reset */ |
- | |
331 | - | ||
332 | if (HAS_PCH_SPLIT(dev_priv->dev)) { |
- | |
333 | val = I915_READ(BLC_PWM_PCH_CTL2); |
- | |
334 | if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) { |
- | |
335 | dev_priv->regfile.saveBLC_PWM_CTL2 = val; |
- | |
336 | } else if (val == 0) { |
- | |
337 | val = dev_priv->regfile.saveBLC_PWM_CTL2; |
- | |
338 | I915_WRITE(BLC_PWM_PCH_CTL2, val); |
- | |
339 | } |
- | |
340 | } else { |
- | |
341 | val = I915_READ(BLC_PWM_CTL); |
- | |
342 | if (dev_priv->regfile.saveBLC_PWM_CTL == 0) { |
- | |
343 | dev_priv->regfile.saveBLC_PWM_CTL = val; |
- | |
344 | if (INTEL_INFO(dev)->gen >= 4) |
- | |
345 | dev_priv->regfile.saveBLC_PWM_CTL2 = |
- | |
346 | I915_READ(BLC_PWM_CTL2); |
- | |
347 | } else if (val == 0) { |
- | |
348 | val = dev_priv->regfile.saveBLC_PWM_CTL; |
- | |
349 | I915_WRITE(BLC_PWM_CTL, val); |
- | |
350 | if (INTEL_INFO(dev)->gen >= 4) |
- | |
351 | I915_WRITE(BLC_PWM_CTL2, |
- | |
352 | dev_priv->regfile.saveBLC_PWM_CTL2); |
- | |
353 | } |
- | |
354 | } |
- | |
355 | - | ||
356 | return val; |
- | |
357 | } |
- | |
358 | - | ||
359 | static u32 intel_panel_get_max_backlight(struct drm_device *dev) |
- | |
360 | { |
- | |
361 | u32 max; |
- | |
362 | - | ||
363 | max = i915_read_blc_pwm_ctl(dev); |
- | |
364 | - | ||
365 | if (HAS_PCH_SPLIT(dev)) { |
- | |
366 | max >>= 16; |
- | |
367 | } else { |
- | |
368 | if (INTEL_INFO(dev)->gen < 4) |
- | |
369 | max >>= 17; |
- | |
370 | else |
- | |
371 | max >>= 16; |
- | |
372 | - | ||
373 | if (is_backlight_combination_mode(dev)) |
- | |
374 | max *= 0xff; |
- | |
375 | } |
- | |
376 | - | ||
377 | DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); |
- | |
378 | - | ||
379 | return max; |
- | |
380 | } |
- | |
381 | 327 | ||
382 | static int i915_panel_invert_brightness; |
328 | static int i915_panel_invert_brightness; |
383 | MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " |
329 | MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " |
384 | "(-1 force normal, 0 machine defaults, 1 force inversion), please " |
330 | "(-1 force normal, 0 machine defaults, 1 force inversion), please " |
385 | "report PCI device ID, subsystem vendor and subsystem device ID " |
331 | "report PCI device ID, subsystem vendor and subsystem device ID " |
386 | "to dri-devel@lists.freedesktop.org, if your machine needs it. " |
332 | "to dri-devel@lists.freedesktop.org, if your machine needs it. " |
387 | "It will then be included in an upcoming module version."); |
333 | "It will then be included in an upcoming module version."); |
388 | module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); |
334 | module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); |
389 | static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) |
335 | static u32 intel_panel_compute_brightness(struct intel_connector *connector, |
- | 336 | u32 val) |
|
390 | { |
337 | { |
- | 338 | struct drm_device *dev = connector->base.dev; |
|
391 | struct drm_i915_private *dev_priv = dev->dev_private; |
339 | struct drm_i915_private *dev_priv = dev->dev_private; |
- | 340 | struct intel_panel *panel = &connector->panel; |
|
- | 341 | ||
- | 342 | WARN_ON(panel->backlight.max == 0); |
|
392 | 343 | ||
393 | if (i915_panel_invert_brightness < 0) |
344 | if (i915_panel_invert_brightness < 0) |
394 | return val; |
345 | return val; |
395 | 346 | ||
396 | if (i915_panel_invert_brightness > 0 || |
347 | if (i915_panel_invert_brightness > 0 || |
397 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { |
348 | dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) { |
398 | u32 max = intel_panel_get_max_backlight(dev); |
- | |
399 | if (max) |
- | |
400 | return max - val; |
349 | return panel->backlight.max - val; |
401 | } |
350 | } |
402 | 351 | ||
403 | return val; |
352 | return val; |
404 | } |
353 | } |
405 | 354 | ||
406 | static u32 intel_panel_get_backlight(struct drm_device *dev) |
355 | static u32 bdw_get_backlight(struct intel_connector *connector) |
- | 356 | { |
|
407 | { |
357 | struct drm_device *dev = connector->base.dev; |
408 | struct drm_i915_private *dev_priv = dev->dev_private; |
- | |
409 | u32 val; |
- | |
- | 358 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 359 | ||
- | 360 | return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK; |
|
- | 361 | } |
|
- | 362 | ||
- | 363 | static u32 pch_get_backlight(struct intel_connector *connector) |
|
410 | unsigned long flags; |
364 | { |
- | 365 | struct drm_device *dev = connector->base.dev; |
|
- | 366 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 367 | ||
- | 368 | return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
|
- | 369 | } |
|
- | 370 | ||
- | 371 | static u32 i9xx_get_backlight(struct intel_connector *connector) |
|
- | 372 | { |
|
- | 373 | struct drm_device *dev = connector->base.dev; |
|
- | 374 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
411 | - | ||
412 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
- | |
413 | - | ||
414 | if (HAS_PCH_SPLIT(dev)) { |
375 | struct intel_panel *panel = &connector->panel; |
415 | val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
376 | u32 val; |
416 | } else { |
377 | |
417 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
378 | val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; |
418 | if (INTEL_INFO(dev)->gen < 4) |
379 | if (INTEL_INFO(dev)->gen < 4) |
419 | val >>= 1; |
380 | val >>= 1; |
420 | 381 | ||
421 | if (is_backlight_combination_mode(dev)) { |
382 | if (panel->backlight.combination_mode) { |
422 | u8 lbpc; |
383 | u8 lbpc; |
423 | 384 | ||
424 | pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); |
385 | pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); |
425 | val *= lbpc; |
386 | val *= lbpc; |
426 | } |
387 | } |
- | 388 | ||
- | 389 | return val; |
|
- | 390 | } |
|
- | 391 | ||
- | 392 | static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe) |
|
- | 393 | { |
|
- | 394 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 395 | ||
- | 396 | return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK; |
|
427 | } |
397 | } |
- | 398 | ||
- | 399 | static u32 vlv_get_backlight(struct intel_connector *connector) |
|
- | 400 | { |
|
- | 401 | struct drm_device *dev = connector->base.dev; |
|
- | 402 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
- | 403 | ||
- | 404 | return _vlv_get_backlight(dev, pipe); |
|
- | 405 | } |
|
- | 406 | ||
- | 407 | static u32 intel_panel_get_backlight(struct intel_connector *connector) |
|
- | 408 | { |
|
- | 409 | struct drm_device *dev = connector->base.dev; |
|
- | 410 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 411 | u32 val; |
|
- | 412 | unsigned long flags; |
|
- | 413 | ||
- | 414 | spin_lock_irqsave(&dev_priv->backlight_lock, flags); |
|
- | 415 | ||
428 | 416 | val = dev_priv->display.get_backlight(connector); |
|
429 | val = intel_panel_compute_brightness(dev, val); |
417 | val = intel_panel_compute_brightness(connector, val); |
430 | 418 | ||
431 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
419 | spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); |
432 | 420 | ||
433 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
421 | DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); |
434 | return val; |
422 | return val; |
435 | } |
423 | } |
436 | 424 | ||
437 | static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) |
425 | static void bdw_set_backlight(struct intel_connector *connector, u32 level) |
- | 426 | { |
|
438 | { |
427 | struct drm_device *dev = connector->base.dev; |
439 | struct drm_i915_private *dev_priv = dev->dev_private; |
428 | struct drm_i915_private *dev_priv = dev->dev_private; |
440 | u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
429 | u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
441 | I915_WRITE(BLC_PWM_CPU_CTL, val | level); |
430 | I915_WRITE(BLC_PWM_PCH_CTL2, val | level); |
442 | } |
431 | } |
443 | 432 | ||
- | 433 | static void pch_set_backlight(struct intel_connector *connector, u32 level) |
|
444 | static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) |
434 | { |
445 | { |
435 | struct drm_device *dev = connector->base.dev; |
446 | struct drm_i915_private *dev_priv = dev->dev_private; |
436 | struct drm_i915_private *dev_priv = dev->dev_private; |
447 | u32 tmp; |
437 | u32 tmp; |
448 | 438 | ||
449 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); |
439 | tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
- | 440 | I915_WRITE(BLC_PWM_CPU_CTL, tmp | level); |
|
- | 441 | } |
|
- | 442 | ||
450 | level = intel_panel_compute_brightness(dev, level); |
443 | static void i9xx_set_backlight(struct intel_connector *connector, u32 level) |
- | 444 | { |
|
451 | 445 | struct drm_device *dev = connector->base.dev; |
|
- | 446 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
452 | if (HAS_PCH_SPLIT(dev)) |
- | |
453 | return intel_pch_panel_set_backlight(dev, level); |
447 | struct intel_panel *panel = &connector->panel; |
454 | - | ||
455 | if (is_backlight_combination_mode(dev)) { |
448 | u32 tmp, mask; |
456 | u32 max = intel_panel_get_max_backlight(dev); |
449 | |
457 | u8 lbpc; |
- | |
458 | 450 | WARN_ON(panel->backlight.max == 0); |
|
459 | /* we're screwed, but keep behaviour backwards compatible */ |
451 | |
460 | if (!max) |
452 | if (panel->backlight.combination_mode) { |
461 | max = 1; |
453 | u8 lbpc; |
462 | 454 | ||
463 | lbpc = level * 0xfe / max + 1; |
455 | lbpc = level * 0xfe / panel->backlight.max + 1; |
464 | level /= lbpc; |
456 | level /= lbpc; |
465 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); |
457 | pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc); |
466 | } |
458 | } |
467 | 459 | ||
468 | tmp = I915_READ(BLC_PWM_CTL); |
460 | if (IS_GEN4(dev)) { |
- | 461 | mask = BACKLIGHT_DUTY_CYCLE_MASK; |
|
469 | if (INTEL_INFO(dev)->gen < 4) |
462 | } else { |
470 | level <<= 1; |
463 | level <<= 1; |
- | 464 | mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV; |
|
- | 465 | } |
|
- | 466 | ||
471 | tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; |
467 | tmp = I915_READ(BLC_PWM_CTL) & ~mask; |
472 | I915_WRITE(BLC_PWM_CTL, tmp | level); |
468 | I915_WRITE(BLC_PWM_CTL, tmp | level); |
473 | } |
469 | } |
- | 470 | ||
- | 471 | static void vlv_set_backlight(struct intel_connector *connector, u32 level) |
|
- | 472 | { |
|
- | 473 | struct drm_device *dev = connector->base.dev; |
|
- | 474 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 475 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
- | 476 | u32 tmp; |
|
- | 477 | ||
- | 478 | tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
|
- | 479 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); |
|
- | 480 | } |
|
- | 481 | ||
- | 482 | static void |
|
- | 483 | intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) |
|
- | 484 | { |
|
- | 485 | struct drm_device *dev = connector->base.dev; |
|
- | 486 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 487 | ||
- | 488 | DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); |
|
- | 489 | ||
- | 490 | level = intel_panel_compute_brightness(connector, level); |
|
- | 491 | dev_priv->display.set_backlight(connector, level); |
|
- | 492 | } |
|
474 | 493 | ||
475 | /* set backlight brightness to level in range [0..max] */ |
494 | /* set backlight brightness to level in range [0..max] */ |
- | 495 | void intel_panel_set_backlight(struct intel_connector *connector, u32 level, |
|
- | 496 | u32 max) |
|
- | 497 | { |
|
- | 498 | struct drm_device *dev = connector->base.dev; |
|
- | 499 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 500 | struct intel_panel *panel = &connector->panel; |
|
- | 501 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
- | 502 | u32 freq; |
|
- | 503 | unsigned long flags; |
|
- | 504 | ||
- | 505 | if (!panel->backlight.present || pipe == INVALID_PIPE) |
|
- | 506 | return; |
|
- | 507 | ||
- | 508 | spin_lock_irqsave(&dev_priv->backlight_lock, flags); |
|
- | 509 | ||
- | 510 | WARN_ON(panel->backlight.max == 0); |
|
- | 511 | ||
- | 512 | /* scale to hardware max, but be careful to not overflow */ |
|
- | 513 | freq = panel->backlight.max; |
|
- | 514 | if (freq < max) |
|
- | 515 | level = level * freq / max; |
|
- | 516 | else |
|
- | 517 | level = freq / max * level; |
|
- | 518 | ||
- | 519 | panel->backlight.level = level; |
|
- | 520 | // if (panel->backlight.device) |
|
- | 521 | // panel->backlight.device->props.brightness = level; |
|
- | 522 | ||
- | 523 | if (panel->backlight.enabled) |
|
- | 524 | intel_panel_actually_set_backlight(connector, level); |
|
- | 525 | ||
- | 526 | spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); |
|
- | 527 | } |
|
- | 528 | ||
- | 529 | static void pch_disable_backlight(struct intel_connector *connector) |
|
- | 530 | { |
|
- | 531 | struct drm_device *dev = connector->base.dev; |
|
- | 532 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 533 | u32 tmp; |
|
- | 534 | ||
- | 535 | intel_panel_actually_set_backlight(connector, 0); |
|
- | 536 | ||
- | 537 | tmp = I915_READ(BLC_PWM_CPU_CTL2); |
|
- | 538 | I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE); |
|
- | 539 | ||
- | 540 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
|
- | 541 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE); |
|
- | 542 | } |
|
- | 543 | ||
476 | void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max) |
544 | static void i9xx_disable_backlight(struct intel_connector *connector) |
- | 545 | { |
|
- | 546 | intel_panel_actually_set_backlight(connector, 0); |
|
- | 547 | } |
|
- | 548 | ||
- | 549 | static void i965_disable_backlight(struct intel_connector *connector) |
|
- | 550 | { |
|
477 | { |
551 | struct drm_device *dev = connector->base.dev; |
- | 552 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
478 | struct drm_i915_private *dev_priv = dev->dev_private; |
553 | u32 tmp; |
479 | - | ||
480 | dev_priv->backlight.level = level; |
- | |
481 | // if (dev_priv->backlight.device) |
554 | |
482 | // dev_priv->backlight.device->props.brightness = level; |
555 | intel_panel_actually_set_backlight(connector, 0); |
483 | 556 | ||
484 | // if (dev_priv->backlight.enabled) |
557 | tmp = I915_READ(BLC_PWM_CTL2); |
485 | // intel_panel_actually_set_backlight(dev, level); |
558 | I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE); |
- | 559 | } |
|
486 | } |
560 | |
- | 561 | static void vlv_disable_backlight(struct intel_connector *connector) |
|
- | 562 | { |
|
- | 563 | struct drm_device *dev = connector->base.dev; |
|
- | 564 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 565 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
- | 566 | u32 tmp; |
|
- | 567 | ||
- | 568 | intel_panel_actually_set_backlight(connector, 0); |
|
- | 569 | ||
- | 570 | tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
|
- | 571 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); |
|
- | 572 | } |
|
- | 573 | ||
- | 574 | void intel_panel_disable_backlight(struct intel_connector *connector) |
|
- | 575 | { |
|
487 | 576 | struct drm_device *dev = connector->base.dev; |
|
- | 577 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 578 | struct intel_panel *panel = &connector->panel; |
|
- | 579 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
488 | void intel_panel_disable_backlight(struct drm_device *dev) |
580 | unsigned long flags; |
489 | { |
581 | |
490 | struct drm_i915_private *dev_priv = dev->dev_private; |
582 | if (!panel->backlight.present || pipe == INVALID_PIPE) |
491 | unsigned long flags; |
583 | return; |
492 | 584 | ||
493 | /* |
585 | /* |
494 | * Do not disable backlight on the vgaswitcheroo path. When switching |
586 | * Do not disable backlight on the vgaswitcheroo path. When switching |
495 | * away from i915, the other client may depend on i915 to handle the |
587 | * away from i915, the other client may depend on i915 to handle the |
496 | * backlight. This will leave the backlight on unnecessarily when |
588 | * backlight. This will leave the backlight on unnecessarily when |
497 | * another client is not activated. |
589 | * another client is not activated. |
498 | */ |
590 | */ |
499 | if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { |
591 | if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) { |
500 | DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); |
592 | DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n"); |
501 | return; |
593 | return; |
502 | } |
594 | } |
503 | 595 | ||
504 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
- | |
505 | - | ||
506 | dev_priv->backlight.enabled = false; |
- | |
507 | intel_panel_actually_set_backlight(dev, 0); |
596 | spin_lock_irqsave(&dev_priv->backlight_lock, flags); |
508 | 597 | ||
509 | if (INTEL_INFO(dev)->gen >= 4) { |
598 | panel->backlight.enabled = false; |
- | 599 | dev_priv->display.disable_backlight(connector); |
|
- | 600 | ||
- | 601 | spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); |
|
- | 602 | } |
|
510 | uint32_t reg, tmp; |
603 | |
- | 604 | static void bdw_enable_backlight(struct intel_connector *connector) |
|
- | 605 | { |
|
- | 606 | struct drm_device *dev = connector->base.dev; |
|
511 | 607 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
512 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; |
608 | struct intel_panel *panel = &connector->panel; |
513 | 609 | u32 pch_ctl1, pch_ctl2; |
|
514 | I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE); |
610 | |
515 | - | ||
516 | if (HAS_PCH_SPLIT(dev)) { |
611 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
- | 612 | if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { |
|
- | 613 | DRM_DEBUG_KMS("pch backlight already enabled\n"); |
|
- | 614 | pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; |
|
- | 615 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
|
- | 616 | } |
|
- | 617 | ||
- | 618 | pch_ctl2 = panel->backlight.max << 16; |
|
- | 619 | I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); |
|
- | 620 | ||
- | 621 | pch_ctl1 = 0; |
|
- | 622 | if (panel->backlight.active_low_pwm) |
|
- | 623 | pch_ctl1 |= BLM_PCH_POLARITY; |
|
- | 624 | ||
- | 625 | /* BDW always uses the pch pwm controls. */ |
|
- | 626 | pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE; |
|
517 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
627 | |
518 | tmp &= ~BLM_PCH_PWM_ENABLE; |
628 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
519 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
629 | POSTING_READ(BLC_PWM_PCH_CTL1); |
520 | } |
- | |
521 | } |
630 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); |
- | 631 | ||
522 | 632 | /* This won't stick until the above enable. */ |
|
- | 633 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
|
- | 634 | } |
|
523 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
635 | |
524 | } |
636 | static void pch_enable_backlight(struct intel_connector *connector) |
525 | 637 | { |
|
- | 638 | struct drm_device *dev = connector->base.dev; |
|
- | 639 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
526 | void intel_panel_enable_backlight(struct drm_device *dev, |
640 | struct intel_panel *panel = &connector->panel; |
- | 641 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
- | 642 | enum transcoder cpu_transcoder = |
|
- | 643 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
|
527 | enum pipe pipe) |
644 | u32 cpu_ctl2, pch_ctl1, pch_ctl2; |
528 | { |
645 | |
529 | struct drm_i915_private *dev_priv = dev->dev_private; |
646 | cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); |
530 | enum transcoder cpu_transcoder = |
647 | if (cpu_ctl2 & BLM_PWM_ENABLE) { |
531 | intel_pipe_to_cpu_transcoder(dev_priv, pipe); |
648 | WARN(1, "cpu backlight already enabled\n"); |
532 | unsigned long flags; |
649 | cpu_ctl2 &= ~BLM_PWM_ENABLE; |
533 | 650 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); |
|
534 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
651 | } |
- | 652 | ||
- | 653 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
|
- | 654 | if (pch_ctl1 & BLM_PCH_PWM_ENABLE) { |
|
- | 655 | DRM_DEBUG_KMS("pch backlight already enabled\n"); |
|
- | 656 | pch_ctl1 &= ~BLM_PCH_PWM_ENABLE; |
|
- | 657 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
|
- | 658 | } |
|
- | 659 | ||
- | 660 | if (cpu_transcoder == TRANSCODER_EDP) |
|
535 | 661 | cpu_ctl2 = BLM_TRANSCODER_EDP; |
|
- | 662 | else |
|
- | 663 | cpu_ctl2 = BLM_PIPE(cpu_transcoder); |
|
- | 664 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2); |
|
- | 665 | POSTING_READ(BLC_PWM_CPU_CTL2); |
|
536 | if (dev_priv->backlight.level == 0) { |
666 | I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE); |
- | 667 | ||
- | 668 | /* This won't stick until the above enable. */ |
|
537 | dev_priv->backlight.level = intel_panel_get_max_backlight(dev); |
669 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
- | 670 | ||
538 | // if (dev_priv->backlight.device) |
671 | pch_ctl2 = panel->backlight.max << 16; |
539 | // dev_priv->backlight.device->props.brightness = |
672 | I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2); |
540 | // dev_priv->backlight.level; |
673 | |
541 | } |
674 | pch_ctl1 = 0; |
542 | 675 | if (panel->backlight.active_low_pwm) |
|
543 | if (INTEL_INFO(dev)->gen >= 4) { |
676 | pch_ctl1 |= BLM_PCH_POLARITY; |
544 | uint32_t reg, tmp; |
677 | |
545 | 678 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1); |
|
- | 679 | POSTING_READ(BLC_PWM_PCH_CTL1); |
|
546 | reg = HAS_PCH_SPLIT(dev) ? BLC_PWM_CPU_CTL2 : BLC_PWM_CTL2; |
- | |
547 | 680 | I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE); |
|
548 | - | ||
549 | tmp = I915_READ(reg); |
681 | } |
550 | 682 | ||
551 | /* Note that this can also get called through dpms changes. And |
683 | static void i9xx_enable_backlight(struct intel_connector *connector) |
- | 684 | { |
|
552 | * we don't track the backlight dpms state, hence check whether |
685 | struct drm_device *dev = connector->base.dev; |
- | 686 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
553 | * we have to do anything first. */ |
687 | struct intel_panel *panel = &connector->panel; |
554 | if (tmp & BLM_PWM_ENABLE) |
688 | u32 ctl, freq; |
- | 689 | ||
- | 690 | ctl = I915_READ(BLC_PWM_CTL); |
|
- | 691 | if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) { |
|
- | 692 | WARN(1, "backlight already enabled\n"); |
|
- | 693 | I915_WRITE(BLC_PWM_CTL, 0); |
|
- | 694 | } |
|
- | 695 | ||
- | 696 | freq = panel->backlight.max; |
|
- | 697 | if (panel->backlight.combination_mode) |
|
555 | goto set_level; |
698 | freq /= 0xff; |
- | 699 | ||
- | 700 | ctl = freq << 17; |
|
- | 701 | if (IS_GEN2(dev) && panel->backlight.combination_mode) |
|
- | 702 | ctl |= BLM_LEGACY_MODE; |
|
556 | 703 | if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm) |
|
557 | if (INTEL_INFO(dev)->num_pipes == 3) |
704 | ctl |= BLM_POLARITY_PNV; |
- | 705 | ||
558 | tmp &= ~BLM_PIPE_SELECT_IVB; |
706 | I915_WRITE(BLC_PWM_CTL, ctl); |
559 | else |
707 | POSTING_READ(BLC_PWM_CTL); |
560 | tmp &= ~BLM_PIPE_SELECT; |
708 | |
- | 709 | /* XXX: combine this into above write? */ |
|
- | 710 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
|
- | 711 | } |
|
- | 712 | ||
- | 713 | static void i965_enable_backlight(struct intel_connector *connector) |
|
- | 714 | { |
|
- | 715 | struct drm_device *dev = connector->base.dev; |
|
- | 716 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 717 | struct intel_panel *panel = &connector->panel; |
|
- | 718 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
- | 719 | u32 ctl, ctl2, freq; |
|
- | 720 | ||
- | 721 | ctl2 = I915_READ(BLC_PWM_CTL2); |
|
- | 722 | if (ctl2 & BLM_PWM_ENABLE) { |
|
- | 723 | WARN(1, "backlight already enabled\n"); |
|
- | 724 | ctl2 &= ~BLM_PWM_ENABLE; |
|
- | 725 | I915_WRITE(BLC_PWM_CTL2, ctl2); |
|
- | 726 | } |
|
- | 727 | ||
561 | 728 | freq = panel->backlight.max; |
|
562 | if (cpu_transcoder == TRANSCODER_EDP) |
- | |
563 | tmp |= BLM_TRANSCODER_EDP; |
729 | if (panel->backlight.combination_mode) |
- | 730 | freq /= 0xff; |
|
564 | else |
731 | |
565 | tmp |= BLM_PIPE(cpu_transcoder); |
732 | ctl = freq << 16; |
566 | tmp &= ~BLM_PWM_ENABLE; |
- | |
567 | 733 | I915_WRITE(BLC_PWM_CTL, ctl); |
|
568 | I915_WRITE(reg, tmp); |
734 | |
- | 735 | /* XXX: combine this into above write? */ |
|
- | 736 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
|
- | 737 | ||
569 | POSTING_READ(reg); |
738 | ctl2 = BLM_PIPE(pipe); |
- | 739 | if (panel->backlight.combination_mode) |
|
- | 740 | ctl2 |= BLM_COMBINATION_MODE; |
|
570 | I915_WRITE(reg, tmp | BLM_PWM_ENABLE); |
741 | if (panel->backlight.active_low_pwm) |
- | 742 | ctl2 |= BLM_POLARITY_I965; |
|
- | 743 | I915_WRITE(BLC_PWM_CTL2, ctl2); |
|
- | 744 | POSTING_READ(BLC_PWM_CTL2); |
|
- | 745 | I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE); |
|
- | 746 | } |
|
- | 747 | ||
- | 748 | static void vlv_enable_backlight(struct intel_connector *connector) |
|
- | 749 | { |
|
- | 750 | struct drm_device *dev = connector->base.dev; |
|
- | 751 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 752 | struct intel_panel *panel = &connector->panel; |
|
- | 753 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
|
- | 754 | u32 ctl, ctl2; |
|
- | 755 | ||
571 | 756 | ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe)); |
|
572 | if (HAS_PCH_SPLIT(dev) && |
757 | if (ctl2 & BLM_PWM_ENABLE) { |
- | 758 | WARN(1, "backlight already enabled\n"); |
|
573 | !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) { |
759 | ctl2 &= ~BLM_PWM_ENABLE; |
- | 760 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); |
|
- | 761 | } |
|
- | 762 | ||
- | 763 | ctl = panel->backlight.max << 16; |
|
- | 764 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl); |
|
- | 765 | ||
- | 766 | /* XXX: combine this into above write? */ |
|
- | 767 | intel_panel_actually_set_backlight(connector, panel->backlight.level); |
|
- | 768 | ||
- | 769 | ctl2 = 0; |
|
- | 770 | if (panel->backlight.active_low_pwm) |
|
- | 771 | ctl2 |= BLM_POLARITY_I965; |
|
- | 772 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2); |
|
- | 773 | POSTING_READ(VLV_BLC_PWM_CTL2(pipe)); |
|
- | 774 | I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); |
|
- | 775 | } |
|
- | 776 | ||
- | 777 | void intel_panel_enable_backlight(struct intel_connector *connector) |
|
- | 778 | { |
|
- | 779 | struct drm_device *dev = connector->base.dev; |
|
- | 780 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 781 | struct intel_panel *panel = &connector->panel; |
|
574 | tmp = I915_READ(BLC_PWM_PCH_CTL1); |
- | |
575 | tmp |= BLM_PCH_PWM_ENABLE; |
782 | enum pipe pipe = intel_get_pipe_from_connector(connector); |
576 | tmp &= ~BLM_PCH_OVERRIDE_ENABLE; |
783 | unsigned long flags; |
577 | I915_WRITE(BLC_PWM_PCH_CTL1, tmp); |
784 | |
578 | } |
785 | if (!panel->backlight.present || pipe == INVALID_PIPE) |
579 | } |
786 | return; |
580 | 787 | ||
581 | set_level: |
788 | DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); |
582 | /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1. |
789 | |
583 | * BLC_PWM_CPU_CTL may be cleared to zero automatically when these |
790 | spin_lock_irqsave(&dev_priv->backlight_lock, flags); |
584 | * registers are set. |
791 | |
585 | */ |
792 | WARN_ON(panel->backlight.max == 0); |
586 | dev_priv->backlight.enabled = true; |
793 | |
587 | intel_panel_actually_set_backlight(dev, dev_priv->backlight.level); |
794 | if (panel->backlight.level == 0) { |
588 | 795 | panel->backlight.level = panel->backlight.max; |
|
589 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
796 | // if (panel->backlight.device) |
590 | } |
797 | // panel->backlight.device->props.brightness = |
591 | 798 | // panel->backlight.level; |
|
592 | static void intel_panel_init_backlight(struct drm_device *dev) |
799 | } |
593 | { |
800 | |
594 | struct drm_i915_private *dev_priv = dev->dev_private; |
801 | dev_priv->display.enable_backlight(connector); |
595 | 802 | panel->backlight.enabled = true; |
|
596 | dev_priv->backlight.level = intel_panel_get_backlight(dev); |
803 | |
597 | dev_priv->backlight.enabled = dev_priv->backlight.level != 0; |
804 | spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); |
598 | } |
805 | } |
599 | 806 | ||
600 | enum drm_connector_status |
807 | enum drm_connector_status |
601 | intel_panel_detect(struct drm_device *dev) |
808 | intel_panel_detect(struct drm_device *dev) |
602 | { |
809 | { |
603 | struct drm_i915_private *dev_priv = dev->dev_private; |
810 | struct drm_i915_private *dev_priv = dev->dev_private; |
604 | 811 | ||
605 | /* Assume that the BIOS does not lie through the OpRegion... */ |
812 | /* Assume that the BIOS does not lie through the OpRegion... */ |
606 | if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) { |
813 | if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) { |
607 | return ioread32(dev_priv->opregion.lid_state) & 0x1 ? |
814 | return ioread32(dev_priv->opregion.lid_state) & 0x1 ? |
608 | connector_status_connected : |
815 | connector_status_connected : |
609 | connector_status_disconnected; |
816 | connector_status_disconnected; |
610 | } |
817 | } |
611 | 818 | ||
612 | switch (i915_panel_ignore_lid) { |
819 | switch (i915_panel_ignore_lid) { |
613 | case -2: |
820 | case -2: |
614 | return connector_status_connected; |
821 | return connector_status_connected; |
615 | case -1: |
822 | case -1: |
616 | return connector_status_disconnected; |
823 | return connector_status_disconnected; |
617 | default: |
824 | default: |
618 | return connector_status_unknown; |
825 | return connector_status_unknown; |
619 | } |
826 | } |
620 | } |
827 | } |
621 | 828 | ||
622 | #ifdef CONFIG_BACKLIGHT_CLASS_DEVICE |
829 | #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE) |
623 | static int intel_panel_update_status(struct backlight_device *bd) |
830 | static int intel_backlight_device_update_status(struct backlight_device *bd) |
- | 831 | { |
|
624 | { |
832 | struct intel_connector *connector = bl_get_data(bd); |
- | 833 | struct drm_device *dev = connector->base.dev; |
|
- | 834 | ||
- | 835 | mutex_lock(&dev->mode_config.mutex); |
|
- | 836 | DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n", |
|
625 | struct drm_device *dev = bl_get_data(bd); |
837 | bd->props.brightness, bd->props.max_brightness); |
626 | intel_panel_set_backlight(dev, bd->props.brightness, |
838 | intel_panel_set_backlight(connector, bd->props.brightness, |
- | 839 | bd->props.max_brightness); |
|
627 | bd->props.max_brightness); |
840 | mutex_unlock(&dev->mode_config.mutex); |
628 | return 0; |
841 | return 0; |
629 | } |
842 | } |
630 | 843 | ||
631 | static int intel_panel_get_brightness(struct backlight_device *bd) |
844 | static int intel_backlight_device_get_brightness(struct backlight_device *bd) |
- | 845 | { |
|
632 | { |
846 | struct intel_connector *connector = bl_get_data(bd); |
- | 847 | struct drm_device *dev = connector->base.dev; |
|
- | 848 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 849 | int ret; |
|
- | 850 | ||
- | 851 | intel_runtime_pm_get(dev_priv); |
|
633 | struct drm_device *dev = bl_get_data(bd); |
852 | mutex_lock(&dev->mode_config.mutex); |
- | 853 | ret = intel_panel_get_backlight(connector); |
|
- | 854 | mutex_unlock(&dev->mode_config.mutex); |
|
- | 855 | intel_runtime_pm_put(dev_priv); |
|
- | 856 | ||
634 | return intel_panel_get_backlight(dev); |
857 | return ret; |
635 | } |
858 | } |
636 | 859 | ||
637 | static const struct backlight_ops intel_panel_bl_ops = { |
860 | static const struct backlight_ops intel_backlight_device_ops = { |
638 | .update_status = intel_panel_update_status, |
861 | .update_status = intel_backlight_device_update_status, |
639 | .get_brightness = intel_panel_get_brightness, |
862 | .get_brightness = intel_backlight_device_get_brightness, |
640 | }; |
863 | }; |
641 | 864 | ||
642 | int intel_panel_setup_backlight(struct drm_connector *connector) |
- | |
643 | { |
865 | static int intel_backlight_device_register(struct intel_connector *connector) |
644 | struct drm_device *dev = connector->dev; |
- | |
645 | struct drm_i915_private *dev_priv = dev->dev_private; |
- | |
646 | struct backlight_properties props; |
- | |
647 | unsigned long flags; |
866 | { |
648 | 867 | struct intel_panel *panel = &connector->panel; |
|
- | 868 | struct backlight_properties props; |
|
- | 869 | ||
649 | intel_panel_init_backlight(dev); |
870 | if (WARN_ON(panel->backlight.device)) |
650 | 871 | return -ENODEV; |
|
651 | if (WARN_ON(dev_priv->backlight.device)) |
872 | |
- | 873 | BUG_ON(panel->backlight.max == 0); |
|
- | 874 | ||
- | 875 | memset(&props, 0, sizeof(props)); |
|
652 | return -ENODEV; |
876 | props.type = BACKLIGHT_RAW; |
- | 877 | props.brightness = panel->backlight.level; |
|
- | 878 | props.max_brightness = panel->backlight.max; |
|
653 | 879 | ||
- | 880 | /* |
|
- | 881 | * Note: using the same name independent of the connector prevents |
|
654 | memset(&props, 0, sizeof(props)); |
882 | * registration of multiple backlight devices in the driver. |
655 | props.type = BACKLIGHT_RAW; |
883 | */ |
656 | props.brightness = dev_priv->backlight.level; |
884 | panel->backlight.device = |
- | 885 | backlight_device_register("intel_backlight", |
|
- | 886 | connector->base.kdev, |
|
657 | 887 | connector, |
|
658 | spin_lock_irqsave(&dev_priv->backlight.lock, flags); |
888 | &intel_backlight_device_ops, &props); |
659 | props.max_brightness = intel_panel_get_max_backlight(dev); |
- | |
660 | spin_unlock_irqrestore(&dev_priv->backlight.lock, flags); |
- | |
661 | 889 | ||
662 | if (props.max_brightness == 0) { |
- | |
- | 890 | if (IS_ERR(panel->backlight.device)) { |
|
- | 891 | DRM_ERROR("Failed to register backlight: %ld\n", |
|
- | 892 | PTR_ERR(panel->backlight.device)); |
|
- | 893 | panel->backlight.device = NULL; |
|
- | 894 | return -ENODEV; |
|
663 | DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n"); |
895 | } |
664 | return -ENODEV; |
896 | return 0; |
665 | } |
897 | } |
- | 898 | ||
- | 899 | static void intel_backlight_device_unregister(struct intel_connector *connector) |
|
- | 900 | { |
|
- | 901 | struct intel_panel *panel = &connector->panel; |
|
- | 902 | ||
- | 903 | if (panel->backlight.device) { |
|
- | 904 | backlight_device_unregister(panel->backlight.device); |
|
- | 905 | panel->backlight.device = NULL; |
|
- | 906 | } |
|
- | 907 | } |
|
- | 908 | #else /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
|
- | 909 | static int intel_backlight_device_register(struct intel_connector *connector) |
|
- | 910 | { |
|
- | 911 | return 0; |
|
- | 912 | } |
|
- | 913 | static void intel_backlight_device_unregister(struct intel_connector *connector) |
|
- | 914 | { |
|
- | 915 | } |
|
- | 916 | #endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ |
|
- | 917 | ||
- | 918 | /* |
|
- | 919 | * Note: The setup hooks can't assume pipe is set! |
|
- | 920 | * |
|
- | 921 | * XXX: Query mode clock or hardware clock and program PWM modulation frequency |
|
- | 922 | * appropriately when it's 0. Use VBT and/or sane defaults. |
|
- | 923 | */ |
|
- | 924 | static int bdw_setup_backlight(struct intel_connector *connector) |
|
- | 925 | { |
|
- | 926 | struct drm_device *dev = connector->base.dev; |
|
- | 927 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 928 | struct intel_panel *panel = &connector->panel; |
|
- | 929 | u32 pch_ctl1, pch_ctl2, val; |
|
- | 930 | ||
- | 931 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
|
- | 932 | panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; |
|
- | 933 | ||
- | 934 | pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); |
|
666 | dev_priv->backlight.device = |
935 | panel->backlight.max = pch_ctl2 >> 16; |
- | 936 | if (!panel->backlight.max) |
|
- | 937 | return -ENODEV; |
|
- | 938 | ||
- | 939 | val = bdw_get_backlight(connector); |
|
- | 940 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
|
- | 941 | ||
- | 942 | panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) && |
|
- | 943 | panel->backlight.level != 0; |
|
- | 944 | ||
- | 945 | return 0; |
|
- | 946 | } |
|
- | 947 | ||
- | 948 | static int pch_setup_backlight(struct intel_connector *connector) |
|
- | 949 | { |
|
- | 950 | struct drm_device *dev = connector->base.dev; |
|
- | 951 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 952 | struct intel_panel *panel = &connector->panel; |
|
- | 953 | u32 cpu_ctl2, pch_ctl1, pch_ctl2, val; |
|
- | 954 | ||
- | 955 | pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1); |
|
- | 956 | panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY; |
|
- | 957 | ||
- | 958 | pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2); |
|
- | 959 | panel->backlight.max = pch_ctl2 >> 16; |
|
- | 960 | if (!panel->backlight.max) |
|
- | 961 | return -ENODEV; |
|
- | 962 | ||
- | 963 | val = pch_get_backlight(connector); |
|
- | 964 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
|
- | 965 | ||
- | 966 | cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2); |
|
- | 967 | panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) && |
|
- | 968 | (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0; |
|
- | 969 | ||
- | 970 | return 0; |
|
- | 971 | } |
|
- | 972 | ||
- | 973 | static int i9xx_setup_backlight(struct intel_connector *connector) |
|
- | 974 | { |
|
- | 975 | struct drm_device *dev = connector->base.dev; |
|
- | 976 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 977 | struct intel_panel *panel = &connector->panel; |
|
- | 978 | u32 ctl, val; |
|
- | 979 | ||
- | 980 | ctl = I915_READ(BLC_PWM_CTL); |
|
- | 981 | ||
- | 982 | if (IS_GEN2(dev)) |
|
- | 983 | panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE; |
|
- | 984 | ||
667 | backlight_device_register("intel_backlight", |
985 | if (IS_PINEVIEW(dev)) |
- | 986 | panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV; |
|
- | 987 | ||
- | 988 | panel->backlight.max = ctl >> 17; |
|
- | 989 | if (panel->backlight.combination_mode) |
|
- | 990 | panel->backlight.max *= 0xff; |
|
- | 991 | ||
- | 992 | if (!panel->backlight.max) |
|
668 | &connector->kdev, dev, |
993 | return -ENODEV; |
- | 994 | ||
- | 995 | val = i9xx_get_backlight(connector); |
|
- | 996 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
|
- | 997 | ||
- | 998 | panel->backlight.enabled = panel->backlight.level != 0; |
|
- | 999 | ||
- | 1000 | return 0; |
|
- | 1001 | } |
|
- | 1002 | ||
- | 1003 | static int i965_setup_backlight(struct intel_connector *connector) |
|
- | 1004 | { |
|
- | 1005 | struct drm_device *dev = connector->base.dev; |
|
- | 1006 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 1007 | struct intel_panel *panel = &connector->panel; |
|
- | 1008 | u32 ctl, ctl2, val; |
|
- | 1009 | ||
- | 1010 | ctl2 = I915_READ(BLC_PWM_CTL2); |
|
- | 1011 | panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE; |
|
- | 1012 | panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; |
|
- | 1013 | ||
- | 1014 | ctl = I915_READ(BLC_PWM_CTL); |
|
- | 1015 | panel->backlight.max = ctl >> 16; |
|
- | 1016 | if (panel->backlight.combination_mode) |
|
- | 1017 | panel->backlight.max *= 0xff; |
|
- | 1018 | ||
- | 1019 | if (!panel->backlight.max) |
|
669 | &intel_panel_bl_ops, &props); |
1020 | return -ENODEV; |
670 | 1021 | ||
671 | if (IS_ERR(dev_priv->backlight.device)) { |
1022 | val = i9xx_get_backlight(connector); |
672 | DRM_ERROR("Failed to register backlight: %ld\n", |
1023 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
673 | PTR_ERR(dev_priv->backlight.device)); |
1024 | |
674 | dev_priv->backlight.device = NULL; |
1025 | panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && |
675 | return -ENODEV; |
1026 | panel->backlight.level != 0; |
676 | } |
1027 | |
677 | return 0; |
1028 | return 0; |
678 | } |
1029 | } |
679 | 1030 | ||
680 | void intel_panel_destroy_backlight(struct drm_device *dev) |
1031 | static int vlv_setup_backlight(struct intel_connector *connector) |
- | 1032 | { |
|
681 | { |
1033 | struct drm_device *dev = connector->base.dev; |
- | 1034 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 1035 | struct intel_panel *panel = &connector->panel; |
|
- | 1036 | enum pipe pipe; |
|
- | 1037 | u32 ctl, ctl2, val; |
|
682 | struct drm_i915_private *dev_priv = dev->dev_private; |
1038 | |
- | 1039 | for_each_pipe(pipe) { |
|
- | 1040 | u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe)); |
|
683 | if (dev_priv->backlight.device) { |
1041 | |
- | 1042 | /* Skip if the modulation freq is already set */ |
|
- | 1043 | if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK) |
|
- | 1044 | continue; |
|
684 | backlight_device_unregister(dev_priv->backlight.device); |
1045 | |
- | 1046 | cur_val &= BACKLIGHT_DUTY_CYCLE_MASK; |
|
- | 1047 | I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) | |
|
685 | dev_priv->backlight.device = NULL; |
1048 | cur_val); |
- | 1049 | } |
|
- | 1050 | ||
- | 1051 | ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A)); |
|
- | 1052 | panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965; |
|
- | 1053 | ||
- | 1054 | ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A)); |
|
- | 1055 | panel->backlight.max = ctl >> 16; |
|
- | 1056 | if (!panel->backlight.max) |
|
- | 1057 | return -ENODEV; |
|
- | 1058 | ||
- | 1059 | val = _vlv_get_backlight(dev, PIPE_A); |
|
- | 1060 | panel->backlight.level = intel_panel_compute_brightness(connector, val); |
|
- | 1061 | ||
- | 1062 | panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) && |
|
- | 1063 | panel->backlight.level != 0; |
|
- | 1064 | ||
686 | } |
1065 | return 0; |
687 | } |
1066 | } |
688 | #else |
1067 | |
689 | int intel_panel_setup_backlight(struct drm_connector *connector) |
1068 | int intel_panel_setup_backlight(struct drm_connector *connector) |
- | 1069 | { |
|
- | 1070 | struct drm_device *dev = connector->dev; |
|
- | 1071 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
690 | { |
1072 | struct intel_connector *intel_connector = to_intel_connector(connector); |
- | 1073 | struct intel_panel *panel = &intel_connector->panel; |
|
- | 1074 | unsigned long flags; |
|
- | 1075 | int ret; |
|
- | 1076 | ||
- | 1077 | /* set level and max in panel struct */ |
|
- | 1078 | spin_lock_irqsave(&dev_priv->backlight_lock, flags); |
|
- | 1079 | ret = dev_priv->display.setup_backlight(intel_connector); |
|
- | 1080 | spin_unlock_irqrestore(&dev_priv->backlight_lock, flags); |
|
- | 1081 | ||
- | 1082 | if (ret) { |
|
- | 1083 | DRM_DEBUG_KMS("failed to setup backlight for connector %s\n", |
|
- | 1084 | drm_get_connector_name(connector)); |
|
- | 1085 | return ret; |
|
- | 1086 | } |
|
- | 1087 | ||
- | 1088 | intel_backlight_device_register(intel_connector); |
|
- | 1089 | ||
- | 1090 | panel->backlight.present = true; |
|
- | 1091 | ||
- | 1092 | DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, " |
|
- | 1093 | "sysfs interface %sregistered\n", |
|
- | 1094 | panel->backlight.enabled ? "enabled" : "disabled", |
|
- | 1095 | panel->backlight.level, panel->backlight.max, |
|
- | 1096 | panel->backlight.device ? "" : "not "); |
|
691 | intel_panel_init_backlight(connector->dev); |
1097 | |
692 | return 0; |
1098 | return 0; |
693 | } |
1099 | } |
694 | 1100 | ||
695 | void intel_panel_destroy_backlight(struct drm_device *dev) |
1101 | void intel_panel_destroy_backlight(struct drm_connector *connector) |
- | 1102 | { |
|
- | 1103 | struct intel_connector *intel_connector = to_intel_connector(connector); |
|
- | 1104 | struct intel_panel *panel = &intel_connector->panel; |
|
- | 1105 | ||
- | 1106 | panel->backlight.present = false; |
|
- | 1107 | intel_backlight_device_unregister(intel_connector); |
|
- | 1108 | } |
|
- | 1109 | ||
- | 1110 | /** |
|
- | 1111 | * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID |
|
- | 1112 | * @dev: drm device |
|
- | 1113 | * @fixed_mode : panel native mode |
|
- | 1114 | * @connector: LVDS/eDP connector |
|
- | 1115 | * |
|
- | 1116 | * Return downclock_avail |
|
- | 1117 | * Find the reduced downclock for LVDS/eDP in EDID. |
|
- | 1118 | */ |
|
- | 1119 | struct drm_display_mode * |
|
- | 1120 | intel_find_panel_downclock(struct drm_device *dev, |
|
- | 1121 | struct drm_display_mode *fixed_mode, |
|
- | 1122 | struct drm_connector *connector) |
|
- | 1123 | { |
|
- | 1124 | struct drm_display_mode *scan, *tmp_mode; |
|
- | 1125 | int temp_downclock; |
|
- | 1126 | ||
- | 1127 | temp_downclock = fixed_mode->clock; |
|
- | 1128 | tmp_mode = NULL; |
|
- | 1129 | ||
- | 1130 | list_for_each_entry(scan, &connector->probed_modes, head) { |
|
- | 1131 | /* |
|
- | 1132 | * If one mode has the same resolution with the fixed_panel |
|
- | 1133 | * mode while they have the different refresh rate, it means |
|
- | 1134 | * that the reduced downclock is found. In such |
|
- | 1135 | * case we can set the different FPx0/1 to dynamically select |
|
- | 1136 | * between low and high frequency. |
|
- | 1137 | */ |
|
- | 1138 | if (scan->hdisplay == fixed_mode->hdisplay && |
|
- | 1139 | scan->hsync_start == fixed_mode->hsync_start && |
|
- | 1140 | scan->hsync_end == fixed_mode->hsync_end && |
|
- | 1141 | scan->htotal == fixed_mode->htotal && |
|
- | 1142 | scan->vdisplay == fixed_mode->vdisplay && |
|
- | 1143 | scan->vsync_start == fixed_mode->vsync_start && |
|
- | 1144 | scan->vsync_end == fixed_mode->vsync_end && |
|
- | 1145 | scan->vtotal == fixed_mode->vtotal) { |
|
- | 1146 | if (scan->clock < temp_downclock) { |
|
- | 1147 | /* |
|
- | 1148 | * The downclock is already found. But we |
|
- | 1149 | * expect to find the lower downclock. |
|
- | 1150 | */ |
|
- | 1151 | temp_downclock = scan->clock; |
|
- | 1152 | tmp_mode = scan; |
|
- | 1153 | } |
|
- | 1154 | } |
|
- | 1155 | } |
|
- | 1156 | ||
- | 1157 | if (temp_downclock < fixed_mode->clock) |
|
- | 1158 | return drm_mode_duplicate(dev, tmp_mode); |
|
696 | { |
1159 | else |
- | 1160 | return NULL; |
|
- | 1161 | } |
|
- | 1162 | ||
- | 1163 | /* Set up chip specific backlight functions */ |
|
- | 1164 | void intel_panel_init_backlight_funcs(struct drm_device *dev) |
|
- | 1165 | { |
|
- | 1166 | struct drm_i915_private *dev_priv = dev->dev_private; |
|
- | 1167 | ||
- | 1168 | if (IS_BROADWELL(dev)) { |
|
- | 1169 | dev_priv->display.setup_backlight = bdw_setup_backlight; |
|
- | 1170 | dev_priv->display.enable_backlight = bdw_enable_backlight; |
|
- | 1171 | dev_priv->display.disable_backlight = pch_disable_backlight; |
|
- | 1172 | dev_priv->display.set_backlight = bdw_set_backlight; |
|
- | 1173 | dev_priv->display.get_backlight = bdw_get_backlight; |
|
- | 1174 | } else if (HAS_PCH_SPLIT(dev)) { |
|
- | 1175 | dev_priv->display.setup_backlight = pch_setup_backlight; |
|
- | 1176 | dev_priv->display.enable_backlight = pch_enable_backlight; |
|
- | 1177 | dev_priv->display.disable_backlight = pch_disable_backlight; |
|
- | 1178 | dev_priv->display.set_backlight = pch_set_backlight; |
|
- | 1179 | dev_priv->display.get_backlight = pch_get_backlight; |
|
- | 1180 | } else if (IS_VALLEYVIEW(dev)) { |
|
- | 1181 | dev_priv->display.setup_backlight = vlv_setup_backlight; |
|
- | 1182 | dev_priv->display.enable_backlight = vlv_enable_backlight; |
|
- | 1183 | dev_priv->display.disable_backlight = vlv_disable_backlight; |
|
- | 1184 | dev_priv->display.set_backlight = vlv_set_backlight; |
|
- | 1185 | dev_priv->display.get_backlight = vlv_get_backlight; |
|
- | 1186 | } else if (IS_GEN4(dev)) { |
|
- | 1187 | dev_priv->display.setup_backlight = i965_setup_backlight; |
|
- | 1188 | dev_priv->display.enable_backlight = i965_enable_backlight; |
|
- | 1189 | dev_priv->display.disable_backlight = i965_disable_backlight; |
|
- | 1190 | dev_priv->display.set_backlight = i9xx_set_backlight; |
|
- | 1191 | dev_priv->display.get_backlight = i9xx_get_backlight; |
|
- | 1192 | } else { |
|
- | 1193 | dev_priv->display.setup_backlight = i9xx_setup_backlight; |
|
- | 1194 | dev_priv->display.enable_backlight = i9xx_enable_backlight; |
|
- | 1195 | dev_priv->display.disable_backlight = i9xx_disable_backlight; |
|
- | 1196 | dev_priv->display.set_backlight = i9xx_set_backlight; |
|
- | 1197 | dev_priv->display.get_backlight = i9xx_get_backlight; |
|
697 | return; |
1198 | } |
698 | } |
- | |
699 | #endif |
1199 | } |
700 | 1200 | ||
701 | int intel_panel_init(struct intel_panel *panel, |
1201 | int intel_panel_init(struct intel_panel *panel, |
702 | struct drm_display_mode *fixed_mode) |
1202 | struct drm_display_mode *fixed_mode) |
703 | { |
1203 | { |
704 | panel->fixed_mode = fixed_mode; |
1204 | panel->fixed_mode = fixed_mode; |
705 | 1205 | ||
706 | return 0; |
1206 | return 0; |
707 | } |
1207 | } |
708 | 1208 | ||
709 | void intel_panel_fini(struct intel_panel *panel) |
1209 | void intel_panel_fini(struct intel_panel *panel) |
710 | { |
1210 | { |
711 | struct intel_connector *intel_connector = |
1211 | struct intel_connector *intel_connector = |
712 | container_of(panel, struct intel_connector, panel); |
1212 | container_of(panel, struct intel_connector, panel); |
713 | 1213 | ||
714 | if (panel->fixed_mode) |
1214 | if (panel->fixed_mode) |
715 | drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); |
1215 | drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); |
- | 1216 | ||
- | 1217 | if (panel->downclock_mode) |
|
- | 1218 | drm_mode_destroy(intel_connector->base.dev, |
|
- | 1219 | panel->downclock_mode); |
|
716 | }=><=>>>>>>><>><>><>>><>><>>><>><>><>> |
1220 | }>>><>><>><>><>><>><>>=><=>>>>><>><>><>>><>><>>><>><>><>> |