diff options
author | Hong Liu <hong.liu@intel.com> | 2008-06-20 10:57:14 +0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2008-06-26 09:30:57 -0700 |
commit | 45c1da56891723dd85153853885dd3b52a23c117 (patch) | |
tree | 2cc2958c10cef8ccdbd6735905b88f2b0b5b1643 | |
parent | 894fbc9d124e4c9dd982e14b83d47f51c479d5b6 (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)
-rw-r--r-- | src/i830_sdvo.c | 233 | ||||
-rw-r--r-- | src/i830_sdvo_regs.h | 36 |
2 files changed, 261 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) { diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h index dc2522a3..747f2cdd 100644 --- a/src/i830_sdvo_regs.h +++ b/src/i830_sdvo_regs.h @@ -511,3 +511,39 @@ struct i830_sdvo_enhancements_arg { # define SDVO_CONTROL_BUS_DDC2 (1 << 2) # define SDVO_CONTROL_BUS_DDC3 (1 << 3) +/* HDMI op codes */ +#define SDVO_CMD_GET_SUPP_ENCODE 0x9d +#define SDVO_CMD_GET_ENCODE 0x9e +#define SDVO_CMD_SET_ENCODE 0x9f + #define SDVO_ENCODE_DVI 0x0 + #define SDVO_ENCODE_HDMI 0x1 +#define SDVO_CMD_SET_PIXEL_REPLI 0x8b +#define SDVO_CMD_GET_PIXEL_REPLI 0x8c +#define SDVO_CMD_GET_COLORIMETRY_CAP 0x8d +#define SDVO_CMD_SET_COLORIMETRY 0x8e + #define SDVO_COLORIMETRY_RGB256 0x0 + #define SDVO_COLORIMETRY_RGB220 0x1 + #define SDVO_COLORIMETRY_YCrCb422 0x3 + #define SDVO_COLORIMETRY_YCrCb444 0x4 +#define SDVO_CMD_GET_COLORIMETRY 0x8f +#define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90 +#define SDVO_CMD_SET_AUDIO_STAT 0x91 +#define SDVO_CMD_GET_AUDIO_STAT 0x92 +#define SDVO_CMD_SET_HBUF_INDEX 0x93 +#define SDVO_CMD_GET_HBUF_INDEX 0x94 +#define SDVO_CMD_GET_HBUF_INFO 0x95 +#define SDVO_CMD_SET_HBUF_AV_SPLIT 0x96 +#define SDVO_CMD_GET_HBUF_AV_SPLIT 0x97 +#define SDVO_CMD_SET_HBUF_DATA 0x98 +#define SDVO_CMD_GET_HBUF_DATA 0x99 +#define SDVO_CMD_SET_HBUF_TXRATE 0x9a +#define SDVO_CMD_GET_HBUF_TXRATE 0x9b + #define SDVO_HBUF_TX_DISABLED (0 << 6) + #define SDVO_HBUF_TX_ONCE (2 << 6) + #define SDVO_HBUF_TX_VSYNC (3 << 6) +#define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c + +struct i830_sdvo_encode{ + uint8_t dvi_rev; + uint8_t hdmi_rev; +} __attribute__ ((packed)); |