diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv04_dfp.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_dfp.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 3311f3a8c818..9871570d2ff4 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include "nouveau_hw.h" | 34 | #include "nouveau_hw.h" |
35 | #include "nvreg.h" | 35 | #include "nvreg.h" |
36 | 36 | ||
37 | #include "i2c/sil164.h" | ||
38 | |||
37 | #define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \ | 39 | #define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \ |
38 | NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \ | 40 | NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \ |
39 | NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS) | 41 | NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS) |
@@ -429,6 +431,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) | |||
429 | else | 431 | else |
430 | NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); | 432 | NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); |
431 | 433 | ||
434 | /* Init external transmitters */ | ||
435 | if (get_slave_funcs(encoder)) | ||
436 | get_slave_funcs(encoder)->mode_set(encoder, &nv_encoder->mode, | ||
437 | &nv_encoder->mode); | ||
438 | |||
432 | helper->dpms(encoder, DRM_MODE_DPMS_ON); | 439 | helper->dpms(encoder, DRM_MODE_DPMS_ON); |
433 | 440 | ||
434 | NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", | 441 | NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", |
@@ -550,10 +557,41 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder) | |||
550 | 557 | ||
551 | NV_DEBUG_KMS(encoder->dev, "\n"); | 558 | NV_DEBUG_KMS(encoder->dev, "\n"); |
552 | 559 | ||
560 | if (get_slave_funcs(encoder)) | ||
561 | get_slave_funcs(encoder)->destroy(encoder); | ||
562 | |||
553 | drm_encoder_cleanup(encoder); | 563 | drm_encoder_cleanup(encoder); |
554 | kfree(nv_encoder); | 564 | kfree(nv_encoder); |
555 | } | 565 | } |
556 | 566 | ||
567 | static void nv04_tmds_slave_init(struct drm_encoder *encoder) | ||
568 | { | ||
569 | struct drm_device *dev = encoder->dev; | ||
570 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; | ||
571 | struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2); | ||
572 | struct i2c_board_info info[] = { | ||
573 | { | ||
574 | .type = "sil164", | ||
575 | .addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38), | ||
576 | .platform_data = &(struct sil164_encoder_params) { | ||
577 | SIL164_INPUT_EDGE_RISING | ||
578 | } | ||
579 | }, | ||
580 | { } | ||
581 | }; | ||
582 | int type; | ||
583 | |||
584 | if (!nv_gf4_disp_arch(dev) || !i2c) | ||
585 | return; | ||
586 | |||
587 | type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2); | ||
588 | if (type < 0) | ||
589 | return; | ||
590 | |||
591 | drm_i2c_encoder_init(dev, to_encoder_slave(encoder), | ||
592 | &i2c->adapter, &info[type]); | ||
593 | } | ||
594 | |||
557 | static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { | 595 | static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { |
558 | .dpms = nv04_lvds_dpms, | 596 | .dpms = nv04_lvds_dpms, |
559 | .save = nv04_dfp_save, | 597 | .save = nv04_dfp_save, |
@@ -616,6 +654,10 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry) | |||
616 | encoder->possible_crtcs = entry->heads; | 654 | encoder->possible_crtcs = entry->heads; |
617 | encoder->possible_clones = 0; | 655 | encoder->possible_clones = 0; |
618 | 656 | ||
657 | if (entry->type == OUTPUT_TMDS && | ||
658 | entry->location != DCB_LOC_ON_CHIP) | ||
659 | nv04_tmds_slave_init(encoder); | ||
660 | |||
619 | drm_mode_connector_attach_encoder(connector, encoder); | 661 | drm_mode_connector_attach_encoder(connector, encoder); |
620 | return 0; | 662 | return 0; |
621 | } | 663 | } |