summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2008-04-02 15:16:17 -0700
committerEric Anholt <eric@anholt.net>2008-04-02 16:11:18 -0700
commit6ad2d6ba86689674876f5f4c473f11e39243ac38 (patch)
treee72f47f0c4492484701b3da79f67ca9f868d3cc1
parent3a17400dc67534f0eb474ece080f01061469569c (diff)
SDVO: Fix mixups with input and output channels.
The 2-bit input_mask was actually an input count -- in0 is always there, and in1 is optional. The output flags weren't being reported in the log, so I mistakenly took controlled_output == RGB0 to mean that the device only reported an RGB0, while it actually reported RGB0|SVID0|YPRPB0|misc|other. Move SVID0 up in priority and remove the RGB-is-it-really-TV hack I had just come up with. Finally, set the input/output mapping at mode set time. We're always supposed to do this, but haven't had to so far as we've never handled devices with more than one output.
-rw-r--r--src/i830_sdvo.c108
-rw-r--r--src/i830_sdvo_regs.h5
2 files changed, 66 insertions, 47 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 59d97c66..46213a2f 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -230,7 +230,7 @@ const static struct _sdvo_cmd_name {
static I2CSlaveAddr slaveAddr;
-#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVO" : "SDVO")
+#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC")
#define SDVO_PRIV(output) ((struct i830_sdvo_priv *) (output)->dev_priv)
/**
@@ -668,13 +668,26 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
uint16_t width, height;
uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
uint16_t h_sync_offset, v_sync_offset;
+ struct i830_sdvo_in_out_map in_out;
struct i830_sdvo_dtd output_dtd;
- uint16_t no_outputs;
-
- no_outputs = 0;
+ uint8_t status;
if (!mode)
return;
+
+ /* First, set the input mapping for the first input to our controlled
+ * output. This is only correct if we're a single-input device, in
+ * which case the first input is the output from the appropriate SDVO
+ * channel on the motherboard. In a two-input device, the first input
+ * will be SDVOB and the second SDVOC.
+ */
+ in_out.in0 = dev_priv->controlled_output;
+ in_out.in1 = 0;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_IN_OUT_MAP,
+ &in_out, sizeof(in_out));
+ status = i830_sdvo_read_response(output, NULL, 0);
+
width = mode->CrtcHDisplay;
height = mode->CrtcVDisplay;
@@ -843,12 +856,10 @@ i830_sdvo_save(xf86OutputPtr output)
dev_priv->save_sdvo_mult = i830_sdvo_get_clock_rate_mult(output);
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, TRUE, FALSE);
- i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1);
- }
+ i830_sdvo_set_target_input(output, TRUE, FALSE);
+ i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1);
- if (dev_priv->caps.sdvo_inputs_mask & 0x2) {
+ if (dev_priv->caps.sdvo_input_count >= 2) {
i830_sdvo_set_target_input(output, FALSE, TRUE);
i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_2);
}
@@ -892,12 +903,10 @@ i830_sdvo_restore(xf86OutputPtr output)
}
}
- if (dev_priv->caps.sdvo_inputs_mask & 0x1) {
- i830_sdvo_set_target_input(output, TRUE, FALSE);
- i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1);
- }
+ i830_sdvo_set_target_input(output, TRUE, FALSE);
+ i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1);
- if (dev_priv->caps.sdvo_inputs_mask & 0x2) {
+ if (dev_priv->caps.sdvo_input_count >= 2) {
i830_sdvo_set_target_input(output, FALSE, TRUE);
i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_2);
}
@@ -1345,7 +1354,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
char name[60];
char *name_prefix;
char *name_suffix;
- struct i830_sdvo_tv_format tv_formats;
output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL);
if (!output)
@@ -1463,6 +1471,13 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
output->subpixel_order = SubPixelHorizontalRGB;
name_prefix="TMDS";
}
+ else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
+ {
+ dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
+ output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
+ name_prefix="TV";
+ dev_priv->is_tv = TRUE;
+ }
else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
{
dev_priv->controlled_output = SDVO_OUTPUT_RGB0;
@@ -1475,13 +1490,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
output->subpixel_order = SubPixelHorizontalRGB;
name_prefix="VGA";
}
- else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
- {
- dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
- output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
- name_prefix="S-Video";
- dev_priv->is_tv = TRUE;
- }
else
{
unsigned char bytes[2];
@@ -1495,21 +1503,6 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
name_prefix="Unknown";
}
- if (dev_priv->controlled_output == SDVO_OUTPUT_RGB0 ||
- dev_priv->controlled_output == SDVO_OUTPUT_RGB1) {
- uint8_t status;
-
- /* Detect if an RGB device is actually a TV device. This is the
- * case for our HDMI+S-Video SDVO card.
- */
- i830_sdvo_write_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS,
- NULL, 0);
- status = i830_sdvo_read_response(output,
- &tv_formats, sizeof(tv_formats));
- if (status == SDVO_CMD_STATUS_SUCCESS)
- dev_priv->is_tv = TRUE;
- }
-
strcpy (name, name_prefix);
strcat (name, name_suffix);
if (!xf86OutputRename (output, name))
@@ -1526,17 +1519,40 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
&dev_priv->pixel_clock_max);
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "%s device VID/DID: %02X:%02X.%02X, "
- "clock range %.1fMHz - %.1fMHz, "
- "input 1: %c, input 2: %c, "
- "output 1: %c, output 2: %c\n",
+ "%s: device VID/DID: %02X:%02X.%02X, "
+ "clock range %.1fMHz - %.1fMHz\n",
SDVO_NAME(dev_priv),
dev_priv->caps.vendor_id, dev_priv->caps.device_id,
dev_priv->caps.device_rev_id,
dev_priv->pixel_clock_min / 1000.0,
- dev_priv->pixel_clock_max / 1000.0,
- (dev_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
- (dev_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
- dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_TMDS0) ? 'Y' : 'N',
- dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB1 | SDVO_OUTPUT_TMDS1) ? 'Y' : 'N');
+ dev_priv->pixel_clock_max / 1000.0);
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "%s: %d input channel%s\n",
+ SDVO_NAME(dev_priv), dev_priv->caps.sdvo_input_count,
+ dev_priv->caps.sdvo_input_count >= 2 ? "s" : "");
+
+#define REPORT_OUTPUT_FLAG(flag, name) do { \
+ if (dev_priv->caps.output_flags & flag) { \
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s: %s output reported\n", \
+ SDVO_NAME(dev_priv), name); \
+ } \
+} while (0)
+
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_TMDS0, "TMDS0");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_RGB0, "RGB0");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_CVBS0, "CVBS0");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SVID0, "SVID0");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_YPRPB0, "YPRPB0");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SCART0, "SCART0");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_LVDS0, "LVDS0");
+
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_TMDS1, "TMDS1");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_RGB1, "RGB1");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_CVBS1, "CVBS1");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SVID1, "SVID1");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_YPRPB1, "YPRPB1");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_SCART1, "SCART1");
+ REPORT_OUTPUT_FLAG(SDVO_OUTPUT_LVDS1, "LVDS1");
+
}
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index 63688acd..3a2deafd 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -52,7 +52,7 @@ struct i830_sdvo_caps {
uint8_t device_rev_id;
uint8_t sdvo_version_major;
uint8_t sdvo_version_minor;
- unsigned int sdvo_inputs_mask:2;
+ unsigned int sdvo_input_count:2;
unsigned int smooth_scaling:1;
unsigned int sharp_scaling:1;
unsigned int up_scaling:1;
@@ -174,6 +174,9 @@ struct i830_sdvo_get_trained_inputs_response {
* Returns two struct i830_sdvo_output_flags structures.
*/
#define SDVO_CMD_GET_IN_OUT_MAP 0x06
+struct i830_sdvo_in_out_map {
+ uint16_t in0, in1;
+};
/**
* Sets the current mapping of SDVO inputs to outputs on the device.