diff options
author | Dave Airlie <airlied@redhat.com> | 2015-03-22 19:34:08 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-03-22 19:34:08 -0400 |
commit | e8b6fe6990643daac9bccbe957a253a7e6bf947d (patch) | |
tree | 8a83f2b138db3d9c59aa04c7a9362afc9abd2106 | |
parent | b3ede177c8ba8c001c65aec1511445363642ecd0 (diff) | |
parent | c6169e49bd37c9556efd7564bcbbf7067cd7efa8 (diff) |
Merge branch 'drm/next/adv7511' of git://linuxtv.org/pinchartl/fbdev into drm-next
adv7511 fixes.
* 'drm/next/adv7511' of git://linuxtv.org/pinchartl/fbdev:
drm: adv7511: Refactor power management
drm: adv7511: Fix nested sleep when reading EDID
drm: adv7511: Fix DDC error interrupt handling
-rw-r--r-- | drivers/gpu/drm/i2c/adv7511.c | 197 |
1 files changed, 102 insertions, 95 deletions
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index 61aa824d45d2..b728523e194f 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c | |||
@@ -27,12 +27,13 @@ struct adv7511 { | |||
27 | struct regmap *regmap; | 27 | struct regmap *regmap; |
28 | struct regmap *packet_memory_regmap; | 28 | struct regmap *packet_memory_regmap; |
29 | enum drm_connector_status status; | 29 | enum drm_connector_status status; |
30 | int dpms_mode; | 30 | bool powered; |
31 | 31 | ||
32 | unsigned int f_tmds; | 32 | unsigned int f_tmds; |
33 | 33 | ||
34 | unsigned int current_edid_segment; | 34 | unsigned int current_edid_segment; |
35 | uint8_t edid_buf[256]; | 35 | uint8_t edid_buf[256]; |
36 | bool edid_read; | ||
36 | 37 | ||
37 | wait_queue_head_t wq; | 38 | wait_queue_head_t wq; |
38 | struct drm_encoder *encoder; | 39 | struct drm_encoder *encoder; |
@@ -357,6 +358,48 @@ static void adv7511_set_link_config(struct adv7511 *adv7511, | |||
357 | adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; | 358 | adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; |
358 | } | 359 | } |
359 | 360 | ||
361 | static void adv7511_power_on(struct adv7511 *adv7511) | ||
362 | { | ||
363 | adv7511->current_edid_segment = -1; | ||
364 | |||
365 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), | ||
366 | ADV7511_INT0_EDID_READY); | ||
367 | regmap_write(adv7511->regmap, ADV7511_REG_INT(1), | ||
368 | ADV7511_INT1_DDC_ERROR); | ||
369 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | ||
370 | ADV7511_POWER_POWER_DOWN, 0); | ||
371 | |||
372 | /* | ||
373 | * Per spec it is allowed to pulse the HDP signal to indicate that the | ||
374 | * EDID information has changed. Some monitors do this when they wakeup | ||
375 | * from standby or are enabled. When the HDP goes low the adv7511 is | ||
376 | * reset and the outputs are disabled which might cause the monitor to | ||
377 | * go to standby again. To avoid this we ignore the HDP pin for the | ||
378 | * first few seconds after enabling the output. | ||
379 | */ | ||
380 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||
381 | ADV7511_REG_POWER2_HDP_SRC_MASK, | ||
382 | ADV7511_REG_POWER2_HDP_SRC_NONE); | ||
383 | |||
384 | /* | ||
385 | * Most of the registers are reset during power down or when HPD is low. | ||
386 | */ | ||
387 | regcache_sync(adv7511->regmap); | ||
388 | |||
389 | adv7511->powered = true; | ||
390 | } | ||
391 | |||
392 | static void adv7511_power_off(struct adv7511 *adv7511) | ||
393 | { | ||
394 | /* TODO: setup additional power down modes */ | ||
395 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | ||
396 | ADV7511_POWER_POWER_DOWN, | ||
397 | ADV7511_POWER_POWER_DOWN); | ||
398 | regcache_mark_dirty(adv7511->regmap); | ||
399 | |||
400 | adv7511->powered = false; | ||
401 | } | ||
402 | |||
360 | /* ----------------------------------------------------------------------------- | 403 | /* ----------------------------------------------------------------------------- |
361 | * Interrupt and hotplug detection | 404 | * Interrupt and hotplug detection |
362 | */ | 405 | */ |
@@ -379,69 +422,71 @@ static bool adv7511_hpd(struct adv7511 *adv7511) | |||
379 | return false; | 422 | return false; |
380 | } | 423 | } |
381 | 424 | ||
382 | static irqreturn_t adv7511_irq_handler(int irq, void *devid) | 425 | static int adv7511_irq_process(struct adv7511 *adv7511) |
383 | { | ||
384 | struct adv7511 *adv7511 = devid; | ||
385 | |||
386 | if (adv7511_hpd(adv7511)) | ||
387 | drm_helper_hpd_irq_event(adv7511->encoder->dev); | ||
388 | |||
389 | wake_up_all(&adv7511->wq); | ||
390 | |||
391 | return IRQ_HANDLED; | ||
392 | } | ||
393 | |||
394 | static unsigned int adv7511_is_interrupt_pending(struct adv7511 *adv7511, | ||
395 | unsigned int irq) | ||
396 | { | 426 | { |
397 | unsigned int irq0, irq1; | 427 | unsigned int irq0, irq1; |
398 | unsigned int pending; | ||
399 | int ret; | 428 | int ret; |
400 | 429 | ||
401 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); | 430 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); |
402 | if (ret < 0) | 431 | if (ret < 0) |
403 | return 0; | 432 | return ret; |
433 | |||
404 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); | 434 | ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); |
405 | if (ret < 0) | 435 | if (ret < 0) |
406 | return 0; | 436 | return ret; |
407 | 437 | ||
408 | pending = (irq1 << 8) | irq0; | 438 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0); |
439 | regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1); | ||
409 | 440 | ||
410 | return pending & irq; | 441 | if (irq0 & ADV7511_INT0_HDP) |
442 | drm_helper_hpd_irq_event(adv7511->encoder->dev); | ||
443 | |||
444 | if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) { | ||
445 | adv7511->edid_read = true; | ||
446 | |||
447 | if (adv7511->i2c_main->irq) | ||
448 | wake_up_all(&adv7511->wq); | ||
449 | } | ||
450 | |||
451 | return 0; | ||
411 | } | 452 | } |
412 | 453 | ||
413 | static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq, | 454 | static irqreturn_t adv7511_irq_handler(int irq, void *devid) |
414 | int timeout) | 455 | { |
456 | struct adv7511 *adv7511 = devid; | ||
457 | int ret; | ||
458 | |||
459 | ret = adv7511_irq_process(adv7511); | ||
460 | return ret < 0 ? IRQ_NONE : IRQ_HANDLED; | ||
461 | } | ||
462 | |||
463 | /* ----------------------------------------------------------------------------- | ||
464 | * EDID retrieval | ||
465 | */ | ||
466 | |||
467 | static int adv7511_wait_for_edid(struct adv7511 *adv7511, int timeout) | ||
415 | { | 468 | { |
416 | unsigned int pending; | ||
417 | int ret; | 469 | int ret; |
418 | 470 | ||
419 | if (adv7511->i2c_main->irq) { | 471 | if (adv7511->i2c_main->irq) { |
420 | ret = wait_event_interruptible_timeout(adv7511->wq, | 472 | ret = wait_event_interruptible_timeout(adv7511->wq, |
421 | adv7511_is_interrupt_pending(adv7511, irq), | 473 | adv7511->edid_read, msecs_to_jiffies(timeout)); |
422 | msecs_to_jiffies(timeout)); | ||
423 | if (ret <= 0) | ||
424 | return 0; | ||
425 | pending = adv7511_is_interrupt_pending(adv7511, irq); | ||
426 | } else { | 474 | } else { |
427 | if (timeout < 25) | 475 | for (; timeout > 0; timeout -= 25) { |
428 | timeout = 25; | 476 | ret = adv7511_irq_process(adv7511); |
429 | do { | 477 | if (ret < 0) |
430 | pending = adv7511_is_interrupt_pending(adv7511, irq); | ||
431 | if (pending) | ||
432 | break; | 478 | break; |
479 | |||
480 | if (adv7511->edid_read) | ||
481 | break; | ||
482 | |||
433 | msleep(25); | 483 | msleep(25); |
434 | timeout -= 25; | 484 | } |
435 | } while (timeout >= 25); | ||
436 | } | 485 | } |
437 | 486 | ||
438 | return pending; | 487 | return adv7511->edid_read ? 0 : -EIO; |
439 | } | 488 | } |
440 | 489 | ||
441 | /* ----------------------------------------------------------------------------- | ||
442 | * EDID retrieval | ||
443 | */ | ||
444 | |||
445 | static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, | 490 | static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, |
446 | size_t len) | 491 | size_t len) |
447 | { | 492 | { |
@@ -463,19 +508,14 @@ static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, | |||
463 | return ret; | 508 | return ret; |
464 | 509 | ||
465 | if (status != 2) { | 510 | if (status != 2) { |
511 | adv7511->edid_read = false; | ||
466 | regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, | 512 | regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, |
467 | block); | 513 | block); |
468 | ret = adv7511_wait_for_interrupt(adv7511, | 514 | ret = adv7511_wait_for_edid(adv7511, 200); |
469 | ADV7511_INT0_EDID_READY | | 515 | if (ret < 0) |
470 | ADV7511_INT1_DDC_ERROR, 200); | 516 | return ret; |
471 | |||
472 | if (!(ret & ADV7511_INT0_EDID_READY)) | ||
473 | return -EIO; | ||
474 | } | 517 | } |
475 | 518 | ||
476 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), | ||
477 | ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); | ||
478 | |||
479 | /* Break this apart, hopefully more I2C controllers will | 519 | /* Break this apart, hopefully more I2C controllers will |
480 | * support 64 byte transfers than 256 byte transfers | 520 | * support 64 byte transfers than 256 byte transfers |
481 | */ | 521 | */ |
@@ -526,9 +566,11 @@ static int adv7511_get_modes(struct drm_encoder *encoder, | |||
526 | unsigned int count; | 566 | unsigned int count; |
527 | 567 | ||
528 | /* Reading the EDID only works if the device is powered */ | 568 | /* Reading the EDID only works if the device is powered */ |
529 | if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) { | 569 | if (!adv7511->powered) { |
530 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), | 570 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), |
531 | ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); | 571 | ADV7511_INT0_EDID_READY); |
572 | regmap_write(adv7511->regmap, ADV7511_REG_INT(1), | ||
573 | ADV7511_INT1_DDC_ERROR); | ||
532 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | 574 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, |
533 | ADV7511_POWER_POWER_DOWN, 0); | 575 | ADV7511_POWER_POWER_DOWN, 0); |
534 | adv7511->current_edid_segment = -1; | 576 | adv7511->current_edid_segment = -1; |
@@ -536,7 +578,7 @@ static int adv7511_get_modes(struct drm_encoder *encoder, | |||
536 | 578 | ||
537 | edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); | 579 | edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); |
538 | 580 | ||
539 | if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) | 581 | if (!adv7511->powered) |
540 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | 582 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, |
541 | ADV7511_POWER_POWER_DOWN, | 583 | ADV7511_POWER_POWER_DOWN, |
542 | ADV7511_POWER_POWER_DOWN); | 584 | ADV7511_POWER_POWER_DOWN); |
@@ -558,41 +600,10 @@ static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode) | |||
558 | { | 600 | { |
559 | struct adv7511 *adv7511 = encoder_to_adv7511(encoder); | 601 | struct adv7511 *adv7511 = encoder_to_adv7511(encoder); |
560 | 602 | ||
561 | switch (mode) { | 603 | if (mode == DRM_MODE_DPMS_ON) |
562 | case DRM_MODE_DPMS_ON: | 604 | adv7511_power_on(adv7511); |
563 | adv7511->current_edid_segment = -1; | 605 | else |
564 | 606 | adv7511_power_off(adv7511); | |
565 | regmap_write(adv7511->regmap, ADV7511_REG_INT(0), | ||
566 | ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); | ||
567 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | ||
568 | ADV7511_POWER_POWER_DOWN, 0); | ||
569 | /* | ||
570 | * Per spec it is allowed to pulse the HDP signal to indicate | ||
571 | * that the EDID information has changed. Some monitors do this | ||
572 | * when they wakeup from standby or are enabled. When the HDP | ||
573 | * goes low the adv7511 is reset and the outputs are disabled | ||
574 | * which might cause the monitor to go to standby again. To | ||
575 | * avoid this we ignore the HDP pin for the first few seconds | ||
576 | * after enabling the output. | ||
577 | */ | ||
578 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||
579 | ADV7511_REG_POWER2_HDP_SRC_MASK, | ||
580 | ADV7511_REG_POWER2_HDP_SRC_NONE); | ||
581 | /* Most of the registers are reset during power down or | ||
582 | * when HPD is low | ||
583 | */ | ||
584 | regcache_sync(adv7511->regmap); | ||
585 | break; | ||
586 | default: | ||
587 | /* TODO: setup additional power down modes */ | ||
588 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | ||
589 | ADV7511_POWER_POWER_DOWN, | ||
590 | ADV7511_POWER_POWER_DOWN); | ||
591 | regcache_mark_dirty(adv7511->regmap); | ||
592 | break; | ||
593 | } | ||
594 | |||
595 | adv7511->dpms_mode = mode; | ||
596 | } | 607 | } |
597 | 608 | ||
598 | static enum drm_connector_status | 609 | static enum drm_connector_status |
@@ -620,10 +631,9 @@ adv7511_encoder_detect(struct drm_encoder *encoder, | |||
620 | * there is a pending HPD interrupt and the cable is connected there was | 631 | * there is a pending HPD interrupt and the cable is connected there was |
621 | * at least one transition from disconnected to connected and the chip | 632 | * at least one transition from disconnected to connected and the chip |
622 | * has to be reinitialized. */ | 633 | * has to be reinitialized. */ |
623 | if (status == connector_status_connected && hpd && | 634 | if (status == connector_status_connected && hpd && adv7511->powered) { |
624 | adv7511->dpms_mode == DRM_MODE_DPMS_ON) { | ||
625 | regcache_mark_dirty(adv7511->regmap); | 635 | regcache_mark_dirty(adv7511->regmap); |
626 | adv7511_encoder_dpms(encoder, adv7511->dpms_mode); | 636 | adv7511_power_on(adv7511); |
627 | adv7511_get_modes(encoder, connector); | 637 | adv7511_get_modes(encoder, connector); |
628 | if (adv7511->status == connector_status_connected) | 638 | if (adv7511->status == connector_status_connected) |
629 | status = connector_status_disconnected; | 639 | status = connector_status_disconnected; |
@@ -858,7 +868,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
858 | if (!adv7511) | 868 | if (!adv7511) |
859 | return -ENOMEM; | 869 | return -ENOMEM; |
860 | 870 | ||
861 | adv7511->dpms_mode = DRM_MODE_DPMS_OFF; | 871 | adv7511->powered = false; |
862 | adv7511->status = connector_status_disconnected; | 872 | adv7511->status = connector_status_disconnected; |
863 | 873 | ||
864 | ret = adv7511_parse_dt(dev->of_node, &link_config); | 874 | ret = adv7511_parse_dt(dev->of_node, &link_config); |
@@ -918,10 +928,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
918 | regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, | 928 | regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, |
919 | ADV7511_CEC_CTRL_POWER_DOWN); | 929 | ADV7511_CEC_CTRL_POWER_DOWN); |
920 | 930 | ||
921 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | 931 | adv7511_power_off(adv7511); |
922 | ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); | ||
923 | |||
924 | adv7511->current_edid_segment = -1; | ||
925 | 932 | ||
926 | i2c_set_clientdata(i2c, adv7511); | 933 | i2c_set_clientdata(i2c, adv7511); |
927 | 934 | ||