aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-07-20 10:48:08 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-08-05 18:34:59 -0400
commit4a9f822fe1a6ca5de7d8cdd5efbead3b9ab4283b (patch)
tree201e0191a1414ff04fe867e2bc6b2dfae8809fe3 /drivers/gpu
parentd2f4e89254b5816925a207a221e6b26100357eea (diff)
drm/nv17-nv4x: Attempt to init some external TMDS transmitters.
sil164 and friends are the most common, usually they just need to be poked once because a fixed configuration is enough for any modes and clocks, so they worked without this patch if the BIOS had done a good job on POST. Display couldn't survive a suspend/resume cycle though. Unfortunately, BIOS scripts are useless here. Signed-off-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c42
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c9
9 files changed, 93 insertions, 21 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index c608b0b29a36..e86f46cf8837 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -5982,7 +5982,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
5982 } 5982 }
5983 break; 5983 break;
5984 case OUTPUT_TMDS: 5984 case OUTPUT_TMDS:
5985 entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; 5985 if (dcb->version >= 0x22)
5986 entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
5987 else if (dcb->version >= 0x30)
5988 entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
5989 else if (dcb->version >= 0x40)
5990 entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
5991
5986 break; 5992 break;
5987 case 0xe: 5993 case 0xe:
5988 /* weird g80 mobile type that "nv" treats as a terminator */ 5994 /* weird g80 mobile type that "nv" treats as a terminator */
@@ -6272,6 +6278,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
6272 dcb->i2c_table = &bios->data[i2ctabptr]; 6278 dcb->i2c_table = &bios->data[i2ctabptr];
6273 if (dcb->version >= 0x30) 6279 if (dcb->version >= 0x30)
6274 dcb->i2c_default_indices = dcb->i2c_table[4]; 6280 dcb->i2c_default_indices = dcb->i2c_table[4];
6281
6282 /*
6283 * Parse the "management" I2C bus, used for hardware
6284 * monitoring and some external TMDS transmitters.
6285 */
6286 if (dcb->version >= 0x22) {
6287 int idx = (dcb->version >= 0x40 ?
6288 dcb->i2c_default_indices & 0xf :
6289 2);
6290
6291 read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
6292 idx, &dcb->i2c[idx]);
6293 }
6275 } 6294 }
6276 6295
6277 if (entries > DCB_MAX_NUM_ENTRIES) 6296 if (entries > DCB_MAX_NUM_ENTRIES)
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 024458a8d060..fd14dfd3d780 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -131,6 +131,7 @@ struct dcb_entry {
131 } dpconf; 131 } dpconf;
132 struct { 132 struct {
133 struct sor_conf sor; 133 struct sor_conf sor;
134 int slave_addr;
134 } tmdsconf; 135 } tmdsconf;
135 }; 136 };
136 bool i2c_upper_default; 137 bool i2c_upper_default;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 734e92635e83..b1b22baf1428 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -37,12 +37,6 @@
37#include "nouveau_connector.h" 37#include "nouveau_connector.h"
38#include "nouveau_hw.h" 38#include "nouveau_hw.h"
39 39
40static inline struct drm_encoder_slave_funcs *
41get_slave_funcs(struct nouveau_encoder *enc)
42{
43 return to_encoder_slave(to_drm_encoder(enc))->slave_funcs;
44}
45
46static struct nouveau_encoder * 40static struct nouveau_encoder *
47find_encoder_by_type(struct drm_connector *connector, int type) 41find_encoder_by_type(struct drm_connector *connector, int type)
48{ 42{
@@ -360,6 +354,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
360{ 354{
361 struct nouveau_connector *nv_connector = nouveau_connector(connector); 355 struct nouveau_connector *nv_connector = nouveau_connector(connector);
362 struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; 356 struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
357 struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
363 struct drm_device *dev = connector->dev; 358 struct drm_device *dev = connector->dev;
364 int ret; 359 int ret;
365 360
@@ -432,8 +427,8 @@ nouveau_connector_set_property(struct drm_connector *connector,
432 } 427 }
433 428
434 if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV) 429 if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
435 return get_slave_funcs(nv_encoder)-> 430 return get_slave_funcs(encoder)->set_property(
436 set_property(to_drm_encoder(nv_encoder), connector, property, value); 431 encoder, connector, property, value);
437 432
438 return -EINVAL; 433 return -EINVAL;
439} 434}
@@ -545,6 +540,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
545 struct drm_nouveau_private *dev_priv = dev->dev_private; 540 struct drm_nouveau_private *dev_priv = dev->dev_private;
546 struct nouveau_connector *nv_connector = nouveau_connector(connector); 541 struct nouveau_connector *nv_connector = nouveau_connector(connector);
547 struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; 542 struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
543 struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
548 int ret = 0; 544 int ret = 0;
549 545
550 /* destroy the native mode, the attached monitor could have changed. 546 /* destroy the native mode, the attached monitor could have changed.
@@ -580,8 +576,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
580 } 576 }
581 577
582 if (nv_encoder->dcb->type == OUTPUT_TV) 578 if (nv_encoder->dcb->type == OUTPUT_TV)
583 ret = get_slave_funcs(nv_encoder)-> 579 ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
584 get_modes(to_drm_encoder(nv_encoder), connector);
585 580
586 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || 581 if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
587 nv_connector->dcb->type == DCB_CONNECTOR_eDP) 582 nv_connector->dcb->type == DCB_CONNECTOR_eDP)
@@ -597,6 +592,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
597 struct drm_nouveau_private *dev_priv = connector->dev->dev_private; 592 struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
598 struct nouveau_connector *nv_connector = nouveau_connector(connector); 593 struct nouveau_connector *nv_connector = nouveau_connector(connector);
599 struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; 594 struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
595 struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
600 unsigned min_clock = 25000, max_clock = min_clock; 596 unsigned min_clock = 25000, max_clock = min_clock;
601 unsigned clock = mode->clock; 597 unsigned clock = mode->clock;
602 598
@@ -623,8 +619,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
623 max_clock = 350000; 619 max_clock = 350000;
624 break; 620 break;
625 case OUTPUT_TV: 621 case OUTPUT_TV:
626 return get_slave_funcs(nv_encoder)-> 622 return get_slave_funcs(encoder)->mode_valid(encoder, mode);
627 mode_valid(to_drm_encoder(nv_encoder), mode);
628 case OUTPUT_DP: 623 case OUTPUT_DP:
629 if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) 624 if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)
630 max_clock = nv_encoder->dp.link_nr * 270000; 625 max_clock = nv_encoder->dp.link_nr * 270000;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index db10809e9131..9e17d88bc890 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -410,7 +410,7 @@ enum nv04_fp_display_regs {
410 410
411struct nv04_crtc_reg { 411struct nv04_crtc_reg {
412 unsigned char MiscOutReg; /* */ 412 unsigned char MiscOutReg; /* */
413 uint8_t CRTC[0x9f]; 413 uint8_t CRTC[0xa0];
414 uint8_t CR58[0x10]; 414 uint8_t CR58[0x10];
415 uint8_t Sequencer[5]; 415 uint8_t Sequencer[5];
416 uint8_t Graphics[9]; 416 uint8_t Graphics[9];
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index a1a0d48ae70c..7c82d68bc155 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -71,6 +71,12 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
71 return &enc->base.base; 71 return &enc->base.base;
72} 72}
73 73
74static inline struct drm_encoder_slave_funcs *
75get_slave_funcs(struct drm_encoder *enc)
76{
77 return to_encoder_slave(enc)->slave_funcs;
78}
79
74struct nouveau_connector * 80struct nouveau_connector *
75nouveau_encoder_connector_get(struct nouveau_encoder *encoder); 81nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
76int nv50_sor_create(struct drm_connector *, struct dcb_entry *); 82int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c
index 7855b35effc3..7b613682e400 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.c
@@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head,
865 rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); 865 rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
866 rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); 866 rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
867 rd_cio_state(dev, head, regp, NV_CIO_CRE_21); 867 rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
868 if (dev_priv->card_type >= NV_30) 868
869 if (dev_priv->card_type >= NV_30) {
869 rd_cio_state(dev, head, regp, NV_CIO_CRE_47); 870 rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
871 rd_cio_state(dev, head, regp, 0x9f);
872 }
873
870 rd_cio_state(dev, head, regp, NV_CIO_CRE_49); 874 rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
871 rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); 875 rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
872 rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); 876 rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX);
@@ -971,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head,
971 wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX); 975 wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX);
972 wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); 976 wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
973 wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); 977 wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
974 if (dev_priv->card_type >= NV_30) 978
979 if (dev_priv->card_type >= NV_30) {
975 wr_cio_state(dev, head, regp, NV_CIO_CRE_47); 980 wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
981 wr_cio_state(dev, head, regp, 0x9f);
982 }
976 983
977 wr_cio_state(dev, head, regp, NV_CIO_CRE_49); 984 wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
978 wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); 985 wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 1c20c08ce67c..08c7e073edce 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -542,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
542 * 1 << 30 on 0x60.830), for no apparent reason */ 542 * 1 << 30 on 0x60.830), for no apparent reason */
543 regp->CRTC[NV_CIO_CRE_59] = off_chip_digital; 543 regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
544 544
545 if (dev_priv->card_type >= NV_30)
546 regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1;
547
545 regp->crtc_830 = mode->crtc_vdisplay - 3; 548 regp->crtc_830 = mode->crtc_vdisplay - 3;
546 regp->crtc_834 = mode->crtc_vdisplay - 1; 549 regp->crtc_834 = mode->crtc_vdisplay - 1;
547 550
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
567static 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
557static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { 595static 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}
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index 94e299cef0b2..4e73c4461a22 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -89,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
89 89
90 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); 90 NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);
91 91
92 to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode); 92 get_slave_funcs(encoder)->dpms(encoder, mode);
93} 93}
94 94
95static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) 95static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
@@ -152,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder,
152 regp->tv_vskew = 1; 152 regp->tv_vskew = 1;
153 regp->tv_vsync_delay = 1; 153 regp->tv_vsync_delay = 1;
154 154
155 to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode); 155 get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
156} 156}
157 157
158static void nv04_tv_commit(struct drm_encoder *encoder) 158static void nv04_tv_commit(struct drm_encoder *encoder)
@@ -171,8 +171,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
171 171
172static void nv04_tv_destroy(struct drm_encoder *encoder) 172static void nv04_tv_destroy(struct drm_encoder *encoder)
173{ 173{
174 to_encoder_slave(encoder)->slave_funcs->destroy(encoder); 174 get_slave_funcs(encoder)->destroy(encoder);
175
176 drm_encoder_cleanup(encoder); 175 drm_encoder_cleanup(encoder);
177 176
178 kfree(encoder->helper_private); 177 kfree(encoder->helper_private);
@@ -229,7 +228,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
229 goto fail_cleanup; 228 goto fail_cleanup;
230 229
231 /* Fill the function pointers */ 230 /* Fill the function pointers */
232 sfuncs = to_encoder_slave(encoder)->slave_funcs; 231 sfuncs = get_slave_funcs(encoder);
233 232
234 *hfuncs = (struct drm_encoder_helper_funcs) { 233 *hfuncs = (struct drm_encoder_helper_funcs) {
235 .dpms = nv04_tv_dpms, 234 .dpms = nv04_tv_dpms,