1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright © 2006-2011 Intel Corporation |
4 | * |
5 | * Authors: |
6 | * Eric Anholt <eric@anholt.net> |
7 | * Dave Airlie <airlied@linux.ie> |
8 | * Jesse Barnes <jesse.barnes@intel.com> |
9 | */ |
10 | |
11 | #include <linux/dmi.h> |
12 | #include <linux/i2c.h> |
13 | #include <linux/pm_runtime.h> |
14 | |
15 | #include <drm/drm_crtc_helper.h> |
16 | #include <drm/drm_modeset_helper_vtables.h> |
17 | #include <drm/drm_simple_kms_helper.h> |
18 | |
19 | #include "cdv_device.h" |
20 | #include "intel_bios.h" |
21 | #include "power.h" |
22 | #include "psb_drv.h" |
23 | #include "psb_intel_drv.h" |
24 | #include "psb_intel_reg.h" |
25 | |
26 | /* |
27 | * LVDS I2C backlight control macros |
28 | */ |
29 | #define BRIGHTNESS_MAX_LEVEL 100 |
30 | #define BRIGHTNESS_MASK 0xFF |
31 | #define BLC_I2C_TYPE 0x01 |
32 | #define BLC_PWM_TYPT 0x02 |
33 | |
34 | #define BLC_POLARITY_NORMAL 0 |
35 | #define BLC_POLARITY_INVERSE 1 |
36 | |
37 | #define PSB_BLC_MAX_PWM_REG_FREQ (0xFFFE) |
38 | #define PSB_BLC_MIN_PWM_REG_FREQ (0x2) |
39 | #define PSB_BLC_PWM_PRECISION_FACTOR (10) |
40 | #define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) |
41 | #define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) |
42 | |
43 | struct cdv_intel_lvds_priv { |
44 | /** |
45 | * Saved LVDO output states |
46 | */ |
47 | uint32_t savePP_ON; |
48 | uint32_t savePP_OFF; |
49 | uint32_t saveLVDS; |
50 | uint32_t savePP_CONTROL; |
51 | uint32_t savePP_CYCLE; |
52 | uint32_t savePFIT_CONTROL; |
53 | uint32_t savePFIT_PGM_RATIOS; |
54 | uint32_t saveBLC_PWM_CTL; |
55 | }; |
56 | |
57 | /* |
58 | * Returns the maximum level of the backlight duty cycle field. |
59 | */ |
60 | static u32 cdv_intel_lvds_get_max_backlight(struct drm_device *dev) |
61 | { |
62 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
63 | u32 retval; |
64 | |
65 | if (gma_power_begin(dev, force: false)) { |
66 | retval = ((REG_READ(BLC_PWM_CTL) & |
67 | BACKLIGHT_MODULATION_FREQ_MASK) >> |
68 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; |
69 | |
70 | gma_power_end(dev); |
71 | } else |
72 | retval = ((dev_priv->regs.saveBLC_PWM_CTL & |
73 | BACKLIGHT_MODULATION_FREQ_MASK) >> |
74 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; |
75 | |
76 | return retval; |
77 | } |
78 | |
79 | /* |
80 | * Sets the backlight level. |
81 | * |
82 | * level backlight level, from 0 to cdv_intel_lvds_get_max_backlight(). |
83 | */ |
84 | static void cdv_intel_lvds_set_backlight(struct drm_device *dev, int level) |
85 | { |
86 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
87 | u32 blc_pwm_ctl; |
88 | |
89 | if (gma_power_begin(dev, force: false)) { |
90 | blc_pwm_ctl = |
91 | REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; |
92 | REG_WRITE(BLC_PWM_CTL, |
93 | (blc_pwm_ctl | |
94 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); |
95 | gma_power_end(dev); |
96 | } else { |
97 | blc_pwm_ctl = dev_priv->regs.saveBLC_PWM_CTL & |
98 | ~BACKLIGHT_DUTY_CYCLE_MASK; |
99 | dev_priv->regs.saveBLC_PWM_CTL = (blc_pwm_ctl | |
100 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); |
101 | } |
102 | } |
103 | |
104 | /* |
105 | * Sets the power state for the panel. |
106 | */ |
107 | static void cdv_intel_lvds_set_power(struct drm_device *dev, |
108 | struct drm_encoder *encoder, bool on) |
109 | { |
110 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
111 | u32 pp_status; |
112 | |
113 | if (!gma_power_begin(dev, force: true)) |
114 | return; |
115 | |
116 | if (on) { |
117 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | |
118 | POWER_TARGET_ON); |
119 | do { |
120 | pp_status = REG_READ(PP_STATUS); |
121 | } while ((pp_status & PP_ON) == 0); |
122 | |
123 | cdv_intel_lvds_set_backlight(dev, |
124 | level: dev_priv->mode_dev.backlight_duty_cycle); |
125 | } else { |
126 | cdv_intel_lvds_set_backlight(dev, level: 0); |
127 | |
128 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & |
129 | ~POWER_TARGET_ON); |
130 | do { |
131 | pp_status = REG_READ(PP_STATUS); |
132 | } while (pp_status & PP_ON); |
133 | } |
134 | gma_power_end(dev); |
135 | } |
136 | |
137 | static void cdv_intel_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) |
138 | { |
139 | struct drm_device *dev = encoder->dev; |
140 | if (mode == DRM_MODE_DPMS_ON) |
141 | cdv_intel_lvds_set_power(dev, encoder, on: true); |
142 | else |
143 | cdv_intel_lvds_set_power(dev, encoder, on: false); |
144 | /* XXX: We never power down the LVDS pairs. */ |
145 | } |
146 | |
147 | static void cdv_intel_lvds_save(struct drm_connector *connector) |
148 | { |
149 | } |
150 | |
151 | static void cdv_intel_lvds_restore(struct drm_connector *connector) |
152 | { |
153 | } |
154 | |
155 | static enum drm_mode_status cdv_intel_lvds_mode_valid(struct drm_connector *connector, |
156 | struct drm_display_mode *mode) |
157 | { |
158 | struct drm_device *dev = connector->dev; |
159 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
160 | struct drm_display_mode *fixed_mode = |
161 | dev_priv->mode_dev.panel_fixed_mode; |
162 | |
163 | /* just in case */ |
164 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
165 | return MODE_NO_DBLESCAN; |
166 | |
167 | /* just in case */ |
168 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
169 | return MODE_NO_INTERLACE; |
170 | |
171 | if (fixed_mode) { |
172 | if (mode->hdisplay > fixed_mode->hdisplay) |
173 | return MODE_PANEL; |
174 | if (mode->vdisplay > fixed_mode->vdisplay) |
175 | return MODE_PANEL; |
176 | } |
177 | return MODE_OK; |
178 | } |
179 | |
180 | static bool cdv_intel_lvds_mode_fixup(struct drm_encoder *encoder, |
181 | const struct drm_display_mode *mode, |
182 | struct drm_display_mode *adjusted_mode) |
183 | { |
184 | struct drm_device *dev = encoder->dev; |
185 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
186 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
187 | struct drm_encoder *tmp_encoder; |
188 | struct drm_display_mode *panel_fixed_mode = mode_dev->panel_fixed_mode; |
189 | |
190 | /* Should never happen!! */ |
191 | list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, |
192 | head) { |
193 | if (tmp_encoder != encoder |
194 | && tmp_encoder->crtc == encoder->crtc) { |
195 | pr_err("Can't enable LVDS and another encoder on the same pipe\n" ); |
196 | return false; |
197 | } |
198 | } |
199 | |
200 | /* |
201 | * If we have timings from the BIOS for the panel, put them in |
202 | * to the adjusted mode. The CRTC will be set up for this mode, |
203 | * with the panel scaling set up to source from the H/VDisplay |
204 | * of the original mode. |
205 | */ |
206 | if (panel_fixed_mode != NULL) { |
207 | adjusted_mode->hdisplay = panel_fixed_mode->hdisplay; |
208 | adjusted_mode->hsync_start = panel_fixed_mode->hsync_start; |
209 | adjusted_mode->hsync_end = panel_fixed_mode->hsync_end; |
210 | adjusted_mode->htotal = panel_fixed_mode->htotal; |
211 | adjusted_mode->vdisplay = panel_fixed_mode->vdisplay; |
212 | adjusted_mode->vsync_start = panel_fixed_mode->vsync_start; |
213 | adjusted_mode->vsync_end = panel_fixed_mode->vsync_end; |
214 | adjusted_mode->vtotal = panel_fixed_mode->vtotal; |
215 | adjusted_mode->clock = panel_fixed_mode->clock; |
216 | drm_mode_set_crtcinfo(p: adjusted_mode, |
217 | CRTC_INTERLACE_HALVE_V); |
218 | } |
219 | |
220 | /* |
221 | * XXX: It would be nice to support lower refresh rates on the |
222 | * panels to reduce power consumption, and perhaps match the |
223 | * user's requested refresh rate. |
224 | */ |
225 | |
226 | return true; |
227 | } |
228 | |
229 | static void cdv_intel_lvds_prepare(struct drm_encoder *encoder) |
230 | { |
231 | struct drm_device *dev = encoder->dev; |
232 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
233 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
234 | |
235 | if (!gma_power_begin(dev, force: true)) |
236 | return; |
237 | |
238 | mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); |
239 | mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & |
240 | BACKLIGHT_DUTY_CYCLE_MASK); |
241 | |
242 | cdv_intel_lvds_set_power(dev, encoder, on: false); |
243 | |
244 | gma_power_end(dev); |
245 | } |
246 | |
247 | static void cdv_intel_lvds_commit(struct drm_encoder *encoder) |
248 | { |
249 | struct drm_device *dev = encoder->dev; |
250 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
251 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
252 | |
253 | if (mode_dev->backlight_duty_cycle == 0) |
254 | mode_dev->backlight_duty_cycle = |
255 | cdv_intel_lvds_get_max_backlight(dev); |
256 | |
257 | cdv_intel_lvds_set_power(dev, encoder, on: true); |
258 | } |
259 | |
260 | static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder, |
261 | struct drm_display_mode *mode, |
262 | struct drm_display_mode *adjusted_mode) |
263 | { |
264 | struct drm_device *dev = encoder->dev; |
265 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
266 | struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc); |
267 | u32 pfit_control; |
268 | |
269 | /* |
270 | * The LVDS pin pair will already have been turned on in the |
271 | * cdv_intel_crtc_mode_set since it has a large impact on the DPLL |
272 | * settings. |
273 | */ |
274 | |
275 | /* |
276 | * Enable automatic panel scaling so that non-native modes fill the |
277 | * screen. Should be enabled before the pipe is enabled, according to |
278 | * register description and PRM. |
279 | */ |
280 | if (mode->hdisplay != adjusted_mode->hdisplay || |
281 | mode->vdisplay != adjusted_mode->vdisplay) |
282 | pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | |
283 | HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | |
284 | HORIZ_INTERP_BILINEAR); |
285 | else |
286 | pfit_control = 0; |
287 | |
288 | pfit_control |= gma_crtc->pipe << PFIT_PIPE_SHIFT; |
289 | |
290 | if (dev_priv->lvds_dither) |
291 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; |
292 | |
293 | REG_WRITE(PFIT_CONTROL, pfit_control); |
294 | } |
295 | |
296 | /* |
297 | * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. |
298 | */ |
299 | static int cdv_intel_lvds_get_modes(struct drm_connector *connector) |
300 | { |
301 | struct drm_device *dev = connector->dev; |
302 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
303 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
304 | int ret; |
305 | |
306 | ret = psb_intel_ddc_get_modes(connector, adapter: connector->ddc); |
307 | |
308 | if (ret) |
309 | return ret; |
310 | |
311 | if (mode_dev->panel_fixed_mode != NULL) { |
312 | struct drm_display_mode *mode = |
313 | drm_mode_duplicate(dev, mode: mode_dev->panel_fixed_mode); |
314 | drm_mode_probed_add(connector, mode); |
315 | return 1; |
316 | } |
317 | |
318 | return 0; |
319 | } |
320 | |
321 | static void cdv_intel_lvds_destroy(struct drm_connector *connector) |
322 | { |
323 | struct gma_connector *gma_connector = to_gma_connector(connector); |
324 | struct gma_encoder *gma_encoder = gma_attached_encoder(connector); |
325 | |
326 | gma_i2c_destroy(to_gma_i2c_chan(connector->ddc)); |
327 | gma_i2c_destroy(chan: gma_encoder->i2c_bus); |
328 | drm_connector_cleanup(connector); |
329 | kfree(objp: gma_connector); |
330 | } |
331 | |
332 | static int cdv_intel_lvds_set_property(struct drm_connector *connector, |
333 | struct drm_property *property, |
334 | uint64_t value) |
335 | { |
336 | struct drm_encoder *encoder = connector->encoder; |
337 | |
338 | if (!strcmp(property->name, "scaling mode" ) && encoder) { |
339 | struct gma_crtc *crtc = to_gma_crtc(encoder->crtc); |
340 | uint64_t curValue; |
341 | |
342 | if (!crtc) |
343 | return -1; |
344 | |
345 | switch (value) { |
346 | case DRM_MODE_SCALE_FULLSCREEN: |
347 | break; |
348 | case DRM_MODE_SCALE_NO_SCALE: |
349 | break; |
350 | case DRM_MODE_SCALE_ASPECT: |
351 | break; |
352 | default: |
353 | return -1; |
354 | } |
355 | |
356 | if (drm_object_property_get_value(obj: &connector->base, |
357 | property, |
358 | value: &curValue)) |
359 | return -1; |
360 | |
361 | if (curValue == value) |
362 | return 0; |
363 | |
364 | if (drm_object_property_set_value(obj: &connector->base, |
365 | property, |
366 | val: value)) |
367 | return -1; |
368 | |
369 | if (crtc->saved_mode.hdisplay != 0 && |
370 | crtc->saved_mode.vdisplay != 0) { |
371 | if (!drm_crtc_helper_set_mode(crtc: encoder->crtc, |
372 | mode: &crtc->saved_mode, |
373 | x: encoder->crtc->x, |
374 | y: encoder->crtc->y, |
375 | old_fb: encoder->crtc->primary->fb)) |
376 | return -1; |
377 | } |
378 | } else if (!strcmp(property->name, "backlight" ) && encoder) { |
379 | if (drm_object_property_set_value(obj: &connector->base, |
380 | property, |
381 | val: value)) |
382 | return -1; |
383 | else |
384 | gma_backlight_set(dev: encoder->dev, v: value); |
385 | } else if (!strcmp(property->name, "DPMS" ) && encoder) { |
386 | const struct drm_encoder_helper_funcs *helpers = |
387 | encoder->helper_private; |
388 | helpers->dpms(encoder, value); |
389 | } |
390 | return 0; |
391 | } |
392 | |
393 | static const struct drm_encoder_helper_funcs |
394 | cdv_intel_lvds_helper_funcs = { |
395 | .dpms = cdv_intel_lvds_encoder_dpms, |
396 | .mode_fixup = cdv_intel_lvds_mode_fixup, |
397 | .prepare = cdv_intel_lvds_prepare, |
398 | .mode_set = cdv_intel_lvds_mode_set, |
399 | .commit = cdv_intel_lvds_commit, |
400 | }; |
401 | |
402 | static const struct drm_connector_helper_funcs |
403 | cdv_intel_lvds_connector_helper_funcs = { |
404 | .get_modes = cdv_intel_lvds_get_modes, |
405 | .mode_valid = cdv_intel_lvds_mode_valid, |
406 | .best_encoder = gma_best_encoder, |
407 | }; |
408 | |
409 | static const struct drm_connector_funcs cdv_intel_lvds_connector_funcs = { |
410 | .dpms = drm_helper_connector_dpms, |
411 | .fill_modes = drm_helper_probe_single_connector_modes, |
412 | .set_property = cdv_intel_lvds_set_property, |
413 | .destroy = cdv_intel_lvds_destroy, |
414 | }; |
415 | |
416 | /* |
417 | * Enumerate the child dev array parsed from VBT to check whether |
418 | * the LVDS is present. |
419 | * If it is present, return 1. |
420 | * If it is not present, return false. |
421 | * If no child dev is parsed from VBT, it assumes that the LVDS is present. |
422 | */ |
423 | static bool lvds_is_present_in_vbt(struct drm_device *dev, |
424 | u8 *i2c_pin) |
425 | { |
426 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
427 | int i; |
428 | |
429 | if (!dev_priv->child_dev_num) |
430 | return true; |
431 | |
432 | for (i = 0; i < dev_priv->child_dev_num; i++) { |
433 | struct child_device_config *child = dev_priv->child_dev + i; |
434 | |
435 | /* If the device type is not LFP, continue. |
436 | * We have to check both the new identifiers as well as the |
437 | * old for compatibility with some BIOSes. |
438 | */ |
439 | if (child->device_type != DEVICE_TYPE_INT_LFP && |
440 | child->device_type != DEVICE_TYPE_LFP) |
441 | continue; |
442 | |
443 | if (child->i2c_pin) |
444 | *i2c_pin = child->i2c_pin; |
445 | |
446 | /* However, we cannot trust the BIOS writers to populate |
447 | * the VBT correctly. Since LVDS requires additional |
448 | * information from AIM blocks, a non-zero addin offset is |
449 | * a good indicator that the LVDS is actually present. |
450 | */ |
451 | if (child->addin_offset) |
452 | return true; |
453 | |
454 | /* But even then some BIOS writers perform some black magic |
455 | * and instantiate the device without reference to any |
456 | * additional data. Trust that if the VBT was written into |
457 | * the OpRegion then they have validated the LVDS's existence. |
458 | */ |
459 | if (dev_priv->opregion.vbt) |
460 | return true; |
461 | } |
462 | |
463 | return false; |
464 | } |
465 | |
466 | /** |
467 | * cdv_intel_lvds_init - setup LVDS connectors on this device |
468 | * @dev: drm device |
469 | * @mode_dev: PSB mode device |
470 | * |
471 | * Create the connector, register the LVDS DDC bus, and try to figure out what |
472 | * modes we can display on the LVDS panel (if present). |
473 | */ |
474 | void cdv_intel_lvds_init(struct drm_device *dev, |
475 | struct psb_intel_mode_device *mode_dev) |
476 | { |
477 | struct gma_encoder *gma_encoder; |
478 | struct gma_connector *gma_connector; |
479 | struct cdv_intel_lvds_priv *lvds_priv; |
480 | struct drm_connector *connector; |
481 | struct drm_encoder *encoder; |
482 | struct drm_display_mode *scan; |
483 | struct drm_crtc *crtc; |
484 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
485 | struct gma_i2c_chan *ddc_bus; |
486 | u32 lvds; |
487 | int pipe; |
488 | int ret; |
489 | u8 pin; |
490 | |
491 | if (!dev_priv->lvds_enabled_in_vbt) |
492 | return; |
493 | |
494 | pin = GMBUS_PORT_PANEL; |
495 | if (!lvds_is_present_in_vbt(dev, i2c_pin: &pin)) { |
496 | DRM_DEBUG_KMS("LVDS is not present in VBT\n" ); |
497 | return; |
498 | } |
499 | |
500 | gma_encoder = kzalloc(size: sizeof(struct gma_encoder), |
501 | GFP_KERNEL); |
502 | if (!gma_encoder) |
503 | return; |
504 | |
505 | gma_connector = kzalloc(size: sizeof(struct gma_connector), |
506 | GFP_KERNEL); |
507 | if (!gma_connector) |
508 | goto err_free_encoder; |
509 | |
510 | lvds_priv = kzalloc(size: sizeof(struct cdv_intel_lvds_priv), GFP_KERNEL); |
511 | if (!lvds_priv) |
512 | goto err_free_connector; |
513 | |
514 | gma_encoder->dev_priv = lvds_priv; |
515 | |
516 | connector = &gma_connector->base; |
517 | gma_connector->save = cdv_intel_lvds_save; |
518 | gma_connector->restore = cdv_intel_lvds_restore; |
519 | encoder = &gma_encoder->base; |
520 | |
521 | /* Set up the DDC bus. */ |
522 | ddc_bus = gma_i2c_create(dev, GPIOC, name: "LVDSDDC_C" ); |
523 | if (!ddc_bus) { |
524 | dev_printk(KERN_ERR, dev->dev, |
525 | "DDC bus registration " "failed.\n" ); |
526 | goto err_free_lvds_priv; |
527 | } |
528 | |
529 | ret = drm_connector_init_with_ddc(dev, connector, |
530 | funcs: &cdv_intel_lvds_connector_funcs, |
531 | DRM_MODE_CONNECTOR_LVDS, |
532 | ddc: &ddc_bus->base); |
533 | if (ret) |
534 | goto err_destroy_ddc; |
535 | |
536 | ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_LVDS); |
537 | if (ret) |
538 | goto err_connector_cleanup; |
539 | |
540 | gma_connector_attach_encoder(connector: gma_connector, encoder: gma_encoder); |
541 | gma_encoder->type = INTEL_OUTPUT_LVDS; |
542 | |
543 | drm_encoder_helper_add(encoder, funcs: &cdv_intel_lvds_helper_funcs); |
544 | drm_connector_helper_add(connector, |
545 | funcs: &cdv_intel_lvds_connector_helper_funcs); |
546 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; |
547 | connector->interlace_allowed = false; |
548 | connector->doublescan_allowed = false; |
549 | |
550 | /*Attach connector properties*/ |
551 | drm_object_attach_property(obj: &connector->base, |
552 | property: dev->mode_config.scaling_mode_property, |
553 | DRM_MODE_SCALE_FULLSCREEN); |
554 | drm_object_attach_property(obj: &connector->base, |
555 | property: dev_priv->backlight_property, |
556 | BRIGHTNESS_MAX_LEVEL); |
557 | |
558 | /** |
559 | * Set up I2C bus |
560 | * FIXME: distroy i2c_bus when exit |
561 | */ |
562 | gma_encoder->i2c_bus = gma_i2c_create(dev, GPIOB, name: "LVDSBLC_B" ); |
563 | if (!gma_encoder->i2c_bus) { |
564 | dev_printk(KERN_ERR, |
565 | dev->dev, "I2C bus registration failed.\n" ); |
566 | goto err_encoder_cleanup; |
567 | } |
568 | gma_encoder->i2c_bus->slave_addr = 0x2C; |
569 | dev_priv->lvds_i2c_bus = gma_encoder->i2c_bus; |
570 | |
571 | /* |
572 | * LVDS discovery: |
573 | * 1) check for EDID on DDC |
574 | * 2) check for VBT data |
575 | * 3) check to see if LVDS is already on |
576 | * if none of the above, no panel |
577 | * 4) make sure lid is open |
578 | * if closed, act like it's not there for now |
579 | */ |
580 | |
581 | /* |
582 | * Attempt to get the fixed panel mode from DDC. Assume that the |
583 | * preferred mode is the right one. |
584 | */ |
585 | mutex_lock(&dev->mode_config.mutex); |
586 | psb_intel_ddc_get_modes(connector, adapter: &ddc_bus->base); |
587 | |
588 | list_for_each_entry(scan, &connector->probed_modes, head) { |
589 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { |
590 | mode_dev->panel_fixed_mode = |
591 | drm_mode_duplicate(dev, mode: scan); |
592 | goto out; /* FIXME: check for quirks */ |
593 | } |
594 | } |
595 | |
596 | /* Failed to get EDID, what about VBT? do we need this?*/ |
597 | if (dev_priv->lfp_lvds_vbt_mode) { |
598 | mode_dev->panel_fixed_mode = |
599 | drm_mode_duplicate(dev, mode: dev_priv->lfp_lvds_vbt_mode); |
600 | if (mode_dev->panel_fixed_mode) { |
601 | mode_dev->panel_fixed_mode->type |= |
602 | DRM_MODE_TYPE_PREFERRED; |
603 | goto out; /* FIXME: check for quirks */ |
604 | } |
605 | } |
606 | /* |
607 | * If we didn't get EDID, try checking if the panel is already turned |
608 | * on. If so, assume that whatever is currently programmed is the |
609 | * correct mode. |
610 | */ |
611 | lvds = REG_READ(LVDS); |
612 | pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; |
613 | crtc = psb_intel_get_crtc_from_pipe(dev, pipe); |
614 | |
615 | if (crtc && (lvds & LVDS_PORT_EN)) { |
616 | mode_dev->panel_fixed_mode = |
617 | cdv_intel_crtc_mode_get(dev, crtc); |
618 | if (mode_dev->panel_fixed_mode) { |
619 | mode_dev->panel_fixed_mode->type |= |
620 | DRM_MODE_TYPE_PREFERRED; |
621 | goto out; /* FIXME: check for quirks */ |
622 | } |
623 | } |
624 | |
625 | /* If we still don't have a mode after all that, give up. */ |
626 | if (!mode_dev->panel_fixed_mode) { |
627 | DRM_DEBUG |
628 | ("Found no modes on the lvds, ignoring the LVDS\n" ); |
629 | goto err_unlock; |
630 | } |
631 | |
632 | /* setup PWM */ |
633 | { |
634 | u32 pwm; |
635 | |
636 | pwm = REG_READ(BLC_PWM_CTL2); |
637 | if (pipe == 1) |
638 | pwm |= PWM_PIPE_B; |
639 | else |
640 | pwm &= ~PWM_PIPE_B; |
641 | pwm |= PWM_ENABLE; |
642 | REG_WRITE(BLC_PWM_CTL2, pwm); |
643 | } |
644 | |
645 | out: |
646 | mutex_unlock(lock: &dev->mode_config.mutex); |
647 | return; |
648 | |
649 | err_unlock: |
650 | mutex_unlock(lock: &dev->mode_config.mutex); |
651 | gma_i2c_destroy(chan: gma_encoder->i2c_bus); |
652 | err_encoder_cleanup: |
653 | drm_encoder_cleanup(encoder); |
654 | err_connector_cleanup: |
655 | drm_connector_cleanup(connector); |
656 | err_destroy_ddc: |
657 | gma_i2c_destroy(chan: ddc_bus); |
658 | err_free_lvds_priv: |
659 | kfree(objp: lvds_priv); |
660 | err_free_connector: |
661 | kfree(objp: gma_connector); |
662 | err_free_encoder: |
663 | kfree(objp: gma_encoder); |
664 | } |
665 | |