SDVO: Fix DDC bus selection based on output priority list.

This commit is contained in:
Hong Liu 2008-04-02 16:05:43 -07:00 committed by Eric Anholt
parent 6ad2d6ba86
commit 13563bd65c
2 changed files with 66 additions and 7 deletions

View File

@ -92,6 +92,9 @@ struct i830_sdvo_priv {
*/
struct i830_sdvo_tv_format tv_format;
/** DDC bus used by this SDVO output */
uint8_t ddc_bus;
/** State for save/restore */
/** @{ */
int save_sdvo_mult;
@ -1011,8 +1014,9 @@ i830_sdvo_ddc_i2c_start(I2CBusPtr b, int timeout)
xf86OutputPtr output = b->DriverPrivate.ptr;
I830OutputPrivatePtr intel_output = output->driver_private;
I2CBusPtr i2cbus = intel_output->pI2CBus;
struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
i830_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2);
i830_sdvo_set_control_bus_switch(output, dev_priv->ddc_bus);
return i2cbus->I2CStart(i2cbus, timeout);
}
@ -1342,6 +1346,60 @@ static const xf86OutputFuncsRec i830_sdvo_output_funcs = {
#endif
};
static unsigned int count_bits(uint32_t mask)
{
unsigned int n;
for (n = 0; mask; n++)
mask &= mask - 1;
return n;
}
/**
* Choose the appropriate DDC bus for control bus switch command for this
* SDVO output based on the controlled output.
*
* DDC bus number assignment is in a priority order of RGB outputs, then TMDS
* outputs, then LVDS outputs.
*/
static void
i830_sdvo_select_ddc_bus(struct i830_sdvo_priv *dev_priv)
{
uint16_t mask = 0;
unsigned int num_bits;
/* Make a mask of outputs less than or equal to our own priority in the
* list.
*/
switch (dev_priv->controlled_output) {
case SDVO_OUTPUT_LVDS1:
mask |= SDVO_OUTPUT_LVDS1;
case SDVO_OUTPUT_LVDS0:
mask |= SDVO_OUTPUT_LVDS0;
case SDVO_OUTPUT_TMDS1:
mask |= SDVO_OUTPUT_TMDS1;
case SDVO_OUTPUT_TMDS0:
mask |= SDVO_OUTPUT_TMDS0;
case SDVO_OUTPUT_RGB1:
mask |= SDVO_OUTPUT_RGB1;
case SDVO_OUTPUT_RGB0:
mask |= SDVO_OUTPUT_RGB0;
break;
}
/* Count bits to find what number we are in the priority list. */
mask &= dev_priv->caps.output_flags;
num_bits = count_bits(mask);
if (num_bits > 3) {
/* if more than 3 outputs, default to DDC bus 3 for now */
num_bits = 3;
}
/* Corresponds to SDVO_CONTROL_BUS_DDCx */
dev_priv->ddc_bus = 1 << num_bits;
}
void
i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
{
@ -1510,8 +1568,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
xf86OutputDestroy (output);
return;
}
i830_sdvo_select_ddc_bus(dev_priv);
/* Set the input timing to the screen. Assume always input 0. */
i830_sdvo_set_target_input(output, TRUE, FALSE);

View File

@ -506,8 +506,8 @@ struct i830_sdvo_enhancements_arg {
#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93
#define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a
# define SDVO_CONTROL_BUS_PROM 0x0
# define SDVO_CONTROL_BUS_DDC1 0x1
# define SDVO_CONTROL_BUS_DDC2 0x2
# define SDVO_CONTROL_BUS_DDC3 0x3
# define SDVO_CONTROL_BUS_PROM (1 << 0)
# define SDVO_CONTROL_BUS_DDC1 (1 << 1)
# define SDVO_CONTROL_BUS_DDC2 (1 << 2)
# define SDVO_CONTROL_BUS_DDC3 (1 << 3)