Commit 4a9f822f authored by Francisco Jerez's avatar Francisco Jerez Committed by Ben Skeggs

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: default avatarFrancisco Jerez <currojerez@riseup.net>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent d2f4e892
...@@ -5982,7 +5982,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, ...@@ -5982,7 +5982,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
} }
break; break;
case OUTPUT_TMDS: case OUTPUT_TMDS:
entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; if (dcb->version >= 0x22)
entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
else if (dcb->version >= 0x30)
entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
else if (dcb->version >= 0x40)
entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
break; break;
case 0xe: case 0xe:
/* weird g80 mobile type that "nv" treats as a terminator */ /* 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,6 +6278,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
dcb->i2c_table = &bios->data[i2ctabptr]; dcb->i2c_table = &bios->data[i2ctabptr];
if (dcb->version >= 0x30) if (dcb->version >= 0x30)
dcb->i2c_default_indices = dcb->i2c_table[4]; dcb->i2c_default_indices = dcb->i2c_table[4];
/*
* Parse the "management" I2C bus, used for hardware
* monitoring and some external TMDS transmitters.
*/
if (dcb->version >= 0x22) {
int idx = (dcb->version >= 0x40 ?
dcb->i2c_default_indices & 0xf :
2);
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
idx, &dcb->i2c[idx]);
}
} }
if (entries > DCB_MAX_NUM_ENTRIES) if (entries > DCB_MAX_NUM_ENTRIES)
......
...@@ -131,6 +131,7 @@ struct dcb_entry { ...@@ -131,6 +131,7 @@ struct dcb_entry {
} dpconf; } dpconf;
struct { struct {
struct sor_conf sor; struct sor_conf sor;
int slave_addr;
} tmdsconf; } tmdsconf;
}; };
bool i2c_upper_default; bool i2c_upper_default;
......
...@@ -37,12 +37,6 @@ ...@@ -37,12 +37,6 @@
#include "nouveau_connector.h" #include "nouveau_connector.h"
#include "nouveau_hw.h" #include "nouveau_hw.h"
static inline struct drm_encoder_slave_funcs *
get_slave_funcs(struct nouveau_encoder *enc)
{
return to_encoder_slave(to_drm_encoder(enc))->slave_funcs;
}
static struct nouveau_encoder * static struct nouveau_encoder *
find_encoder_by_type(struct drm_connector *connector, int type) find_encoder_by_type(struct drm_connector *connector, int type)
{ {
...@@ -360,6 +354,7 @@ nouveau_connector_set_property(struct drm_connector *connector, ...@@ -360,6 +354,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
{ {
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
int ret; int ret;
...@@ -432,8 +427,8 @@ nouveau_connector_set_property(struct drm_connector *connector, ...@@ -432,8 +427,8 @@ nouveau_connector_set_property(struct drm_connector *connector,
} }
if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV) if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
return get_slave_funcs(nv_encoder)-> return get_slave_funcs(encoder)->set_property(
set_property(to_drm_encoder(nv_encoder), connector, property, value); encoder, connector, property, value);
return -EINVAL; return -EINVAL;
} }
...@@ -545,6 +540,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) ...@@ -545,6 +540,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
int ret = 0; int ret = 0;
/* destroy the native mode, the attached monitor could have changed. /* destroy the native mode, the attached monitor could have changed.
...@@ -580,8 +576,7 @@ nouveau_connector_get_modes(struct drm_connector *connector) ...@@ -580,8 +576,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
} }
if (nv_encoder->dcb->type == OUTPUT_TV) if (nv_encoder->dcb->type == OUTPUT_TV)
ret = get_slave_funcs(nv_encoder)-> ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
get_modes(to_drm_encoder(nv_encoder), connector);
if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
nv_connector->dcb->type == DCB_CONNECTOR_eDP) nv_connector->dcb->type == DCB_CONNECTOR_eDP)
...@@ -597,6 +592,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, ...@@ -597,6 +592,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
struct drm_nouveau_private *dev_priv = connector->dev->dev_private; struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
unsigned min_clock = 25000, max_clock = min_clock; unsigned min_clock = 25000, max_clock = min_clock;
unsigned clock = mode->clock; unsigned clock = mode->clock;
...@@ -623,8 +619,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, ...@@ -623,8 +619,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
max_clock = 350000; max_clock = 350000;
break; break;
case OUTPUT_TV: case OUTPUT_TV:
return get_slave_funcs(nv_encoder)-> return get_slave_funcs(encoder)->mode_valid(encoder, mode);
mode_valid(to_drm_encoder(nv_encoder), mode);
case OUTPUT_DP: case OUTPUT_DP:
if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)
max_clock = nv_encoder->dp.link_nr * 270000; max_clock = nv_encoder->dp.link_nr * 270000;
......
...@@ -410,7 +410,7 @@ enum nv04_fp_display_regs { ...@@ -410,7 +410,7 @@ enum nv04_fp_display_regs {
struct nv04_crtc_reg { struct nv04_crtc_reg {
unsigned char MiscOutReg; /* */ unsigned char MiscOutReg; /* */
uint8_t CRTC[0x9f]; uint8_t CRTC[0xa0];
uint8_t CR58[0x10]; uint8_t CR58[0x10];
uint8_t Sequencer[5]; uint8_t Sequencer[5];
uint8_t Graphics[9]; uint8_t Graphics[9];
......
...@@ -71,6 +71,12 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) ...@@ -71,6 +71,12 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
return &enc->base.base; return &enc->base.base;
} }
static inline struct drm_encoder_slave_funcs *
get_slave_funcs(struct drm_encoder *enc)
{
return to_encoder_slave(enc)->slave_funcs;
}
struct nouveau_connector * struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder *encoder); nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
int nv50_sor_create(struct drm_connector *, struct dcb_entry *); int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
......
...@@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head, ...@@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head,
rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_21); rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
if (dev_priv->card_type >= NV_30)
if (dev_priv->card_type >= NV_30) {
rd_cio_state(dev, head, regp, NV_CIO_CRE_47); rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
rd_cio_state(dev, head, regp, 0x9f);
}
rd_cio_state(dev, head, regp, NV_CIO_CRE_49); rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); 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,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head,
wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX);
wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
if (dev_priv->card_type >= NV_30)
if (dev_priv->card_type >= NV_30) {
wr_cio_state(dev, head, regp, NV_CIO_CRE_47); wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
wr_cio_state(dev, head, regp, 0x9f);
}
wr_cio_state(dev, head, regp, NV_CIO_CRE_49); wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
......
...@@ -542,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) ...@@ -542,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
* 1 << 30 on 0x60.830), for no apparent reason */ * 1 << 30 on 0x60.830), for no apparent reason */
regp->CRTC[NV_CIO_CRE_59] = off_chip_digital; regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
if (dev_priv->card_type >= NV_30)
regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1;
regp->crtc_830 = mode->crtc_vdisplay - 3; regp->crtc_830 = mode->crtc_vdisplay - 3;
regp->crtc_834 = mode->crtc_vdisplay - 1; regp->crtc_834 = mode->crtc_vdisplay - 1;
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include "nouveau_hw.h" #include "nouveau_hw.h"
#include "nvreg.h" #include "nvreg.h"
#include "i2c/sil164.h"
#define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \ #define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \
NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \ NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \
NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS) NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS)
...@@ -429,6 +431,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) ...@@ -429,6 +431,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
else else
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
/* Init external transmitters */
if (get_slave_funcs(encoder))
get_slave_funcs(encoder)->mode_set(encoder, &nv_encoder->mode,
&nv_encoder->mode);
helper->dpms(encoder, DRM_MODE_DPMS_ON); helper->dpms(encoder, DRM_MODE_DPMS_ON);
NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", 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,10 +557,41 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder)
NV_DEBUG_KMS(encoder->dev, "\n"); NV_DEBUG_KMS(encoder->dev, "\n");
if (get_slave_funcs(encoder))
get_slave_funcs(encoder)->destroy(encoder);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(nv_encoder); kfree(nv_encoder);
} }
static void nv04_tmds_slave_init(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2);
struct i2c_board_info info[] = {
{
.type = "sil164",
.addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
.platform_data = &(struct sil164_encoder_params) {
SIL164_INPUT_EDGE_RISING
}
},
{ }
};
int type;
if (!nv_gf4_disp_arch(dev) || !i2c)
return;
type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
if (type < 0)
return;
drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
&i2c->adapter, &info[type]);
}
static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
.dpms = nv04_lvds_dpms, .dpms = nv04_lvds_dpms,
.save = nv04_dfp_save, .save = nv04_dfp_save,
...@@ -616,6 +654,10 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry) ...@@ -616,6 +654,10 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
encoder->possible_crtcs = entry->heads; encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0; encoder->possible_clones = 0;
if (entry->type == OUTPUT_TMDS &&
entry->location != DCB_LOC_ON_CHIP)
nv04_tmds_slave_init(encoder);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
return 0; return 0;
} }
...@@ -89,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode) ...@@ -89,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);
to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode); get_slave_funcs(encoder)->dpms(encoder, mode);
} }
static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) static 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,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder,
regp->tv_vskew = 1; regp->tv_vskew = 1;
regp->tv_vsync_delay = 1; regp->tv_vsync_delay = 1;
to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode); get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
} }
static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_commit(struct drm_encoder *encoder)
...@@ -171,8 +171,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder) ...@@ -171,8 +171,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
static void nv04_tv_destroy(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder)
{ {
to_encoder_slave(encoder)->slave_funcs->destroy(encoder); get_slave_funcs(encoder)->destroy(encoder);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(encoder->helper_private); kfree(encoder->helper_private);
...@@ -229,7 +228,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) ...@@ -229,7 +228,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
goto fail_cleanup; goto fail_cleanup;
/* Fill the function pointers */ /* Fill the function pointers */
sfuncs = to_encoder_slave(encoder)->slave_funcs; sfuncs = get_slave_funcs(encoder);
*hfuncs = (struct drm_encoder_helper_funcs) { *hfuncs = (struct drm_encoder_helper_funcs) {
.dpms = nv04_tv_dpms, .dpms = nv04_tv_dpms,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment