summaryrefslogtreecommitdiff
path: root/src/i830_sdvo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i830_sdvo.c')
-rw-r--r--src/i830_sdvo.c169
1 files changed, 87 insertions, 82 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index bbc1c725..d3f509e5 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -54,21 +54,27 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
struct i830_sdvo_priv {
/** SDVO device on SDVO I2C bus. */
I2CDevRec d;
+
/** Register for the SDVO device: SDVOB or SDVOC */
int output_device;
+
+ /** Active outputs controlled by this SDVO output */
+ struct i830_sdvo_output_flags active_outputs;
+
/**
* Capabilities of the SDVO device returned by i830_sdvo_get_capabilities()
*/
- i830_sdvo_caps caps;
+ struct i830_sdvo_caps caps;
+
/** Pixel clock limitations reported by the SDVO device */
CARD16 pixel_clock_min, pixel_clock_max;
/** State for save/restore */
/** @{ */
int save_sdvo_mult;
- Bool save_sdvo_active_1, save_sdvo_active_2;
+ struct i830_sdvo_output_flags save_active_outputs;
struct i830_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
- struct i830_sdvo_dtd save_output_dtd_1, save_output_dtd_2;
+ struct i830_sdvo_dtd save_output_dtd;
CARD32 save_SDVOX;
/** @} */
};
@@ -122,7 +128,7 @@ const struct _sdvo_cmd_name {
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG),
- SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTR_EVENT_SOURCE),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1),
@@ -187,7 +193,7 @@ static const char *cmd_status_names[] = {
"Not supported",
"Invalid arg",
"Pending",
- "Target not supported",
+ "Target not specified",
"Scaling not supported"
};
@@ -249,14 +255,19 @@ i830_sdvo_set_control_bus_switch(I830OutputPtr output, CARD8 target)
}
static Bool
-i830_sdvo_set_target_input(I830OutputPtr output, Bool target_1, Bool target_2)
+i830_sdvo_set_target_input(I830OutputPtr output, Bool target_0, Bool target_1)
{
- CARD8 targets[2];
+ struct i830_sdvo_set_target_input_args targets = {0};
CARD8 status;
- targets[0] = target_1;
- targets[1] = target_2;
- i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, 2);
+ if (target_0 && target_1)
+ return SDVO_CMD_STATUS_NOTSUPP;
+
+ if (target_1)
+ targets.target_1 = 1;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets,
+ sizeof(targets));
status = i830_sdvo_read_response(output, NULL, 0);
@@ -272,47 +283,41 @@ i830_sdvo_set_target_input(I830OutputPtr output, Bool target_1, Bool target_2)
static Bool
i830_sdvo_get_trained_inputs(I830OutputPtr output, Bool *input_1, Bool *input_2)
{
- CARD8 response[2];
+ struct i830_sdvo_get_trained_inputs_response response;
CARD8 status;
i830_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0);
- status = i830_sdvo_read_response(output, response, 2);
+ status = i830_sdvo_read_response(output, &response, sizeof(response));
if (status != SDVO_CMD_STATUS_SUCCESS)
return FALSE;
- *input_1 = response[0];
- *input_2 = response[1];
+ *input_1 = response.input0_trained;
+ *input_2 = response.input1_trained;
return TRUE;
}
static Bool
-i830_sdvo_get_active_outputs(I830OutputPtr output, Bool *on_1, Bool *on_2)
+i830_sdvo_get_active_outputs(I830OutputPtr output,
+ struct i830_sdvo_output_flags *outputs)
{
- CARD8 response[2];
CARD8 status;
i830_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0);
-
- status = i830_sdvo_read_response(output, &response, 2);
-
- *on_1 = response[0];
- *on_2 = response[1];
+ status = i830_sdvo_read_response(output, outputs, sizeof(*outputs));
return (status == SDVO_CMD_STATUS_SUCCESS);
}
static Bool
-i830_sdvo_set_active_outputs(I830OutputPtr output, Bool on_1, Bool on_2)
+i830_sdvo_set_active_outputs(I830OutputPtr output,
+ struct i830_sdvo_output_flags *outputs)
{
- CARD8 outputs[2];
CARD8 status;
- outputs[0] = on_1;
- outputs[1] = on_2;
- i830_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, 2);
-
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, outputs,
+ sizeof(*outputs));
status = i830_sdvo_read_response(output, NULL, 0);
return (status == SDVO_CMD_STATUS_SUCCESS);
@@ -339,14 +344,13 @@ i830_sdvo_get_input_pixel_clock_range(I830OutputPtr output, CARD16 *clock_min,
}
static Bool
-i830_sdvo_set_target_output(I830OutputPtr output, Bool target_1, Bool target_2)
+i830_sdvo_set_target_output(I830OutputPtr output,
+ struct i830_sdvo_output_flags *outputs)
{
- CARD8 targets[2];
CARD8 status;
- targets[0] = target_1;
- targets[1] = target_2;
- i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &targets, 2);
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, outputs,
+ sizeof(*outputs));
status = i830_sdvo_read_response(output, NULL, 0);
@@ -508,11 +512,15 @@ i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr mode)
{
I830Ptr pI830 = I830PTR(pScrn);
+ struct i830_sdvo_priv *dev_priv = output->dev_priv;
CARD16 width = mode->CrtcHDisplay;
CARD16 height = mode->CrtcVDisplay;
CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
CARD16 h_sync_offset, v_sync_offset;
struct i830_sdvo_dtd output_dtd;
+ struct i830_sdvo_output_flags no_outputs;
+
+ memset(&no_outputs, 0, sizeof(no_outputs));
/* do some mode translations */
h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart;
@@ -549,13 +557,13 @@ i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
output_dtd.part2.dtd_flags |= 0x4;
/* Turn off the screens before adjusting timings */
- i830_sdvo_set_active_outputs(output, FALSE, FALSE);
+ i830_sdvo_set_active_outputs(output, &no_outputs);
/* Set the output timing to the screen */
- i830_sdvo_set_target_output(output, TRUE, FALSE);
+ i830_sdvo_set_target_output(output, &dev_priv->active_outputs);
i830_sdvo_set_output_timing(output, &output_dtd);
- /* Set the input timing to the screen */
+ /* Set the input timing to the screen. Assume always input 0. */
i830_sdvo_set_target_input(output, TRUE, FALSE);
/* We would like to use i830_sdvo_create_preferred_input_timing() to
@@ -597,29 +605,15 @@ i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
DisplayModePtr mode)
{
I830Ptr pI830 = I830PTR(pScrn);
- Bool out1, out2, input1, input2;
+ struct i830_sdvo_priv *dev_priv = output->dev_priv;
+ Bool input1, input2;
CARD32 dpll, sdvob, sdvoc;
int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B;
int dpll_md_reg = (output->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
int sdvo_pixel_multiply;
+ int i;
CARD8 status;
- /* the BIOS writes out 6 commands post mode set */
- /* two 03s, 04 05, 10, 1d */
- /* these contain the height and mode clock / 10 by the looks of it */
-
- status = i830_sdvo_get_trained_inputs(output, &input1, &input2);
-
- /* Warn if the device reported failure to sync. */
- if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "First SDVO output reported failure to sync\n");
- }
-
- i830_sdvo_get_active_outputs(output, &out1, &out2);
- i830_sdvo_set_active_outputs(output, TRUE, FALSE);
- i830_sdvo_set_target_input(output, FALSE, FALSE);
-
/* Set the SDVO control regs. */
sdvob = INREG(SDVOB) & SDVOB_PRESERVE_MASK;
sdvoc = INREG(SDVOC) & SDVOC_PRESERVE_MASK;
@@ -644,18 +638,37 @@ i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
OUTREG(SDVOB, sdvob);
OUTREG(SDVOC, sdvoc);
+
+ for (i = 0; i < 2; i++)
+ i830WaitForVblank(pScrn);
+
+ status = i830_sdvo_get_trained_inputs(output, &input1, &input2);
+
+ /* Warn if the device reported failure to sync. */
+ if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "First SDVO output reported failure to sync\n");
+ }
+
+ i830_sdvo_set_active_outputs(output, &dev_priv->active_outputs);
+ i830_sdvo_set_target_input(output, TRUE, FALSE);
}
static void
i830_sdvo_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
{
I830Ptr pI830 = I830PTR(pScrn);
+ struct i830_sdvo_priv *dev_priv = output->dev_priv;
if (mode != DPMSModeOn) {
- i830_sdvo_set_active_outputs(output, FALSE, FALSE);
+ struct i830_sdvo_output_flags no_outputs;
+
+ memset(&no_outputs, 0, sizeof(no_outputs));
+
+ i830_sdvo_set_active_outputs(output, &no_outputs);
OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE);
} else {
- i830_sdvo_set_active_outputs(output, TRUE, FALSE);
+ i830_sdvo_set_active_outputs(output, &dev_priv->active_outputs);
OUTREG(SDVOB, INREG(SDVOB) | SDVO_ENABLE);
}
}
@@ -666,12 +679,13 @@ i830_sdvo_save(ScrnInfoPtr pScrn, I830OutputPtr output)
I830Ptr pI830 = I830PTR(pScrn);
struct i830_sdvo_priv *dev_priv = output->dev_priv;
+ /* XXX: We should save the in/out mapping. */
+
dev_priv->save_sdvo_mult = i830_sdvo_get_clock_rate_mult(output);
- i830_sdvo_get_active_outputs(output, &dev_priv->save_sdvo_active_1,
- &dev_priv->save_sdvo_active_2);
+ i830_sdvo_get_active_outputs(output, &dev_priv->save_active_outputs);
if (dev_priv->caps.sdvo_inputs_mask & 0x1) {
- i830_sdvo_set_target_input(output, FALSE, FALSE);
+ i830_sdvo_set_target_input(output, TRUE, FALSE);
i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1);
}
@@ -680,15 +694,11 @@ i830_sdvo_save(ScrnInfoPtr pScrn, I830OutputPtr output)
i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_2);
}
- if (dev_priv->caps.output_0_supported) {
- i830_sdvo_set_target_output(output, TRUE, FALSE);
- i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd_1);
- }
-
- if (dev_priv->caps.output_1_supported) {
- i830_sdvo_set_target_output(output, FALSE, TRUE);
- i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd_2);
- }
+ /* XXX: We should really iterate over the enabled outputs and save each
+ * one's state.
+ */
+ i830_sdvo_set_target_output(output, &dev_priv->save_active_outputs);
+ i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd);
dev_priv->save_SDVOX = INREG(dev_priv->output_device);
}
@@ -700,7 +710,7 @@ i830_sdvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
struct i830_sdvo_priv *dev_priv = output->dev_priv;
if (dev_priv->caps.sdvo_inputs_mask & 0x1) {
- i830_sdvo_set_target_input(output, FALSE, FALSE);
+ i830_sdvo_set_target_input(output, TRUE, FALSE);
i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1);
}
@@ -709,22 +719,14 @@ i830_sdvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_2);
}
- if (dev_priv->caps.output_0_supported) {
- i830_sdvo_set_target_output(output, TRUE, FALSE);
- i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd_1);
- }
-
- if (dev_priv->caps.output_1_supported) {
- i830_sdvo_set_target_output(output, FALSE, TRUE);
- i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd_2);
- }
+ i830_sdvo_set_target_output(output, &dev_priv->save_active_outputs);
+ i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd);
i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult);
OUTREG(dev_priv->output_device, dev_priv->save_SDVOX);
- i830_sdvo_set_active_outputs(output, dev_priv->save_sdvo_active_1,
- dev_priv->save_sdvo_active_2);
+ i830_sdvo_set_active_outputs(output, &dev_priv->save_active_outputs);
}
static int
@@ -743,7 +745,7 @@ i830_sdvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
}
static Bool
-i830_sdvo_get_capabilities(I830OutputPtr output, i830_sdvo_caps *caps)
+i830_sdvo_get_capabilities(I830OutputPtr output, struct i830_sdvo_caps *caps)
{
CARD8 status;
@@ -866,7 +868,7 @@ i830_sdvo_dump_device(I830OutputPtr output)
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS);
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT);
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG);
- i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INTR_EVENT_SOURCE);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE);
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART1);
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART2);
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1);
@@ -1023,6 +1025,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
i830_sdvo_get_input_pixel_clock_range(output, &dev_priv->pixel_clock_min,
&dev_priv->pixel_clock_max);
+ memset(&dev_priv->active_outputs, 0, sizeof(dev_priv->active_outputs));
+ dev_priv->active_outputs.tmds0 = 1;
+
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"SDVO device VID/DID: %02X:%02X.%02X, "
"input 1: %c, input 2: %c, "
@@ -1031,8 +1036,8 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
dev_priv->caps.device_rev_id,
(dev_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
(dev_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
- dev_priv->caps.output_0_supported ? 'Y' : 'N',
- dev_priv->caps.output_1_supported ? 'Y' : 'N');
+ dev_priv->caps.output_flags.tmds0 ? 'Y' : 'N',
+ dev_priv->caps.output_flags.tmds1 ? 'Y' : 'N');
pI830->num_outputs++;
}