diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index f60e38cf..642ba885 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -59,7 +59,7 @@ struct i830_sdvo_priv { int output_device; /** Active outputs controlled by this SDVO output */ - uint16_t active_outputs; + uint16_t controlled_output; /** * Capabilities of the SDVO device returned by i830_sdvo_get_capabilities() @@ -69,6 +69,32 @@ 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; + + /** DDC bus used by this SDVO output */ + uint8_t ddc_bus; + /** State for save/restore */ /** @{ */ int save_sdvo_mult; @@ -201,11 +227,13 @@ 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; -#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) /** @@ -643,13 +671,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; @@ -692,7 +733,7 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode, output_dtd.part2.reserved = 0; /* Set the output timing to the screen */ - i830_sdvo_set_target_output(output, dev_priv->active_outputs); + i830_sdvo_set_target_output(output, dev_priv->controlled_output); i830_sdvo_set_output_timing(output, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ @@ -800,7 +841,7 @@ i830_sdvo_dpms(xf86OutputPtr output, int mode) if (0) i830_sdvo_set_encoder_power_state(output, mode); - i830_sdvo_set_active_outputs(output, dev_priv->active_outputs); + i830_sdvo_set_active_outputs(output, dev_priv->controlled_output); } } @@ -818,12 +859,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); } @@ -837,6 +876,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); } @@ -864,18 +906,20 @@ 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); } 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) @@ -970,8 +1014,9 @@ i830_sdvo_ddc_i2c_start(I2CBusPtr b, int timeout) xf86OutputPtr output = b->DriverPrivate.ptr; I830OutputPrivatePtr intel_output = output->driver_private; I2CBusPtr i2cbus = intel_output->pI2CBus; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; - i830_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); + i830_sdvo_set_control_bus_switch(output, dev_priv->ddc_bus); return i2cbus->I2CStart(i2cbus, timeout); } @@ -1052,6 +1097,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 @@ -1098,7 +1145,7 @@ i830_sdvo_detect(xf86OutputPtr output) } static DisplayModePtr -i830_sdvo_get_modes(xf86OutputPtr output) +i830_sdvo_get_ddc_modes(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); @@ -1130,6 +1177,128 @@ i830_sdvo_get_modes(xf86OutputPtr output) return modes; } +/** + * Constructs a DisplayModeRec for the given widht/height/refresh, which will + * be programmed into the display pipe. The TV encoder's scaler will filter + * this to the format actually required by the display. + */ +static void +i830_sdvo_get_tv_mode(DisplayModePtr *head, int width, int height, + float refresh) +{ + DisplayModePtr mode; + + mode = xcalloc(1, sizeof(*mode)); + if (mode == NULL) + return; + + mode->name = XNFprintf("%dx%d@%.2f", width, height, refresh); + mode->HDisplay = width; + mode->HSyncStart = width + 1; + mode->HSyncEnd = width + 64; + mode->HTotal = width + 96; + + mode->VDisplay = height; + mode->VSyncStart = height + 1; + mode->VSyncEnd = height + 32; + mode->VTotal = height + 33; + + mode->Clock = (int) (refresh * mode->VTotal * mode->HTotal / 1000.0); + mode->type = M_T_DRIVER; + mode->next = NULL; + mode->prev = NULL; + + mode->next = NULL; + mode->prev = *head; + if (*head != NULL) + (*head)->next = mode; + else + *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) +{ + 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 = &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)); + 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); + + return modes; +} + +static DisplayModePtr +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->is_tv) + return i830_sdvo_get_tv_modes(output); + else + return i830_sdvo_get_ddc_modes(output); +} + static void i830_sdvo_destroy (xf86OutputPtr output) { @@ -1177,6 +1346,60 @@ static const xf86OutputFuncsRec i830_sdvo_output_funcs = { #endif }; +static unsigned int count_bits(uint32_t mask) +{ + unsigned int n; + + for (n = 0; mask; n++) + mask &= mask - 1; + + return n; +} + +/** + * Choose the appropriate DDC bus for control bus switch command for this + * SDVO output based on the controlled output. + * + * DDC bus number assignment is in a priority order of RGB outputs, then TMDS + * outputs, then LVDS outputs. + */ +static void +i830_sdvo_select_ddc_bus(struct i830_sdvo_priv *dev_priv) +{ + uint16_t mask = 0; + unsigned int num_bits; + + /* Make a mask of outputs less than or equal to our own priority in the + * list. + */ + switch (dev_priv->controlled_output) { + case SDVO_OUTPUT_LVDS1: + mask |= SDVO_OUTPUT_LVDS1; + case SDVO_OUTPUT_LVDS0: + mask |= SDVO_OUTPUT_LVDS0; + case SDVO_OUTPUT_TMDS1: + mask |= SDVO_OUTPUT_TMDS1; + case SDVO_OUTPUT_TMDS0: + mask |= SDVO_OUTPUT_TMDS0; + case SDVO_OUTPUT_RGB1: + mask |= SDVO_OUTPUT_RGB1; + case SDVO_OUTPUT_RGB0: + mask |= SDVO_OUTPUT_RGB0; + break; + } + + /* Count bits to find what number we are in the priority list. */ + mask &= dev_priv->caps.output_flags; + num_bits = count_bits(mask); + if (num_bits > 3) { + /* if more than 3 outputs, default to DDC bus 3 for now */ + num_bits = 3; + } + + /* Corresponds to SDVO_CONTROL_BUS_DDCx */ + dev_priv->ddc_bus = 1 << num_bits; +} + void i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) { @@ -1294,28 +1517,34 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) i830_sdvo_get_capabilities(output, &dev_priv->caps); - memset(&dev_priv->active_outputs, 0, sizeof(dev_priv->active_outputs)); if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { - dev_priv->active_outputs = 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) { - dev_priv->active_outputs = SDVO_OUTPUT_TMDS1; + dev_priv->controlled_output = SDVO_OUTPUT_TMDS1; 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->active_outputs = SDVO_OUTPUT_RGB0; + dev_priv->controlled_output = SDVO_OUTPUT_RGB0; output->subpixel_order = SubPixelHorizontalRGB; name_prefix="VGA"; } else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { - dev_priv->active_outputs = SDVO_OUTPUT_RGB1; + dev_priv->controlled_output = SDVO_OUTPUT_RGB1; output->subpixel_order = SubPixelHorizontalRGB; name_prefix="VGA"; } @@ -1323,13 +1552,15 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) { unsigned char bytes[2]; + dev_priv->controlled_output = 0; memcpy (bytes, &dev_priv->caps.output_flags, 2); - xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_ERROR, - "%s: No active TMDS outputs (0x%02x%02x)\n", + xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING, + "%s: Unknown SDVO output type (0x%02x%02x)\n", SDVO_NAME(dev_priv), bytes[0], bytes[1]); name_prefix="Unknown"; } + strcpy (name, name_prefix); strcat (name, name_suffix); if (!xf86OutputRename (output, name)) @@ -1337,8 +1568,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) xf86OutputDestroy (output); return; } - - + + i830_sdvo_select_ddc_bus(dev_priv); + /* Set the input timing to the screen. Assume always input 0. */ i830_sdvo_set_target_input(output, TRUE, FALSE); @@ -1346,17 +1578,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 725460f2..dc2522a3 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. @@ -306,11 +309,107 @@ struct i830_sdvo_set_target_input_args { # define SDVO_CLOCK_RATE_MULT_4X (1 << 3) #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 +/** 5 bytes of bit flags for TV formats shared by all TV format functions */ +struct i830_sdvo_tv_format { + unsigned int ntsc_m:1; + unsigned int ntsc_j:1; + unsigned int ntsc_443:1; + unsigned int pal_b:1; + unsigned int pal_d:1; + unsigned int pal_g:1; + unsigned int pal_h:1; + unsigned int pal_i:1; + + unsigned int pal_m:1; + unsigned int pal_n:1; + unsigned int pal_nc:1; + unsigned int pal_60:1; + unsigned int secam_b:1; + unsigned int secam_d:1; + unsigned int secam_g:1; + unsigned int secam_k:1; + + unsigned int secam_k1:1; + unsigned int secam_l:1; + unsigned int secam_60:1; + unsigned int hdtv_std_smpte_240m_1080i_59:1; + unsigned int hdtv_std_smpte_240m_1080i_60:1; + unsigned int hdtv_std_smpte_260m_1080i_59:1; + unsigned int hdtv_std_smpte_260m_1080i_60:1; + unsigned int hdtv_std_smpte_270m_1080i_50:1; + + unsigned int hdtv_std_smpte_274m_1080i_50:1; + unsigned int hdtv_std_smpte_274m_1080i_59:1; + unsigned int hdtv_std_smpte_274m_1080i_60:1; + unsigned int hdtv_std_smpte_274m_1080p_23:1; + unsigned int hdtv_std_smpte_274m_1080p_24:1; + unsigned int hdtv_std_smpte_274m_1080p_25:1; + unsigned int hdtv_std_smpte_274m_1080p_29:1; + unsigned int hdtv_std_smpte_274m_1080p_50:1; + + unsigned int hdtv_std_smpte_274m_1080p_59:1; + unsigned int hdtv_std_smpte_274m_1080p_60:1; + unsigned int hdtv_std_smpte_295m_1080i_50:1; + unsigned int hdtv_std_smpte_295m_1080p_50:1; + unsigned int hdtv_std_smpte_296m_720p_59:1; + unsigned int hdtv_std_smpte_296m_720p_60:1; + unsigned int hdtv_std_smpte_296m_720p_50:1; + unsigned int hdtv_std_smpte_293m_480p_59:1; + + unsigned int hdtv_std_smpte_270m_480i_59:1; + unsigned int hdtv_std_iturbt601_576i_50:1; + unsigned int hdtv_std_iturbt601_576p_50:1; + unsigned int hdtv_std_eia_7702a_480i_60:1; + unsigned int hdtv_std_eia_7702a_480p_60:1; + unsigned int pad:3; +} __attribute__((packed)); #define SDVO_CMD_GET_TV_FORMAT 0x28 +/** This command should be run before SetOutputTimingsPart[12] */ #define SDVO_CMD_SET_TV_FORMAT 0x29 +/** Returns the resolutiosn that can be used with the given TV format */ +#define SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT 0x83 +struct i830_sdvo_sdtv_resolution_request { + unsigned int ntsc_m:1; + unsigned int ntsc_j:1; + unsigned int ntsc_443:1; + unsigned int pal_b:1; + unsigned int pal_d:1; + unsigned int pal_g:1; + unsigned int pal_h:1; + unsigned int pal_i:1; + + unsigned int pal_m:1; + unsigned int pal_n:1; + unsigned int pal_nc:1; + unsigned int pal_60:1; +} __attribute__((packed)); +struct i830_sdvo_sdtv_resolution_reply { + unsigned int res_320x200:1; + unsigned int res_320x240:1; + unsigned int res_400x300:1; + unsigned int res_640x350:1; + unsigned int res_640x400:1; + unsigned int res_640x480:1; + unsigned int res_704x480:1; + unsigned int res_704x576:1; + + unsigned int res_720x350:1; + unsigned int res_720x400:1; + unsigned int res_720x480:1; + unsigned int res_720x540:1; + unsigned int res_720x576:1; + unsigned int res_800x600:1; + unsigned int res_832x624:1; + + unsigned int res_920x766:1; + unsigned int res_1024x768:1; + unsigned int res_1280x1024:1; + unsigned int pad:5; +} __attribute__((packed)); + #define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a #define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b #define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c @@ -319,11 +418,96 @@ struct i830_sdvo_set_target_input_args { # define SDVO_ENCODER_STATE_SUSPEND (1 << 2) # define SDVO_ENCODER_STATE_OFF (1 << 3) +#define SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS 0x84 +struct i830_sdvo_enhancements_reply { + unsigned int flicker_filter:1; + unsigned int flicker_filter_adaptive:1; + unsigned int flicker_filter_2d:1; + unsigned int saturation:1; + unsigned int hue:1; + unsigned int brightness:1; + unsigned int contrast:1; + unsigned int overscan_h:1; + + unsigned int overscan_v:1; + unsigned int position_h:1; + unsigned int position_v:1; + unsigned int sharpness:1; + unsigned int dot_crawl:1; + unsigned int dither:1; + unsigned int max_tv_chroma_filter:1; + unsigned int max_tv_luma_filter:1; +} __attribute__((packed)); + +/* Picture enhancement limits below are dependent on the current TV format, + * and thus need to be queried and set after it. + */ +#define SDVO_CMD_GET_MAX_FLICKER_FITER 0x4d +#define SDVO_CMD_GET_MAX_ADAPTIVE_FLICKER_FITER 0x7b +#define SDVO_CMD_GET_MAX_2D_FLICKER_FITER 0x52 +#define SDVO_CMD_GET_MAX_SATURATION 0x55 +#define SDVO_CMD_GET_MAX_HUE 0x58 +#define SDVO_CMD_GET_MAX_BRIGHTNESS 0x5c +#define SDVO_CMD_GET_MAX_CONTRAST 0x5e +#define SDVO_CMD_GET_MAX_OVERSCAN_H 0x61 +#define SDVO_CMD_GET_MAX_OVERSCAN_V 0x64 +#define SDVO_CMD_GET_MAX_POSITION_H 0x67 +#define SDVO_CMD_GET_MAX_POSITION_V 0x6a +#define SDVO_CMD_GET_MAX_SHARPNESS_V 0x6d +#define SDVO_CMD_GET_MAX_TV_CHROMA 0x74 +#define SDVO_CMD_GET_MAX_TV_LUMA 0x77 +struct i830_sdvo_enhancement_limits_reply { + uint16_t max_value; + uint16_t default_value; +} __attribute__((packed)); + +#define SDVO_CMD_GET_FLICKER_FITER 0x4d +#define SDVO_CMD_SET_FLICKER_FITER 0x4e +#define SDVO_CMD_GET_ADAPTIVE_FLICKER_FITER 0x50 +#define SDVO_CMD_SET_ADAPTIVE_FLICKER_FITER 0x51 +#define SDVO_CMD_GET_2D_FLICKER_FITER 0x53 +#define SDVO_CMD_SET_2D_FLICKER_FITER 0x54 +#define SDVO_CMD_GET_SATURATION 0x56 +#define SDVO_CMD_SET_SATURATION 0x57 +#define SDVO_CMD_GET_HUE 0x59 +#define SDVO_CMD_SET_HUE 0x5a +#define SDVO_CMD_GET_BRIGHTNESS 0x5c +#define SDVO_CMD_SET_BRIGHTNESS 0x5d +#define SDVO_CMD_GET_CONTRAST 0x5f +#define SDVO_CMD_SET_CONTRAST 0x60 +#define SDVO_CMD_GET_OVERSCAN_H 0x62 +#define SDVO_CMD_SET_OVERSCAN_H 0x63 +#define SDVO_CMD_GET_OVERSCAN_V 0x65 +#define SDVO_CMD_SET_OVERSCAN_V 0x66 +#define SDVO_CMD_GET_POSITION_H 0x68 +#define SDVO_CMD_SET_POSITION_H 0x69 +#define SDVO_CMD_GET_POSITION_V 0x6b +#define SDVO_CMD_SET_POSITION_V 0x6c +#define SDVO_CMD_GET_SHARPNESS 0x6e +#define SDVO_CMD_SET_SHARPNESS 0x6f +#define SDVO_CMD_GET_TV_CHROMA 0x75 +#define SDVO_CMD_SET_TV_CHROMA 0x76 +#define SDVO_CMD_GET_TV_LUMA 0x78 +#define SDVO_CMD_SET_TV_LUMA 0x79 +struct i830_sdvo_enhancements_arg { + uint16_t value; +}__attribute__((packed)); + +#define SDVO_CMD_GET_DOT_CRAWL 0x70 +#define SDVO_CMD_SET_DOT_CRAWL 0x71 +# define SDVO_DOT_CRAWL_ON (1 << 0) +# define SDVO_DOT_CRAWL_DEFAULT_ON (1 << 1) + +#define SDVO_CMD_GET_DITHER 0x72 +#define SDVO_CMD_SET_DITHER 0x73 +# define SDVO_DITHER_ON (1 << 0) +# define SDVO_DITHER_DEFAULT_ON (1 << 1) + #define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93 #define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a -# define SDVO_CONTROL_BUS_PROM 0x0 -# define SDVO_CONTROL_BUS_DDC1 0x1 -# define SDVO_CONTROL_BUS_DDC2 0x2 -# define SDVO_CONTROL_BUS_DDC3 0x3 +# define SDVO_CONTROL_BUS_PROM (1 << 0) +# define SDVO_CONTROL_BUS_DDC1 (1 << 1) +# define SDVO_CONTROL_BUS_DDC2 (1 << 2) +# define SDVO_CONTROL_BUS_DDC3 (1 << 3)