From 49bbdf16c02107c08169f8d2b6e9c6dbd7d8cd95 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 31 Oct 2006 10:44:45 -0800 Subject: Fix many inconsistencies in the SDVO code compared to the spec. Also, fix some struct padding so that the right bits are sent out. --- src/i830_sdvo.c | 169 ++++++++++++++++++++++++++------------------------- src/i830_sdvo_regs.h | 109 +++++++++++++++++++++++++++++---- 2 files changed, 185 insertions(+), 93 deletions(-) diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index bbc1c725..d3f509e5 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -54,21 +54,27 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. struct i830_sdvo_priv { /** SDVO device on SDVO I2C bus. */ I2CDevRec d; + /** Register for the SDVO device: SDVOB or SDVOC */ int output_device; + + /** Active outputs controlled by this SDVO output */ + struct i830_sdvo_output_flags active_outputs; + /** * Capabilities of the SDVO device returned by i830_sdvo_get_capabilities() */ - i830_sdvo_caps caps; + struct i830_sdvo_caps caps; + /** Pixel clock limitations reported by the SDVO device */ CARD16 pixel_clock_min, pixel_clock_max; /** State for save/restore */ /** @{ */ int save_sdvo_mult; - Bool save_sdvo_active_1, save_sdvo_active_2; + struct i830_sdvo_output_flags save_active_outputs; struct i830_sdvo_dtd save_input_dtd_1, save_input_dtd_2; - struct i830_sdvo_dtd save_output_dtd_1, save_output_dtd_2; + struct i830_sdvo_dtd save_output_dtd; CARD32 save_SDVOX; /** @} */ }; @@ -122,7 +128,7 @@ const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTR_EVENT_SOURCE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), @@ -187,7 +193,7 @@ static const char *cmd_status_names[] = { "Not supported", "Invalid arg", "Pending", - "Target not supported", + "Target not specified", "Scaling not supported" }; @@ -249,14 +255,19 @@ i830_sdvo_set_control_bus_switch(I830OutputPtr output, CARD8 target) } static Bool -i830_sdvo_set_target_input(I830OutputPtr output, Bool target_1, Bool target_2) +i830_sdvo_set_target_input(I830OutputPtr output, Bool target_0, Bool target_1) { - CARD8 targets[2]; + struct i830_sdvo_set_target_input_args targets = {0}; CARD8 status; - targets[0] = target_1; - targets[1] = target_2; - i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, 2); + if (target_0 && target_1) + return SDVO_CMD_STATUS_NOTSUPP; + + if (target_1) + targets.target_1 = 1; + + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, + sizeof(targets)); status = i830_sdvo_read_response(output, NULL, 0); @@ -272,47 +283,41 @@ i830_sdvo_set_target_input(I830OutputPtr output, Bool target_1, Bool target_2) static Bool i830_sdvo_get_trained_inputs(I830OutputPtr output, Bool *input_1, Bool *input_2) { - CARD8 response[2]; + struct i830_sdvo_get_trained_inputs_response response; CARD8 status; i830_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); - status = i830_sdvo_read_response(output, response, 2); + status = i830_sdvo_read_response(output, &response, sizeof(response)); if (status != SDVO_CMD_STATUS_SUCCESS) return FALSE; - *input_1 = response[0]; - *input_2 = response[1]; + *input_1 = response.input0_trained; + *input_2 = response.input1_trained; return TRUE; } static Bool -i830_sdvo_get_active_outputs(I830OutputPtr output, Bool *on_1, Bool *on_2) +i830_sdvo_get_active_outputs(I830OutputPtr output, + struct i830_sdvo_output_flags *outputs) { - CARD8 response[2]; CARD8 status; i830_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); - - status = i830_sdvo_read_response(output, &response, 2); - - *on_1 = response[0]; - *on_2 = response[1]; + status = i830_sdvo_read_response(output, outputs, sizeof(*outputs)); return (status == SDVO_CMD_STATUS_SUCCESS); } static Bool -i830_sdvo_set_active_outputs(I830OutputPtr output, Bool on_1, Bool on_2) +i830_sdvo_set_active_outputs(I830OutputPtr output, + struct i830_sdvo_output_flags *outputs) { - CARD8 outputs[2]; CARD8 status; - outputs[0] = on_1; - outputs[1] = on_2; - i830_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, 2); - + i830_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, outputs, + sizeof(*outputs)); status = i830_sdvo_read_response(output, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); @@ -339,14 +344,13 @@ i830_sdvo_get_input_pixel_clock_range(I830OutputPtr output, CARD16 *clock_min, } static Bool -i830_sdvo_set_target_output(I830OutputPtr output, Bool target_1, Bool target_2) +i830_sdvo_set_target_output(I830OutputPtr output, + struct i830_sdvo_output_flags *outputs) { - CARD8 targets[2]; CARD8 status; - targets[0] = target_1; - targets[1] = target_2; - i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &targets, 2); + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, outputs, + sizeof(*outputs)); status = i830_sdvo_read_response(output, NULL, 0); @@ -508,11 +512,15 @@ i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, DisplayModePtr mode) { I830Ptr pI830 = I830PTR(pScrn); + struct i830_sdvo_priv *dev_priv = output->dev_priv; CARD16 width = mode->CrtcHDisplay; CARD16 height = mode->CrtcVDisplay; CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; CARD16 h_sync_offset, v_sync_offset; struct i830_sdvo_dtd output_dtd; + struct i830_sdvo_output_flags no_outputs; + + memset(&no_outputs, 0, sizeof(no_outputs)); /* do some mode translations */ h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart; @@ -549,13 +557,13 @@ i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, output_dtd.part2.dtd_flags |= 0x4; /* Turn off the screens before adjusting timings */ - i830_sdvo_set_active_outputs(output, FALSE, FALSE); + i830_sdvo_set_active_outputs(output, &no_outputs); /* Set the output timing to the screen */ - i830_sdvo_set_target_output(output, TRUE, FALSE); + i830_sdvo_set_target_output(output, &dev_priv->active_outputs); i830_sdvo_set_output_timing(output, &output_dtd); - /* Set the input timing to the screen */ + /* Set the input timing to the screen. Assume always input 0. */ i830_sdvo_set_target_input(output, TRUE, FALSE); /* We would like to use i830_sdvo_create_preferred_input_timing() to @@ -597,29 +605,15 @@ i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, DisplayModePtr mode) { I830Ptr pI830 = I830PTR(pScrn); - Bool out1, out2, input1, input2; + struct i830_sdvo_priv *dev_priv = output->dev_priv; + Bool input1, input2; CARD32 dpll, sdvob, sdvoc; int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B; int dpll_md_reg = (output->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; int sdvo_pixel_multiply; + int i; CARD8 status; - /* the BIOS writes out 6 commands post mode set */ - /* two 03s, 04 05, 10, 1d */ - /* these contain the height and mode clock / 10 by the looks of it */ - - status = i830_sdvo_get_trained_inputs(output, &input1, &input2); - - /* Warn if the device reported failure to sync. */ - if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "First SDVO output reported failure to sync\n"); - } - - i830_sdvo_get_active_outputs(output, &out1, &out2); - i830_sdvo_set_active_outputs(output, TRUE, FALSE); - i830_sdvo_set_target_input(output, FALSE, FALSE); - /* Set the SDVO control regs. */ sdvob = INREG(SDVOB) & SDVOB_PRESERVE_MASK; sdvoc = INREG(SDVOC) & SDVOC_PRESERVE_MASK; @@ -644,18 +638,37 @@ i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, OUTREG(SDVOB, sdvob); OUTREG(SDVOC, sdvoc); + + for (i = 0; i < 2; i++) + i830WaitForVblank(pScrn); + + status = i830_sdvo_get_trained_inputs(output, &input1, &input2); + + /* Warn if the device reported failure to sync. */ + if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "First SDVO output reported failure to sync\n"); + } + + i830_sdvo_set_active_outputs(output, &dev_priv->active_outputs); + i830_sdvo_set_target_input(output, TRUE, FALSE); } static void i830_sdvo_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode) { I830Ptr pI830 = I830PTR(pScrn); + struct i830_sdvo_priv *dev_priv = output->dev_priv; if (mode != DPMSModeOn) { - i830_sdvo_set_active_outputs(output, FALSE, FALSE); + struct i830_sdvo_output_flags no_outputs; + + memset(&no_outputs, 0, sizeof(no_outputs)); + + i830_sdvo_set_active_outputs(output, &no_outputs); OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE); } else { - i830_sdvo_set_active_outputs(output, TRUE, FALSE); + i830_sdvo_set_active_outputs(output, &dev_priv->active_outputs); OUTREG(SDVOB, INREG(SDVOB) | SDVO_ENABLE); } } @@ -666,12 +679,13 @@ i830_sdvo_save(ScrnInfoPtr pScrn, I830OutputPtr output) I830Ptr pI830 = I830PTR(pScrn); struct i830_sdvo_priv *dev_priv = output->dev_priv; + /* XXX: We should save the in/out mapping. */ + dev_priv->save_sdvo_mult = i830_sdvo_get_clock_rate_mult(output); - i830_sdvo_get_active_outputs(output, &dev_priv->save_sdvo_active_1, - &dev_priv->save_sdvo_active_2); + 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, FALSE, FALSE); + i830_sdvo_set_target_input(output, TRUE, FALSE); i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1); } @@ -680,15 +694,11 @@ i830_sdvo_save(ScrnInfoPtr pScrn, I830OutputPtr output) i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_2); } - if (dev_priv->caps.output_0_supported) { - i830_sdvo_set_target_output(output, TRUE, FALSE); - i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd_1); - } - - if (dev_priv->caps.output_1_supported) { - i830_sdvo_set_target_output(output, FALSE, TRUE); - i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd_2); - } + /* XXX: We should really iterate over the enabled outputs and save each + * one's state. + */ + i830_sdvo_set_target_output(output, &dev_priv->save_active_outputs); + i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd); dev_priv->save_SDVOX = INREG(dev_priv->output_device); } @@ -700,7 +710,7 @@ i830_sdvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output) struct i830_sdvo_priv *dev_priv = output->dev_priv; if (dev_priv->caps.sdvo_inputs_mask & 0x1) { - i830_sdvo_set_target_input(output, FALSE, FALSE); + i830_sdvo_set_target_input(output, TRUE, FALSE); i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1); } @@ -709,22 +719,14 @@ i830_sdvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output) i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_2); } - if (dev_priv->caps.output_0_supported) { - i830_sdvo_set_target_output(output, TRUE, FALSE); - i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd_1); - } - - if (dev_priv->caps.output_1_supported) { - i830_sdvo_set_target_output(output, FALSE, TRUE); - i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd_2); - } + i830_sdvo_set_target_output(output, &dev_priv->save_active_outputs); + i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd); i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult); OUTREG(dev_priv->output_device, dev_priv->save_SDVOX); - i830_sdvo_set_active_outputs(output, dev_priv->save_sdvo_active_1, - dev_priv->save_sdvo_active_2); + i830_sdvo_set_active_outputs(output, &dev_priv->save_active_outputs); } static int @@ -743,7 +745,7 @@ i830_sdvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output, } static Bool -i830_sdvo_get_capabilities(I830OutputPtr output, i830_sdvo_caps *caps) +i830_sdvo_get_capabilities(I830OutputPtr output, struct i830_sdvo_caps *caps) { CARD8 status; @@ -866,7 +868,7 @@ i830_sdvo_dump_device(I830OutputPtr output) i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS); i830_sdvo_dump_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT); i830_sdvo_dump_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG); - i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INTR_EVENT_SOURCE); + i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE); i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART1); i830_sdvo_dump_cmd(output, SDVO_CMD_GET_INPUT_TIMINGS_PART2); i830_sdvo_dump_cmd(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1); @@ -1023,6 +1025,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) i830_sdvo_get_input_pixel_clock_range(output, &dev_priv->pixel_clock_min, &dev_priv->pixel_clock_max); + memset(&dev_priv->active_outputs, 0, sizeof(dev_priv->active_outputs)); + dev_priv->active_outputs.tmds0 = 1; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SDVO device VID/DID: %02X:%02X.%02X, " "input 1: %c, input 2: %c, " @@ -1031,8 +1036,8 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) dev_priv->caps.device_rev_id, (dev_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', (dev_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', - dev_priv->caps.output_0_supported ? 'Y' : 'N', - dev_priv->caps.output_1_supported ? 'Y' : 'N'); + dev_priv->caps.output_flags.tmds0 ? 'Y' : 'N', + dev_priv->caps.output_flags.tmds1 ? 'Y' : 'N'); pI830->num_outputs++; } diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h index be3294b4..c43e17a8 100644 --- a/src/i830_sdvo_regs.h +++ b/src/i830_sdvo_regs.h @@ -25,7 +25,23 @@ * */ -typedef struct _i830_sdvo_caps { +struct i830_sdvo_output_flags { + unsigned int tmds0:1; + unsigned int rgb0:1; + unsigned int cvbs0:1; + unsigned int svid0:1; + unsigned int yprpb0:1; + unsigned int scart0:1; + unsigned int lvds0:1; + unsigned int pad0:1; + unsigned int tmds1:1; + unsigned int pad1:4; + unsigned int rgb1:1; + unsigned int lvds1:1; + unsigned int pad2:1; +} __attribute__((packed)); + +struct i830_sdvo_caps { CARD8 vendor_id; CARD8 device_id; CARD8 device_rev_id; @@ -38,13 +54,13 @@ typedef struct _i830_sdvo_caps { unsigned int down_scaling:1; unsigned int stall_support:1; unsigned int pad:1; - CARD8 output_0_supported; - CARD8 output_1_supported; -} __attribute__((packed)) i830_sdvo_caps; + struct i830_sdvo_output_flags output_flags; +} __attribute__((packed)); +/** This matches the EDID DTD structure, more or less */ struct i830_sdvo_dtd { struct { - CARD16 clock; + CARD16 clock; /**< pixel clock, in 10kHz units */ CARD8 h_active; CARD8 h_blank; CARD8 h_high; @@ -66,8 +82,8 @@ struct i830_sdvo_dtd { } __attribute__((packed)); struct i830_sdvo_pixel_clock_range { - CARD16 min; - CARD16 max; + CARD16 min; /**< pixel clock, in 10kHz units */ + CARD16 max; /**< pixel clock, in 10kHz units */ } __attribute__((packed)); struct i830_sdvo_preferred_input_timing_args { @@ -103,7 +119,7 @@ struct i830_sdvo_preferred_input_timing_args { #define SDVO_CMD_STATUS_NOTSUPP 0x2 #define SDVO_CMD_STATUS_INVALID_ARG 0x3 #define SDVO_CMD_STATUS_PENDING 0x4 -#define SDVO_CMD_STATUS_TARGET_NOT_SUPP 0x5 +#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5 #define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6 /* SDVO commands, argument/result registers */ @@ -116,29 +132,93 @@ struct i830_sdvo_preferred_input_timing_args { #define SDVO_CMD_GET_FIRMWARE_REV 0x86 # define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0 # define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1 +# define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2 +/** + * Reports which inputs are trained (managed to sync). + * + * Devices must have trained within 2 vsyncs of a mode change. + */ #define SDVO_CMD_GET_TRAINED_INPUTS 0x03 +struct i830_sdvo_get_trained_inputs_response { + unsigned int input0_trained:1; + unsigned int input1_trained:1; + unsigned int pad:6; +} __attribute__((packed)); +/** Returns a struct i830_sdvo_output_flags of active outputs. */ #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 +/** + * Sets the current set of active outputs. + * + * Takes a struct i830_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP + * on multi-output devices. + */ #define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05 +/** + * Returns the current mapping of SDVO inputs to outputs on the device. + * + * Returns two struct i830_sdvo_output_flags structures. + */ #define SDVO_CMD_GET_IN_OUT_MAP 0x06 +/** + * Sets the current mapping of SDVO inputs to outputs on the device. + * + * Takes two struct i380_sdvo_output_flags structures. + */ #define SDVO_CMD_SET_IN_OUT_MAP 0x07 +/** + * Returns a struct i830_sdvo_output_flags of attached displays. + */ #define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b +/** + * Returns a struct i830_sdvo_ouptut_flags of displays supporting hot plugging. + */ #define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c +/** + * Takes a struct i830_sdvo_output_flags. + */ #define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d +/** + * Returns a struct i830_sdvo_output_flags of displays with hot plug + * interrupts enabled. + */ #define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e -#define SDVO_CMD_GET_INTR_EVENT_SOURCE 0x0f +#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f +struct i830_sdvo_get_interrupt_event_source_response { + struct i830_sdvo_output_flags interrupt_status; + unsigned int ambient_light_interrupt:1; + unsigned int pad:7; +} __attribute__((packed)); +/** + * Selects which input is affected by future input commands. + * + * Commands affected include SET_INPUT_TIMINGS_PART[12], + * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12], + * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS. + */ #define SDVO_CMD_SET_TARGET_INPUT 0x10 +struct i830_sdvo_set_target_input_args { + unsigned int target_1:1; + unsigned int pad:7; +} __attribute__((packed)); +/** + * Takes a struct i830_sdvo_output_flags of which outputs are targetted by + * future output commands. + * + * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], + * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE. + */ #define SDVO_CMD_SET_TARGET_OUTPUT 0x11 #define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12 @@ -174,6 +254,12 @@ struct i830_sdvo_preferred_input_timing_args { # define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4) # define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6 +/** + * Generates a DTD based on the given width, height, and flags. + * + * This will be supported by any device supporting scaling or interlaced + * modes. + */ #define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0 # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1 @@ -193,15 +279,16 @@ struct i830_sdvo_preferred_input_timing_args { /** Returns a struct i830_sdvo_pixel_clock_range */ #define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e +/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */ #define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f +/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ #define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20 +/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ #define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21 # define SDVO_CLOCK_RATE_MULT_1X (1 << 0) # define SDVO_CLOCK_RATE_MULT_2X (1 << 1) -# define SDVO_CLOCK_RATE_MULT_3X (1 << 2) # define SDVO_CLOCK_RATE_MULT_4X (1 << 3) -# define SDVO_CLOCK_RATE_MULT_5X (1 << 4) #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 -- cgit v1.2.3