summaryrefslogtreecommitdiff
path: root/src/i830_sdvo.c
diff options
context:
space:
mode:
authorHong Liu <hong.liu@intel.com>2008-06-20 10:57:14 +0800
committerEric Anholt <eric@anholt.net>2008-06-26 09:30:57 -0700
commit45c1da56891723dd85153853885dd3b52a23c117 (patch)
tree2cc2958c10cef8ccdbd6735905b88f2b0b5b1643 /src/i830_sdvo.c
parent894fbc9d124e4c9dd982e14b83d47f51c479d5b6 (diff)
Fix SDVO HDMI output.
While some cards had enough initialized at startup to work already, others required that the driver actually initialize the required AVI info frame. (cherry picked from commit 05df8c0b31721a9ccc7215fb1cda1115758367c7)
Diffstat (limited to 'src/i830_sdvo.c')
-rw-r--r--src/i830_sdvo.c233
1 files changed, 225 insertions, 8 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index cdfc9c66..d9b76d40 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -92,6 +92,9 @@ struct i830_sdvo_priv {
*/
struct i830_sdvo_tv_format tv_format;
+ /** supported encoding mode, used to determine whether HDMI is supported */
+ struct i830_sdvo_encode encode;
+
/** DDC bus used by this SDVO output */
uint8_t ddc_bus;
@@ -229,6 +232,19 @@ const static struct _sdvo_cmd_name {
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),
+ /* HDMI op code */
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_STAT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INDEX),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_INDEX),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INFO),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_AV_SPLIT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE),
};
static I2CSlaveAddr slaveAddr;
@@ -741,6 +757,190 @@ i830_sdvo_get_mode_from_dtd(DisplayModePtr mode, struct i830_sdvo_dtd *dtd)
}
static Bool
+i830_sdvo_get_supp_encode(xf86OutputPtr output, struct i830_sdvo_encode *encode)
+{
+ uint8_t status;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0);
+ status = i830_sdvo_read_response(output, encode, sizeof(*encode));
+ if (status != SDVO_CMD_STATUS_SUCCESS) {
+ memset(encode, 0, sizeof(*encode));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static Bool
+i830_sdvo_set_encode(xf86OutputPtr output, uint8_t mode)
+{
+ uint8_t status;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODE, &mode, 1);
+ status = i830_sdvo_read_response(output, NULL, 0);
+
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static Bool
+i830_sdvo_set_colorimetry(xf86OutputPtr output, uint8_t mode)
+{
+ uint8_t status;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
+ status = i830_sdvo_read_response(output, NULL, 0);
+
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+#if 0
+static Bool
+i830_sdvo_set_pixel_repli(xf86OutputPtr output, uint8_t repli)
+{
+ uint8_t status;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_PIXEL_REPLI, &repli, 1);
+ status = i830_sdvo_read_response(output, NULL, 0);
+
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+#endif
+
+static void i830_sdvo_dump_hdmi_buf(xf86OutputPtr output)
+{
+ int i, j;
+ uint8_t set_buf_index[2];
+ uint8_t av_split;
+ uint8_t buf_size;
+ uint8_t buf[48];
+ uint8_t *pos;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_AV_SPLIT, NULL, 0);
+ i830_sdvo_read_response(output, &av_split, 1);
+
+ for (i = 0; i <= av_split; i++) {
+ set_buf_index[0] = i; set_buf_index[1] = 0;
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX,
+ set_buf_index, 2);
+ i830_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
+ i830_sdvo_read_response(output, &buf_size, 1);
+
+ pos = buf;
+ for (j = 0; j <= buf_size; j += 8) {
+ i830_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_DATA, NULL, 0);
+ i830_sdvo_read_response(output, pos, 8);
+ pos += 8;
+ }
+ }
+}
+
+static void i830_sdvo_set_hdmi_buf(xf86OutputPtr output, int index,
+ uint8_t *data, int8_t size, uint8_t tx_rate)
+{
+ uint8_t set_buf_index[2];
+
+ set_buf_index[0] = index;
+ set_buf_index[1] = 0;
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2);
+
+ for (; size > 0; size -= 8) {
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_DATA, data, 8);
+ data += 8;
+ }
+
+ i830_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
+}
+
+static uint8_t i830_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size)
+{
+ uint8_t csum = 0;
+ int i;
+
+ for (i = 0; i < size; i++)
+ csum += data[i];
+
+ return 0x100 - csum;
+}
+
+#define DIP_TYPE_AVI 0x82
+#define DIP_VERSION_AVI 0x2
+#define DIP_LEN_AVI 13
+
+struct dip_infoframe {
+ uint8_t type;
+ uint8_t version;
+ uint8_t len;
+ uint8_t checksum;
+ union {
+ struct {
+ /* Packet Byte #1 */
+ uint8_t S:2;
+ uint8_t B:2;
+ uint8_t A:1;
+ uint8_t Y:2;
+ uint8_t rsvd1:1;
+ /* Packet Byte #2 */
+ uint8_t R:4;
+ uint8_t M:2;
+ uint8_t C:2;
+ /* Packet Byte #3 */
+ uint8_t SC:2;
+ uint8_t Q:2;
+ uint8_t EC:3;
+ uint8_t ITC:1;
+ /* Packet Byte #4 */
+ uint8_t VIC:7;
+ uint8_t rsvd2:1;
+ /* Packet Byte #5 */
+ uint8_t PR:4;
+ uint8_t rsvd3:4;
+ /* Packet Byte #6~13 */
+ uint16_t top_bar_end;
+ uint16_t bottom_bar_start;
+ uint16_t left_bar_end;
+ uint16_t right_bar_start;
+ } avi;
+ struct {
+ /* Packet Byte #1 */
+ uint8_t CC:3;
+ uint8_t rsvd1:1;
+ uint8_t CT:4;
+ /* Packet Byte #2 */
+ uint8_t SS:2;
+ uint8_t SF:3;
+ uint8_t rsvd2:3;
+ /* Packet Byte #3 */
+ uint8_t CXT:5;
+ uint8_t rsvd3:3;
+ /* Packet Byte #4 */
+ uint8_t CA;
+ /* Packet Byte #5 */
+ uint8_t rsvd4:3;
+ uint8_t LSV:4;
+ uint8_t DM_INH:1;
+ } audio;
+ uint8_t payload[28];
+ } __attribute__ ((packed)) u;
+} __attribute__((packed));
+
+static void i830_sdvo_set_avi_infoframe(xf86OutputPtr output,
+ DisplayModePtr mode)
+{
+ struct dip_infoframe avi_if = {
+ .type = DIP_TYPE_AVI,
+ .version = DIP_VERSION_AVI,
+ .len = DIP_LEN_AVI,
+ };
+
+ avi_if.u.avi.PR = i830_sdvo_get_pixel_multiplier(mode) - 1;
+ avi_if.checksum = i830_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
+ 4 + avi_if.len);
+ i830_sdvo_set_hdmi_buf(output, 1, (uint8_t *)&avi_if, 4 + avi_if.len,
+ SDVO_HBUF_TX_VSYNC);
+}
+
+static Bool
i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
DisplayModePtr adjusted_mode)
{
@@ -827,6 +1027,9 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
&in_out, sizeof(in_out));
status = i830_sdvo_read_response(output, NULL, 0);
+ if (dev_priv->encode.hdmi_rev)
+ i830_sdvo_set_avi_infoframe(output, mode);
+
i830_sdvo_get_dtd_from_mode(&input_dtd, mode);
/* If it's a TV, we already set the output timing in mode_fixup.
@@ -1203,6 +1406,15 @@ i830_sdvo_dump_device(xf86OutputPtr output)
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);
+
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_SUPP_ENCODE);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ENCODE);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_PIXEL_REPLI);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_COLORIMETRY_CAP);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_COLORIMETRY);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER);
+ i830_sdvo_dump_cmd(output, SDVO_CMD_GET_AUDIO_STAT);
+ i830_sdvo_dump_hdmi_buf(output);
}
void
@@ -1621,17 +1833,22 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
i830_sdvo_get_capabilities(output, &dev_priv->caps);
- if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
- {
- dev_priv->controlled_output = SDVO_OUTPUT_TMDS0;
- output->subpixel_order = SubPixelHorizontalRGB;
- name_prefix="TMDS";
- }
- else if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS1)
+ if (dev_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
{
- dev_priv->controlled_output = SDVO_OUTPUT_TMDS1;
+ if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+ dev_priv->controlled_output = SDVO_OUTPUT_TMDS0;
+ else
+ dev_priv->controlled_output = SDVO_OUTPUT_TMDS1;
output->subpixel_order = SubPixelHorizontalRGB;
name_prefix="TMDS";
+
+ i830_sdvo_get_supp_encode(output, &dev_priv->encode);
+ if (dev_priv->encode.hdmi_rev != 0) {
+ /* enable hdmi encoding mode if supported */
+ i830_sdvo_set_encode(output, SDVO_ENCODE_HDMI);
+ i830_sdvo_set_colorimetry(output, SDVO_COLORIMETRY_RGB256);
+ name_prefix = "HDMI";
+ }
}
else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
{