summaryrefslogtreecommitdiff
path: root/src/i830_sdvo.c
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2008-04-02 14:21:23 -0700
committerEric Anholt <eric@anholt.net>2008-04-02 16:06:46 -0700
commit3a17400dc67534f0eb474ece080f01061469569c (patch)
tree2e3a357d0db6007165e58460229b36c4472ca9b3 /src/i830_sdvo.c
parent3c1701797b61afaae826a78455079e2115483053 (diff)
SDVO: Handle RGB outputs that are really TV outputs, and select a TV format.
Still doesn't light anything up.
Diffstat (limited to 'src/i830_sdvo.c')
-rw-r--r--src/i830_sdvo.c129
1 files changed, 107 insertions, 22 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 6c23c157..59d97c66 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -69,6 +69,29 @@ struct i830_sdvo_priv {
/** Pixel clock limitations reported by the SDVO device, in kHz */
int pixel_clock_min, pixel_clock_max;
+ /**
+ * This is set if we're going to treat the device as TV-out.
+ *
+ * While we have these nice friendly flags for output types that ought to
+ * decide this for us, the S-Video output on our HDMI+S-Video card shows
+ * up as RGB1 (VGA).
+ */
+ Bool is_tv;
+
+ /**
+ * Returned SDTV resolutions allowed for the current format, if the
+ * device reported it.
+ */
+ struct i830_sdvo_sdtv_resolution_reply sdtv_resolutions;
+
+ /**
+ * Current selected TV format.
+ *
+ * This is stored in the same structure that's passed to the device, for
+ * convenience.
+ */
+ struct i830_sdvo_tv_format tv_format;
+
/** State for save/restore */
/** @{ */
int save_sdvo_mult;
@@ -201,6 +224,8 @@ const static struct _sdvo_cmd_name {
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS),
};
static I2CSlaveAddr slaveAddr;
@@ -837,6 +862,9 @@ i830_sdvo_save(xf86OutputPtr output)
i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd[o]);
}
}
+ if (dev_priv->is_tv) {
+ /* XXX: Save TV format/enhancements. */
+ }
dev_priv->save_SDVOX = INREG(dev_priv->output_device);
}
@@ -876,6 +904,10 @@ i830_sdvo_restore(xf86OutputPtr output)
i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult);
+ if (dev_priv->is_tv) {
+ /* XXX: Restore TV format/enhancements. */
+ }
+
i830_sdvo_write_sdvox(output, dev_priv->save_SDVOX);
if (dev_priv->save_SDVOX & SDVO_ENABLE)
@@ -1052,6 +1084,8 @@ i830_sdvo_dump_device(xf86OutputPtr output)
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT);
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS);
i830_sdvo_dump_cmd(output, SDVO_CMD_GET_TV_FORMAT);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS);
}
void
@@ -1169,40 +1203,73 @@ i830_sdvo_get_tv_mode(DisplayModePtr *head, int width, int height,
*head = mode;
}
+/**
+ * This function checks the current TV format, and chooses a default if
+ * it hasn't been set.
+ */
+static void
+i830_sdvo_check_tv_format(xf86OutputPtr output)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ I830OutputPrivatePtr intel_output = output->driver_private;
+ struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
+ struct i830_sdvo_tv_format format, unset;
+ uint8_t status;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
+ status = i830_sdvo_read_response(output, &format, sizeof(format));
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return;
+
+ memset(&unset, 0, sizeof(unset));
+ if (memcmp(&format, &unset, sizeof(format))) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "%s: Choosing default TV format of NTSC-M\n",
+ SDVO_NAME(dev_priv));
+
+ format.ntsc_m = TRUE;
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0);
+ status = i830_sdvo_read_response(output, NULL, 0);
+ }
+}
+
static DisplayModePtr
i830_sdvo_get_tv_modes(xf86OutputPtr output)
{
- ScrnInfoPtr pScrn = output->scrn;
+ I830OutputPrivatePtr intel_output = output->driver_private;
+ struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
DisplayModePtr modes = NULL;
- struct i830_sdvo_sdtv_resolution_reply res;
+ struct i830_sdvo_sdtv_resolution_reply *res = &dev_priv->sdtv_resolutions;
uint8_t status;
float refresh = 60; /* XXX */
+ i830_sdvo_check_tv_format(output);
+
/* Read the list of supported input resolutions for the selected TV format.
*/
i830_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, NULL, 0);
- status = i830_sdvo_read_response(output, &res, sizeof(res));
+ status = i830_sdvo_read_response(output, res, sizeof(*res));
if (status != SDVO_CMD_STATUS_SUCCESS)
return NULL;
- if (res.res_320x200) i830_sdvo_get_tv_mode(&modes, 320, 200, refresh);
- if (res.res_320x240) i830_sdvo_get_tv_mode(&modes, 320, 240, refresh);
- if (res.res_400x300) i830_sdvo_get_tv_mode(&modes, 400, 300, refresh);
- if (res.res_640x350) i830_sdvo_get_tv_mode(&modes, 640, 350, refresh);
- if (res.res_640x400) i830_sdvo_get_tv_mode(&modes, 640, 400, refresh);
- if (res.res_640x480) i830_sdvo_get_tv_mode(&modes, 640, 480, refresh);
- if (res.res_704x480) i830_sdvo_get_tv_mode(&modes, 704, 480, refresh);
- if (res.res_704x576) i830_sdvo_get_tv_mode(&modes, 704, 576, refresh);
- if (res.res_720x350) i830_sdvo_get_tv_mode(&modes, 720, 350, refresh);
- if (res.res_720x400) i830_sdvo_get_tv_mode(&modes, 720, 400, refresh);
- if (res.res_720x480) i830_sdvo_get_tv_mode(&modes, 720, 480, refresh);
- if (res.res_720x540) i830_sdvo_get_tv_mode(&modes, 720, 540, refresh);
- if (res.res_720x576) i830_sdvo_get_tv_mode(&modes, 720, 576, refresh);
- if (res.res_800x600) i830_sdvo_get_tv_mode(&modes, 800, 600, refresh);
- if (res.res_832x624) i830_sdvo_get_tv_mode(&modes, 832, 624, refresh);
- if (res.res_920x766) i830_sdvo_get_tv_mode(&modes, 920, 766, refresh);
- if (res.res_1024x768) i830_sdvo_get_tv_mode(&modes, 1024, 768, refresh);
- if (res.res_1280x1024) i830_sdvo_get_tv_mode(&modes, 1280, 1024, refresh);
+ if (res->res_320x200) i830_sdvo_get_tv_mode(&modes, 320, 200, refresh);
+ if (res->res_320x240) i830_sdvo_get_tv_mode(&modes, 320, 240, refresh);
+ if (res->res_400x300) i830_sdvo_get_tv_mode(&modes, 400, 300, refresh);
+ if (res->res_640x350) i830_sdvo_get_tv_mode(&modes, 640, 350, refresh);
+ if (res->res_640x400) i830_sdvo_get_tv_mode(&modes, 640, 400, refresh);
+ if (res->res_640x480) i830_sdvo_get_tv_mode(&modes, 640, 480, refresh);
+ if (res->res_704x480) i830_sdvo_get_tv_mode(&modes, 704, 480, refresh);
+ if (res->res_704x576) i830_sdvo_get_tv_mode(&modes, 704, 576, refresh);
+ if (res->res_720x350) i830_sdvo_get_tv_mode(&modes, 720, 350, refresh);
+ if (res->res_720x400) i830_sdvo_get_tv_mode(&modes, 720, 400, refresh);
+ if (res->res_720x480) i830_sdvo_get_tv_mode(&modes, 720, 480, refresh);
+ if (res->res_720x540) i830_sdvo_get_tv_mode(&modes, 720, 540, refresh);
+ if (res->res_720x576) i830_sdvo_get_tv_mode(&modes, 720, 576, refresh);
+ if (res->res_800x600) i830_sdvo_get_tv_mode(&modes, 800, 600, refresh);
+ if (res->res_832x624) i830_sdvo_get_tv_mode(&modes, 832, 624, refresh);
+ if (res->res_920x766) i830_sdvo_get_tv_mode(&modes, 920, 766, refresh);
+ if (res->res_1024x768) i830_sdvo_get_tv_mode(&modes, 1024, 768, refresh);
+ if (res->res_1280x1024) i830_sdvo_get_tv_mode(&modes, 1280, 1024, refresh);
return modes;
}
@@ -1213,7 +1280,7 @@ i830_sdvo_get_modes(xf86OutputPtr output)
I830OutputPrivatePtr intel_output = output->driver_private;
struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
- if (dev_priv->controlled_output == SDVO_OUTPUT_SVID0)
+ if (dev_priv->is_tv)
return i830_sdvo_get_tv_modes(output);
else
return i830_sdvo_get_ddc_modes(output);
@@ -1278,6 +1345,7 @@ 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)
@@ -1412,6 +1480,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
name_prefix="S-Video";
+ dev_priv->is_tv = TRUE;
}
else
{
@@ -1425,6 +1494,22 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
bytes[0], bytes[1]);
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))