]>
Commit | Line | Data |
---|---|---|
1b082ccf AC |
1 | /* |
2 | * Copyright © 2006-2009 Intel Corporation | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program; if not, write to the Free Software Foundation, Inc., | |
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
16 | * | |
17 | * Authors: | |
18 | * Eric Anholt <eric@anholt.net> | |
19 | * Dave Airlie <airlied@linux.ie> | |
20 | * Jesse Barnes <jesse.barnes@intel.com> | |
21 | */ | |
22 | ||
23 | #include <linux/i2c.h> | |
24 | #include <drm/drmP.h> | |
05454c26 | 25 | #include <asm/intel-mid.h> |
1b082ccf AC |
26 | |
27 | #include "intel_bios.h" | |
28 | #include "psb_drv.h" | |
29 | #include "psb_intel_drv.h" | |
30 | #include "psb_intel_reg.h" | |
31 | #include "power.h" | |
32 | #include <linux/pm_runtime.h> | |
33 | ||
34 | /* The max/min PWM frequency in BPCR[31:17] - */ | |
35 | /* The smallest number is 1 (not 0) that can fit in the | |
36 | * 15-bit field of the and then*/ | |
37 | /* shifts to the left by one bit to get the actual 16-bit | |
38 | * value that the 15-bits correspond to.*/ | |
39 | #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF | |
40 | #define BRIGHTNESS_MAX_LEVEL 100 | |
41 | ||
42 | /** | |
43 | * Sets the power state for the panel. | |
44 | */ | |
45 | static void oaktrail_lvds_set_power(struct drm_device *dev, | |
367e4408 | 46 | struct gma_encoder *gma_encoder, |
9bd81acd | 47 | bool on) |
1b082ccf AC |
48 | { |
49 | u32 pp_status; | |
50 | struct drm_psb_private *dev_priv = dev->dev_private; | |
51 | ||
52 | if (!gma_power_begin(dev, true)) | |
53 | return; | |
54 | ||
55 | if (on) { | |
56 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | | |
57 | POWER_TARGET_ON); | |
58 | do { | |
59 | pp_status = REG_READ(PP_STATUS); | |
60 | } while ((pp_status & (PP_ON | PP_READY)) == PP_READY); | |
61 | dev_priv->is_lvds_on = true; | |
62 | if (dev_priv->ops->lvds_bl_power) | |
63 | dev_priv->ops->lvds_bl_power(dev, true); | |
64 | } else { | |
65 | if (dev_priv->ops->lvds_bl_power) | |
66 | dev_priv->ops->lvds_bl_power(dev, false); | |
67 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & | |
68 | ~POWER_TARGET_ON); | |
69 | do { | |
70 | pp_status = REG_READ(PP_STATUS); | |
71 | } while (pp_status & PP_ON); | |
72 | dev_priv->is_lvds_on = false; | |
73 | pm_request_idle(&dev->pdev->dev); | |
74 | } | |
75 | gma_power_end(dev); | |
76 | } | |
77 | ||
78 | static void oaktrail_lvds_dpms(struct drm_encoder *encoder, int mode) | |
79 | { | |
80 | struct drm_device *dev = encoder->dev; | |
367e4408 | 81 | struct gma_encoder *gma_encoder = to_gma_encoder(encoder); |
1b082ccf AC |
82 | |
83 | if (mode == DRM_MODE_DPMS_ON) | |
367e4408 | 84 | oaktrail_lvds_set_power(dev, gma_encoder, true); |
1b082ccf | 85 | else |
367e4408 | 86 | oaktrail_lvds_set_power(dev, gma_encoder, false); |
1b082ccf AC |
87 | |
88 | /* XXX: We never power down the LVDS pairs. */ | |
89 | } | |
90 | ||
91 | static void oaktrail_lvds_mode_set(struct drm_encoder *encoder, | |
92 | struct drm_display_mode *mode, | |
93 | struct drm_display_mode *adjusted_mode) | |
94 | { | |
1b082ccf AC |
95 | struct drm_device *dev = encoder->dev; |
96 | struct drm_psb_private *dev_priv = dev->dev_private; | |
9bd81acd PJ |
97 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
98 | struct drm_mode_config *mode_config = &dev->mode_config; | |
99 | struct drm_connector *connector = NULL; | |
100 | struct drm_crtc *crtc = encoder->crtc; | |
1b082ccf AC |
101 | u32 lvds_port; |
102 | uint64_t v = DRM_MODE_SCALE_FULLSCREEN; | |
103 | ||
104 | if (!gma_power_begin(dev, true)) | |
105 | return; | |
106 | ||
107 | /* | |
108 | * The LVDS pin pair will already have been turned on in the | |
109 | * psb_intel_crtc_mode_set since it has a large impact on the DPLL | |
110 | * settings. | |
111 | */ | |
112 | lvds_port = (REG_READ(LVDS) & | |
113 | (~LVDS_PIPEB_SELECT)) | | |
114 | LVDS_PORT_EN | | |
115 | LVDS_BORDER_EN; | |
116 | ||
117 | /* If the firmware says dither on Moorestown, or the BIOS does | |
118 | on Oaktrail then enable dithering */ | |
119 | if (mode_dev->panel_wants_dither || dev_priv->lvds_dither) | |
120 | lvds_port |= MRST_PANEL_8TO6_DITHER_ENABLE; | |
121 | ||
122 | REG_WRITE(LVDS, lvds_port); | |
123 | ||
9bd81acd PJ |
124 | /* Find the connector we're trying to set up */ |
125 | list_for_each_entry(connector, &mode_config->connector_list, head) { | |
126 | if (!connector->encoder || connector->encoder->crtc != crtc) | |
127 | continue; | |
128 | } | |
129 | ||
130 | if (!connector) { | |
131 | DRM_ERROR("Couldn't find connector when setting mode"); | |
132 | return; | |
133 | } | |
134 | ||
a69ac9ea RC |
135 | drm_object_property_get_value( |
136 | &connector->base, | |
1b082ccf AC |
137 | dev->mode_config.scaling_mode_property, |
138 | &v); | |
139 | ||
140 | if (v == DRM_MODE_SCALE_NO_SCALE) | |
141 | REG_WRITE(PFIT_CONTROL, 0); | |
142 | else if (v == DRM_MODE_SCALE_ASPECT) { | |
143 | if ((mode->vdisplay != adjusted_mode->crtc_vdisplay) || | |
144 | (mode->hdisplay != adjusted_mode->crtc_hdisplay)) { | |
145 | if ((adjusted_mode->crtc_hdisplay * mode->vdisplay) == | |
146 | (mode->hdisplay * adjusted_mode->crtc_vdisplay)) | |
147 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | |
148 | else if ((adjusted_mode->crtc_hdisplay * | |
149 | mode->vdisplay) > (mode->hdisplay * | |
150 | adjusted_mode->crtc_vdisplay)) | |
151 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | | |
152 | PFIT_SCALING_MODE_PILLARBOX); | |
153 | else | |
154 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | | |
155 | PFIT_SCALING_MODE_LETTERBOX); | |
156 | } else | |
157 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | |
158 | } else /*(v == DRM_MODE_SCALE_FULLSCREEN)*/ | |
159 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | |
160 | ||
161 | gma_power_end(dev); | |
162 | } | |
163 | ||
164 | static void oaktrail_lvds_prepare(struct drm_encoder *encoder) | |
165 | { | |
166 | struct drm_device *dev = encoder->dev; | |
9bd81acd | 167 | struct drm_psb_private *dev_priv = dev->dev_private; |
367e4408 | 168 | struct gma_encoder *gma_encoder = to_gma_encoder(encoder); |
9bd81acd | 169 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
1b082ccf AC |
170 | |
171 | if (!gma_power_begin(dev, true)) | |
172 | return; | |
173 | ||
174 | mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); | |
175 | mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & | |
176 | BACKLIGHT_DUTY_CYCLE_MASK); | |
367e4408 | 177 | oaktrail_lvds_set_power(dev, gma_encoder, false); |
1b082ccf AC |
178 | gma_power_end(dev); |
179 | } | |
180 | ||
181 | static u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev) | |
182 | { | |
183 | struct drm_psb_private *dev_priv = dev->dev_private; | |
184 | u32 ret; | |
185 | ||
186 | if (gma_power_begin(dev, false)) { | |
187 | ret = ((REG_READ(BLC_PWM_CTL) & | |
188 | BACKLIGHT_MODULATION_FREQ_MASK) >> | |
189 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | |
190 | ||
191 | gma_power_end(dev); | |
192 | } else | |
648a8e34 | 193 | ret = ((dev_priv->regs.saveBLC_PWM_CTL & |
1b082ccf AC |
194 | BACKLIGHT_MODULATION_FREQ_MASK) >> |
195 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | |
196 | ||
197 | return ret; | |
198 | } | |
199 | ||
200 | static void oaktrail_lvds_commit(struct drm_encoder *encoder) | |
201 | { | |
202 | struct drm_device *dev = encoder->dev; | |
9bd81acd | 203 | struct drm_psb_private *dev_priv = dev->dev_private; |
367e4408 | 204 | struct gma_encoder *gma_encoder = to_gma_encoder(encoder); |
9bd81acd | 205 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
1b082ccf AC |
206 | |
207 | if (mode_dev->backlight_duty_cycle == 0) | |
208 | mode_dev->backlight_duty_cycle = | |
209 | oaktrail_lvds_get_max_backlight(dev); | |
367e4408 | 210 | oaktrail_lvds_set_power(dev, gma_encoder, true); |
1b082ccf AC |
211 | } |
212 | ||
213 | static const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = { | |
214 | .dpms = oaktrail_lvds_dpms, | |
215 | .mode_fixup = psb_intel_lvds_mode_fixup, | |
216 | .prepare = oaktrail_lvds_prepare, | |
217 | .mode_set = oaktrail_lvds_mode_set, | |
218 | .commit = oaktrail_lvds_commit, | |
219 | }; | |
220 | ||
1b082ccf AC |
221 | /* Returns the panel fixed mode from configuration. */ |
222 | ||
1b22edfd AC |
223 | static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, |
224 | struct psb_intel_mode_device *mode_dev) | |
1b082ccf AC |
225 | { |
226 | struct drm_display_mode *mode = NULL; | |
227 | struct drm_psb_private *dev_priv = dev->dev_private; | |
228 | struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; | |
229 | ||
1b22edfd AC |
230 | mode_dev->panel_fixed_mode = NULL; |
231 | ||
232 | /* Use the firmware provided data on Moorestown */ | |
4086b1e2 | 233 | if (dev_priv->has_gct) { |
1b082ccf AC |
234 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); |
235 | if (!mode) | |
1b22edfd | 236 | return; |
1b082ccf AC |
237 | |
238 | mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; | |
239 | mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; | |
240 | mode->hsync_start = mode->hdisplay + \ | |
241 | ((ti->hsync_offset_hi << 8) | \ | |
242 | ti->hsync_offset_lo); | |
243 | mode->hsync_end = mode->hsync_start + \ | |
244 | ((ti->hsync_pulse_width_hi << 8) | \ | |
245 | ti->hsync_pulse_width_lo); | |
246 | mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ | |
247 | ti->hblank_lo); | |
248 | mode->vsync_start = \ | |
249 | mode->vdisplay + ((ti->vsync_offset_hi << 4) | \ | |
250 | ti->vsync_offset_lo); | |
251 | mode->vsync_end = \ | |
252 | mode->vsync_start + ((ti->vsync_pulse_width_hi << 4) | \ | |
253 | ti->vsync_pulse_width_lo); | |
254 | mode->vtotal = mode->vdisplay + \ | |
255 | ((ti->vblank_hi << 8) | ti->vblank_lo); | |
256 | mode->clock = ti->pixel_clock * 10; | |
257 | #if 0 | |
8dfe162a JP |
258 | pr_info("hdisplay is %d\n", mode->hdisplay); |
259 | pr_info("vdisplay is %d\n", mode->vdisplay); | |
260 | pr_info("HSS is %d\n", mode->hsync_start); | |
261 | pr_info("HSE is %d\n", mode->hsync_end); | |
262 | pr_info("htotal is %d\n", mode->htotal); | |
263 | pr_info("VSS is %d\n", mode->vsync_start); | |
264 | pr_info("VSE is %d\n", mode->vsync_end); | |
265 | pr_info("vtotal is %d\n", mode->vtotal); | |
266 | pr_info("clock is %d\n", mode->clock); | |
1b082ccf | 267 | #endif |
1b22edfd AC |
268 | mode_dev->panel_fixed_mode = mode; |
269 | } | |
1b082ccf | 270 | |
1b22edfd AC |
271 | /* Use the BIOS VBT mode if available */ |
272 | if (mode_dev->panel_fixed_mode == NULL && mode_dev->vbt_mode) | |
273 | mode_dev->panel_fixed_mode = drm_mode_duplicate(dev, | |
274 | mode_dev->vbt_mode); | |
275 | ||
276 | /* Then try the LVDS VBT mode */ | |
277 | if (mode_dev->panel_fixed_mode == NULL) | |
278 | if (dev_priv->lfp_lvds_vbt_mode) | |
279 | mode_dev->panel_fixed_mode = | |
280 | drm_mode_duplicate(dev, | |
281 | dev_priv->lfp_lvds_vbt_mode); | |
49a5d87a PJ |
282 | |
283 | /* If we still got no mode then bail */ | |
1b22edfd | 284 | if (mode_dev->panel_fixed_mode == NULL) |
49a5d87a | 285 | return; |
1b22edfd AC |
286 | |
287 | drm_mode_set_name(mode_dev->panel_fixed_mode); | |
288 | drm_mode_set_crtcinfo(mode_dev->panel_fixed_mode, 0); | |
1b082ccf AC |
289 | } |
290 | ||
291 | /** | |
292 | * oaktrail_lvds_init - setup LVDS connectors on this device | |
293 | * @dev: drm device | |
294 | * | |
295 | * Create the connector, register the LVDS DDC bus, and try to figure out what | |
296 | * modes we can display on the LVDS panel (if present). | |
297 | */ | |
298 | void oaktrail_lvds_init(struct drm_device *dev, | |
299 | struct psb_intel_mode_device *mode_dev) | |
300 | { | |
367e4408 | 301 | struct gma_encoder *gma_encoder; |
a3d5d75f | 302 | struct gma_connector *gma_connector; |
1b082ccf AC |
303 | struct drm_connector *connector; |
304 | struct drm_encoder *encoder; | |
5d3852dc | 305 | struct drm_psb_private *dev_priv = dev->dev_private; |
1b082ccf | 306 | struct edid *edid; |
1b082ccf AC |
307 | struct i2c_adapter *i2c_adap; |
308 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ | |
309 | ||
367e4408 PJ |
310 | gma_encoder = kzalloc(sizeof(struct gma_encoder), GFP_KERNEL); |
311 | if (!gma_encoder) | |
1b082ccf AC |
312 | return; |
313 | ||
a3d5d75f PJ |
314 | gma_connector = kzalloc(sizeof(struct gma_connector), GFP_KERNEL); |
315 | if (!gma_connector) | |
9bd81acd PJ |
316 | goto failed_connector; |
317 | ||
a3d5d75f | 318 | connector = &gma_connector->base; |
367e4408 | 319 | encoder = &gma_encoder->base; |
1b082ccf | 320 | dev_priv->is_lvds_on = true; |
9bd81acd | 321 | drm_connector_init(dev, connector, |
1b082ccf AC |
322 | &psb_intel_lvds_connector_funcs, |
323 | DRM_MODE_CONNECTOR_LVDS); | |
324 | ||
9bd81acd | 325 | drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs, |
13a3d91f | 326 | DRM_MODE_ENCODER_LVDS, NULL); |
1b082ccf | 327 | |
367e4408 PJ |
328 | gma_connector_attach_encoder(gma_connector, gma_encoder); |
329 | gma_encoder->type = INTEL_OUTPUT_LVDS; | |
1b082ccf AC |
330 | |
331 | drm_encoder_helper_add(encoder, &oaktrail_lvds_helper_funcs); | |
332 | drm_connector_helper_add(connector, | |
333 | &psb_intel_lvds_connector_helper_funcs); | |
334 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | |
335 | connector->interlace_allowed = false; | |
336 | connector->doublescan_allowed = false; | |
337 | ||
a69ac9ea | 338 | drm_object_attach_property(&connector->base, |
1b082ccf AC |
339 | dev->mode_config.scaling_mode_property, |
340 | DRM_MODE_SCALE_FULLSCREEN); | |
a69ac9ea | 341 | drm_object_attach_property(&connector->base, |
1b082ccf AC |
342 | dev_priv->backlight_property, |
343 | BRIGHTNESS_MAX_LEVEL); | |
344 | ||
345 | mode_dev->panel_wants_dither = false; | |
4086b1e2 | 346 | if (dev_priv->has_gct) |
1b082ccf AC |
347 | mode_dev->panel_wants_dither = (dev_priv->gct_data. |
348 | Panel_Port_Control & MRST_PANEL_8TO6_DITHER_ENABLE); | |
e2e022ec AC |
349 | if (dev_priv->lvds_dither) |
350 | mode_dev->panel_wants_dither = 1; | |
1b082ccf AC |
351 | |
352 | /* | |
353 | * LVDS discovery: | |
354 | * 1) check for EDID on DDC | |
355 | * 2) check for VBT data | |
356 | * 3) check to see if LVDS is already on | |
357 | * if none of the above, no panel | |
358 | * 4) make sure lid is open | |
359 | * if closed, act like it's not there for now | |
360 | */ | |
361 | ||
5a52b1f2 | 362 | edid = NULL; |
c46145ae | 363 | mutex_lock(&dev->mode_config.mutex); |
1b082ccf | 364 | i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); |
5a52b1f2 JS |
365 | if (i2c_adap) |
366 | edid = drm_get_edid(connector, i2c_adap); | |
367 | if (edid == NULL && dev_priv->lpc_gpio_base) { | |
368 | oaktrail_lvds_i2c_init(encoder); | |
369 | if (gma_encoder->ddc_bus != NULL) { | |
370 | i2c_adap = &gma_encoder->ddc_bus->adapter; | |
371 | edid = drm_get_edid(connector, i2c_adap); | |
372 | } | |
373 | } | |
1b082ccf AC |
374 | /* |
375 | * Attempt to get the fixed panel mode from DDC. Assume that the | |
376 | * preferred mode is the right one. | |
377 | */ | |
5a52b1f2 JS |
378 | if (edid) { |
379 | drm_mode_connector_update_edid_property(connector, edid); | |
380 | drm_add_edid_modes(connector, edid); | |
381 | kfree(edid); | |
1b082ccf AC |
382 | |
383 | list_for_each_entry(scan, &connector->probed_modes, head) { | |
384 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { | |
385 | mode_dev->panel_fixed_mode = | |
386 | drm_mode_duplicate(dev, scan); | |
387 | goto out; /* FIXME: check for quirks */ | |
388 | } | |
389 | } | |
5a52b1f2 JS |
390 | } else |
391 | dev_err(dev->dev, "No ddc adapter available!\n"); | |
1b082ccf AC |
392 | /* |
393 | * If we didn't get EDID, try geting panel timing | |
394 | * from configuration data | |
395 | */ | |
1b22edfd | 396 | oaktrail_lvds_get_configuration_mode(dev, mode_dev); |
1b082ccf AC |
397 | |
398 | if (mode_dev->panel_fixed_mode) { | |
399 | mode_dev->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; | |
400 | goto out; /* FIXME: check for quirks */ | |
401 | } | |
402 | ||
403 | /* If we still don't have a mode after all that, give up. */ | |
404 | if (!mode_dev->panel_fixed_mode) { | |
405 | dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); | |
406 | goto failed_find; | |
407 | } | |
408 | ||
409 | out: | |
c46145ae DV |
410 | mutex_unlock(&dev->mode_config.mutex); |
411 | ||
34ea3d38 | 412 | drm_connector_register(connector); |
1b082ccf AC |
413 | return; |
414 | ||
415 | failed_find: | |
c46145ae DV |
416 | mutex_unlock(&dev->mode_config.mutex); |
417 | ||
1b082ccf | 418 | dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); |
5a52b1f2 | 419 | if (gma_encoder->ddc_bus) { |
367e4408 | 420 | psb_intel_i2c_destroy(gma_encoder->ddc_bus); |
5a52b1f2 JS |
421 | gma_encoder->ddc_bus = NULL; |
422 | } | |
1b082ccf AC |
423 | |
424 | /* failed_ddc: */ | |
425 | ||
426 | drm_encoder_cleanup(encoder); | |
427 | drm_connector_cleanup(connector); | |
a3d5d75f | 428 | kfree(gma_connector); |
9bd81acd | 429 | failed_connector: |
367e4408 | 430 | kfree(gma_encoder); |
1b082ccf AC |
431 | } |
432 |