diff options
author | Francisco Jerez <currojerez@riseup.net> | 2010-07-25 13:13:43 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-08-05 18:35:11 -0400 |
commit | 2d14e35c950b00bddeba770278f2fe4dfd4355b2 (patch) | |
tree | 572d2d0c02629cb5ed0d8dacc42503f282bba4a6 /drivers/gpu/drm/nouveau/nv04_dfp.c | |
parent | bfe9dbcfc67e14eb679869afbc8ada2c4bcc4440 (diff) |
drm/nv30: Workaround dual TMDS brain damage.
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv04_dfp.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_dfp.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 9871570d2ff4..a5dcf7685800 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c | |||
@@ -146,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode) | |||
146 | } | 146 | } |
147 | } | 147 | } |
148 | 148 | ||
149 | static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder) | ||
150 | { | ||
151 | struct drm_device *dev = encoder->dev; | ||
152 | struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; | ||
153 | struct drm_encoder *slave; | ||
154 | |||
155 | if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP) | ||
156 | return NULL; | ||
157 | |||
158 | /* Some BIOSes (e.g. the one in a Quadro FX1000) report several | ||
159 | * TMDS transmitters at the same I2C address, in the same I2C | ||
160 | * bus. This can still work because in that case one of them is | ||
161 | * always hard-wired to a reasonable configuration using straps, | ||
162 | * and the other one needs to be programmed. | ||
163 | * | ||
164 | * I don't think there's a way to know which is which, even the | ||
165 | * blob programs the one exposed via I2C for *both* heads, so | ||
166 | * let's do the same. | ||
167 | */ | ||
168 | list_for_each_entry(slave, &dev->mode_config.encoder_list, head) { | ||
169 | struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb; | ||
170 | |||
171 | if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) && | ||
172 | slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr) | ||
173 | return slave; | ||
174 | } | ||
175 | |||
176 | return NULL; | ||
177 | } | ||
178 | |||
149 | static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, | 179 | static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, |
150 | struct drm_display_mode *mode, | 180 | struct drm_display_mode *mode, |
151 | struct drm_display_mode *adjusted_mode) | 181 | struct drm_display_mode *adjusted_mode) |
@@ -432,9 +462,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) | |||
432 | NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); | 462 | NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); |
433 | 463 | ||
434 | /* Init external transmitters */ | 464 | /* Init external transmitters */ |
435 | if (get_slave_funcs(encoder)) | 465 | if (get_tmds_slave(encoder)) |
436 | get_slave_funcs(encoder)->mode_set(encoder, &nv_encoder->mode, | 466 | get_slave_funcs(get_tmds_slave(encoder))->mode_set( |
437 | &nv_encoder->mode); | 467 | encoder, &nv_encoder->mode, &nv_encoder->mode); |
438 | 468 | ||
439 | helper->dpms(encoder, DRM_MODE_DPMS_ON); | 469 | helper->dpms(encoder, DRM_MODE_DPMS_ON); |
440 | 470 | ||
@@ -581,7 +611,8 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) | |||
581 | }; | 611 | }; |
582 | int type; | 612 | int type; |
583 | 613 | ||
584 | if (!nv_gf4_disp_arch(dev) || !i2c) | 614 | if (!nv_gf4_disp_arch(dev) || !i2c || |
615 | get_tmds_slave(encoder)) | ||
585 | return; | 616 | return; |
586 | 617 | ||
587 | type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2); | 618 | type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2); |