diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index 523eed27..ac5ae48e 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -54,8 +54,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. struct i830_sdvo_priv { /** SDVO device on SDVO I2C bus. */ I2CDevRec d; - /** Temporary storage for reg read/writes */ - unsigned char sdvo_regs[20]; /** Register for the SDVO device: SDVOB or SDVOC */ int output_device; /** @@ -69,14 +67,12 @@ struct i830_sdvo_priv { /** @{ */ int save_sdvo_mult; Bool save_sdvo_active_1, save_sdvo_active_2; - i830_sdvo_dtd save_input_dtd_1, save_input_dtd_2; - i830_sdvo_dtd save_output_dtd_1, save_output_dtd_2; + struct i830_sdvo_dtd save_input_dtd_1, save_input_dtd_2; + struct i830_sdvo_dtd save_output_dtd_1, save_output_dtd_2; CARD32 save_SDVOX; /** @} */ }; -CARD16 curr_table[6]; - /** Read a single byte from the given address on the SDVO device. */ static Bool i830_sdvo_read_byte(I830OutputPtr output, int addr, unsigned char *ch) @@ -153,33 +149,36 @@ const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), }; -/* following on from tracing the intel BIOS i2c routines */ +/** + * Writes out the data given in args (up to 8 bytes), followed by the opcode. + */ static void -i830_sdvo_write_outputs(I830OutputPtr output, int num_out) +i830_sdvo_write_cmd(I830OutputPtr output, CARD8 cmd, void *args, int args_len) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; int i; - ErrorF("SDVO: W: %02X ", dev_priv->sdvo_regs[SDVO_I2C_OPCODE]); - for (i = SDVO_I2C_ARG_0; i > SDVO_I2C_ARG_0 - num_out; i--) - ErrorF("%02X ", dev_priv->sdvo_regs[i]); - for (; i > SDVO_I2C_ARG_7; i--) - ErrorF(" "); + /* Write the SDVO command logging */ + xf86DrvMsg(output->pI2CBus->scrnIndex, X_INFO, "SDVO: W: %02X ", cmd); + for (i = 0; i < args_len; i++) + LogWrite(1, "%02X ", ((CARD8 *)args)[i]); + for (; i < 8; i++) + LogWrite(1, " "); for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { - if (dev_priv->sdvo_regs[SDVO_I2C_OPCODE] == sdvo_cmd_names[i].cmd) { - ErrorF("(%s)", sdvo_cmd_names[i].name); + if (cmd == sdvo_cmd_names[i].cmd) { + LogWrite(1, "(%s)", sdvo_cmd_names[i].name); break; } } - ErrorF("\n"); + if (i == sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0])) + LogWrite(1, "(%02X)", cmd); + LogWrite(1, "\n"); - /* blast the output regs */ - for (i = SDVO_I2C_ARG_0; i > SDVO_I2C_ARG_0 - num_out; i--) { - i830_sdvo_write_byte(output, i, dev_priv->sdvo_regs[i]); + /* send the output regs */ + for (i = 0; i < args_len; i++) { + i830_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((CARD8 *)args)[i]); } /* blast the command reg */ - i830_sdvo_write_byte(output, SDVO_I2C_OPCODE, - dev_priv->sdvo_regs[SDVO_I2C_OPCODE]); + i830_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd); } static const char *cmd_status_names[] = { @@ -192,45 +191,40 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; -static void -i830_sdvo_read_input_regs(I830OutputPtr output) +/** + * Reads back response_len bytes from the SDVO device, and returns the status. + */ +static CARD8 +i830_sdvo_read_response(I830OutputPtr output, void *response, int response_len) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; int i; + CARD8 status; - /* follow BIOS ordering */ - i830_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, - &dev_priv->sdvo_regs[SDVO_I2C_CMD_STATUS]); - - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_3, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_3]); - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_2, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_2]); - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_1, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_1]); - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_0, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_0]); - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_7, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_7]); - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_6, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_6]); - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_5, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_5]); - i830_sdvo_read_byte(output, SDVO_I2C_RETURN_4, - &dev_priv->sdvo_regs[SDVO_I2C_RETURN_4]); - - ErrorF("SDVO: R: "); - for (i = SDVO_I2C_RETURN_0; i <= SDVO_I2C_RETURN_7; i++) - ErrorF("%02X ", dev_priv->sdvo_regs[i]); - if (dev_priv->sdvo_regs[SDVO_I2C_CMD_STATUS] <= - SDVO_CMD_STATUS_SCALING_NOT_SUPP) - { - ErrorF("(%s)", - cmd_status_names[dev_priv->sdvo_regs[SDVO_I2C_CMD_STATUS]]); - } else { - ErrorF("(??? %d)", dev_priv->sdvo_regs[SDVO_I2C_CMD_STATUS]); + /* Read the command response */ + for (i = 0; i < response_len; i++) { + i830_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, + &((CARD8 *)response)[i]); } - ErrorF("\n"); + + /* Read the return status */ + i830_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + + /* Write the SDVO command logging */ + xf86DrvMsg(output->pI2CBus->scrnIndex, X_INFO, + "SDVO: R: "); + for (i = 0; i < response_len; i++) + LogWrite(1, "%02X ", ((CARD8 *)response)[i]); + for (; i < 8; i++) + LogWrite(1, " "); + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) + { + LogWrite(1, "(%s)", cmd_status_names[status]); + } else { + LogWrite(1, "(??? %d)", status); + } + LogWrite(1, "\n"); + + return status; } int @@ -248,49 +242,47 @@ i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode) * PROM. It resets from the DDC bus back to internal registers at the next I2C * STOP. PROM access is terminated by accessing an internal register. */ -static Bool +static void i830_sdvo_set_control_bus_switch(I830OutputPtr output, CARD8 target) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; - - memset(dev_priv->sdvo_regs, 0, 9); - - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_CONTROL_BUS_SWITCH; - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = target; - - i830_sdvo_write_outputs(output, 1); - return TRUE; + i830_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); } static Bool i830_sdvo_set_target_input(I830OutputPtr output, Bool target_1, Bool target_2) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 targets[2]; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); + targets[0] = target_1; + targets[1] = target_2; + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, 2); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_TARGET_INPUT; - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = target_1; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = target_2; + status = i830_sdvo_read_response(output, NULL, 0); - i830_sdvo_write_outputs(output, 2); - - i830_sdvo_read_input_regs(output); - - return TRUE; + return (status == SDVO_CMD_STATUS_SUCCESS); } +/** + * Return whether each input is trained. + * + * This function is making an assumption about the layout of the response, + * which should be checked against the docs. + */ static Bool -i830_sdvo_get_trained_inputs(I830OutputPtr output) +i830_sdvo_get_trained_inputs(I830OutputPtr output, Bool *input_1, Bool *input_2) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 response[2]; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_TRAINED_INPUTS; + i830_sdvo_read_response(output, response, 2); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + *input_1 = response[0]; + *input_2 = response[1]; return TRUE; } @@ -298,56 +290,50 @@ i830_sdvo_get_trained_inputs(I830OutputPtr output) static Bool i830_sdvo_get_active_outputs(I830OutputPtr output, Bool *on_1, Bool *on_2) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 response[2]; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_ACTIVE_OUTPUTS; + status = i830_sdvo_read_response(output, &response, 2); - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + *on_1 = response[0]; + *on_2 = response[1]; - *on_1 = dev_priv->sdvo_regs[SDVO_I2C_RETURN_0]; - *on_2 = dev_priv->sdvo_regs[SDVO_I2C_RETURN_1]; - - return TRUE; + return (status == SDVO_CMD_STATUS_SUCCESS); } static Bool i830_sdvo_set_active_outputs(I830OutputPtr output, Bool on_1, Bool on_2) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 outputs[2]; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); + outputs[0] = on_1; + outputs[1] = on_2; + i830_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, 2); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_ACTIVE_OUTPUTS; - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = on_1; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = on_2; + status = i830_sdvo_read_response(output, NULL, 0); - i830_sdvo_write_outputs(output, 2); - i830_sdvo_read_input_regs(output); - - return TRUE; + return (status == SDVO_CMD_STATUS_SUCCESS); } static Bool i830_sdvo_get_input_pixel_clock_range(I830OutputPtr output, CARD16 *clock_min, CARD16 *clock_max) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + struct i830_sdvo_pixel_clock_range clocks; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, NULL, 0); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = - SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE; + status = i830_sdvo_read_response(output, &clocks, sizeof(clocks)); - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; - *clock_min = dev_priv->sdvo_regs[SDVO_I2C_RETURN_0] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_1] << 8); - *clock_max = dev_priv->sdvo_regs[SDVO_I2C_RETURN_2] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_3] << 8); + *clock_min = clocks.min; + *clock_max = clocks.max; return TRUE; } @@ -355,282 +341,164 @@ 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) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 targets[2]; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); + targets[0] = target_1; + targets[1] = target_2; + i830_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &targets, 2); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_TARGET_OUTPUT; - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = target_1; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = target_2; + status = i830_sdvo_read_response(output, NULL, 0); - i830_sdvo_write_outputs(output, 2); - i830_sdvo_read_input_regs(output); - - return TRUE; + return (status == SDVO_CMD_STATUS_SUCCESS); } -/* Fetches either input or output timings to *dtd, depending on cmd. */ +/** Fetches either input or output timings to *dtd, depending on cmd. */ static Bool -i830_sdvo_get_timings(I830OutputPtr output, i830_sdvo_dtd *dtd, CARD8 cmd) +i830_sdvo_get_timing(I830OutputPtr output, CARD8 cmd, struct i830_sdvo_dtd *dtd) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = cmd; - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, cmd, NULL, 0); - dtd->clock = dev_priv->sdvo_regs[SDVO_I2C_RETURN_0] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_1] << 8); - dtd->h_active = dev_priv->sdvo_regs[SDVO_I2C_RETURN_2]; - dtd->h_blank = dev_priv->sdvo_regs[SDVO_I2C_RETURN_3]; - dtd->h_high = dev_priv->sdvo_regs[SDVO_I2C_RETURN_4]; - dtd->v_active = dev_priv->sdvo_regs[SDVO_I2C_RETURN_5]; - dtd->v_blank = dev_priv->sdvo_regs[SDVO_I2C_RETURN_6]; - dtd->v_high = dev_priv->sdvo_regs[SDVO_I2C_RETURN_7]; + status = i830_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; - memset(dev_priv->sdvo_regs, 0, 9); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = cmd + 1; - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, cmd + 1, NULL, 0); - dtd->h_sync_off = dev_priv->sdvo_regs[SDVO_I2C_RETURN_0]; - dtd->h_sync_width = dev_priv->sdvo_regs[SDVO_I2C_RETURN_1]; - dtd->v_sync_off_width = dev_priv->sdvo_regs[SDVO_I2C_RETURN_2]; - dtd->sync_off_width_high = dev_priv->sdvo_regs[SDVO_I2C_RETURN_3]; - dtd->dtd_flags = dev_priv->sdvo_regs[SDVO_I2C_RETURN_4]; - dtd->sdvo_flags = dev_priv->sdvo_regs[SDVO_I2C_RETURN_5]; - dtd->v_sync_off_high = dev_priv->sdvo_regs[SDVO_I2C_RETURN_6]; - dtd->reserved = dev_priv->sdvo_regs[SDVO_I2C_RETURN_7]; - - return TRUE; -} - -/* Sets either input or output timings to *dtd, depending on cmd. */ -static Bool -i830_sdvo_set_timings(I830OutputPtr output, i830_sdvo_dtd *dtd, CARD8 cmd) -{ - struct i830_sdvo_priv *dev_priv = output->dev_priv; - - memset(dev_priv->sdvo_regs, 0, 9); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = cmd; - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = dtd->clock & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = dtd->clock >> 8; - dev_priv->sdvo_regs[SDVO_I2C_ARG_2] = dtd->h_active; - dev_priv->sdvo_regs[SDVO_I2C_ARG_3] = dtd->h_blank; - dev_priv->sdvo_regs[SDVO_I2C_ARG_4] = dtd->h_high; - dev_priv->sdvo_regs[SDVO_I2C_ARG_5] = dtd->v_active; - dev_priv->sdvo_regs[SDVO_I2C_ARG_6] = dtd->v_blank; - dev_priv->sdvo_regs[SDVO_I2C_ARG_7] = dtd->v_high; - i830_sdvo_write_outputs(output, 8); - i830_sdvo_read_input_regs(output); - - memset(dev_priv->sdvo_regs, 0, 9); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = cmd + 1; - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = dtd->h_sync_off; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = dtd->h_sync_width; - dev_priv->sdvo_regs[SDVO_I2C_ARG_2] = dtd->v_sync_off_width; - dev_priv->sdvo_regs[SDVO_I2C_ARG_3] = dtd->sync_off_width_high; - dev_priv->sdvo_regs[SDVO_I2C_ARG_4] = dtd->dtd_flags; - dev_priv->sdvo_regs[SDVO_I2C_ARG_5] = dtd->sdvo_flags; - dev_priv->sdvo_regs[SDVO_I2C_ARG_6] = dtd->v_sync_off_high; - dev_priv->sdvo_regs[SDVO_I2C_ARG_7] = dtd->reserved; - i830_sdvo_write_outputs(output, 7); - i830_sdvo_read_input_regs(output); + status = i830_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; return TRUE; } static Bool -i830_sdvo_set_timings_part1(I830OutputPtr output, char cmd, CARD16 clock, - CARD16 magic1, CARD16 magic2, CARD16 magic3) +i830_sdvo_get_input_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + return i830_sdvo_get_timing(output, SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); +} - memset(dev_priv->sdvo_regs, 0, 9); +static Bool +i830_sdvo_get_output_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) +{ + return i830_sdvo_get_timing(output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); +} - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = cmd; +/** Sets either input or output timings from *dtd, depending on cmd. */ +static Bool +i830_sdvo_set_timing(I830OutputPtr output, CARD8 cmd, struct i830_sdvo_dtd *dtd) +{ + CARD8 status; - /* set clock regs */ - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = clock & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = (clock >> 8) & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_2] = magic3 & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_3] = (magic3 >> 8) & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_4] = magic2 & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_5] = (magic2 >> 8) & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_6] = magic1 & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_7] = (magic1 >> 8) & 0xff; + i830_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; - i830_sdvo_write_outputs(output, 8); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; return TRUE; } static Bool -i830_sdvo_set_input_timings_part1(I830OutputPtr output, CARD16 clock, - CARD16 magic1, CARD16 magic2, CARD16 magic3) +i830_sdvo_set_input_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) { - return i830_sdvo_set_timings_part1(output, - SDVO_CMD_SET_INPUT_TIMINGS_PART1, - clock, magic1, magic2, magic3); + return i830_sdvo_set_timing(output, SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); } static Bool -i830_sdvo_set_output_timings_part1(I830OutputPtr output, CARD16 clock, - CARD16 magic1, CARD16 magic2, CARD16 magic3) +i830_sdvo_set_output_timing(I830OutputPtr output, struct i830_sdvo_dtd *dtd) { - return i830_sdvo_set_timings_part1(output, - SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, - clock, magic1, magic2, magic3); -} - -static Bool -i830_sdvo_set_timings_part2(I830OutputPtr output, CARD8 cmd, - CARD16 magic4, CARD16 magic5, CARD16 magic6) -{ - struct i830_sdvo_priv *dev_priv = output->dev_priv; - - memset(dev_priv->sdvo_regs, 0, 9); - - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = cmd; - - /* set clock regs */ - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = magic4 & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = (magic4 >> 8) & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_2] = magic5 & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_3] = (magic5 >> 8) & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_4] = magic6 & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_5] = (magic6 >> 8) & 0xff; - - i830_sdvo_write_outputs(output, 8); - i830_sdvo_read_input_regs(output); - - return TRUE; -} - -static Bool -i830_sdvo_set_input_timings_part2(I830OutputPtr output, - CARD16 magic4, CARD16 magic5, CARD16 magic6) -{ - return i830_sdvo_set_timings_part2(output, - SDVO_CMD_SET_INPUT_TIMINGS_PART2, - magic4, magic5, magic6); -} - -static Bool -i830_sdvo_set_output_timings_part2(I830OutputPtr output, - CARD16 magic4, CARD16 magic5, CARD16 magic6) -{ - return i830_sdvo_set_timings_part2(output, - SDVO_CMD_SET_OUTPUT_TIMINGS_PART2, - magic4, magic5, magic6); + return i830_sdvo_set_timing(output, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); } +#if 0 static Bool i830_sdvo_create_preferred_input_timing(I830OutputPtr output, CARD16 clock, CARD16 width, CARD16 height) { struct i830_sdvo_priv *dev_priv = output->dev_priv; + struct i830_sdvo_preferred_input_timing_args args; - memset(dev_priv->sdvo_regs, 0, 9); - - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = - SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING; - - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = clock & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_1] = (clock >> 8) & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_2] = width & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_3] = (width >> 8) & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_4] = height & 0xff; - dev_priv->sdvo_regs[SDVO_I2C_ARG_5] = (height >> 8) & 0xff; - - i830_sdvo_write_outputs(output, 7); - i830_sdvo_read_input_regs(output); + args.clock = clock; + args.width = width; + args.height = height; + i830_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, + &args, sizeof(args)); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; return TRUE; } static Bool -i830_sdvo_get_preferred_input_timing_part1(I830OutputPtr output) +i830_sdvo_get_preferred_input_timing(I830OutputPtr output, + struct i830_sdvo_dtd *dtd) { struct i830_sdvo_priv *dev_priv = output->dev_priv; - memset(dev_priv->sdvo_regs, 0, 9); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + NULL, 0); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = - SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1; + status = i830_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + NULL, 0); - curr_table[0] = dev_priv->sdvo_regs[SDVO_I2C_RETURN_6] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_7] << 8); - curr_table[1] = dev_priv->sdvo_regs[SDVO_I2C_RETURN_4] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_5] << 8); - curr_table[2] = dev_priv->sdvo_regs[SDVO_I2C_RETURN_2] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_3] << 8); - - return TRUE; -} - -static Bool -i830_sdvo_get_preferred_input_timing_part2(I830OutputPtr output) -{ - struct i830_sdvo_priv *dev_priv = output->dev_priv; - - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = - SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2; - - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); - - curr_table[3] = dev_priv->sdvo_regs[SDVO_I2C_RETURN_0] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_1] << 8); - curr_table[4] = dev_priv->sdvo_regs[SDVO_I2C_RETURN_2] | - (dev_priv->sdvo_regs[SDVO_I2C_RETURN_3] << 8); - curr_table[5] = 0x1e; + status = i830_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; return TRUE; } +#endif +/** Returns the SDVO_CLOCK_RATE_MULT_* for the current clock multiplier */ static int i830_sdvo_get_clock_rate_mult(I830OutputPtr output) { struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 response; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); + status = i830_sdvo_read_response(output, &response, 1); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_CLOCK_RATE_MULT; - - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); - - if (dev_priv->sdvo_regs[SDVO_I2C_CMD_STATUS] != SDVO_CMD_STATUS_SUCCESS) { + if (status != SDVO_CMD_STATUS_SUCCESS) { xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_ERROR, "Couldn't get SDVO clock rate multiplier\n"); return SDVO_CLOCK_RATE_MULT_1X; } else { xf86DrvMsg(dev_priv->d.pI2CBus->scrnIndex, X_INFO, - "Current clock rate multiplier: %d\n", - dev_priv->sdvo_regs[SDVO_I2C_RETURN_0]); + "Current clock rate multiplier: %d\n", response); } - return dev_priv->sdvo_regs[SDVO_I2C_RETURN_0]; + return response; } +/** + * Sets the current clock multiplier. + * + * This has to match with the settings in the DPLL/SDVO reg when the output + * is actually turned on. + */ static Bool i830_sdvo_set_clock_rate_mult(I830OutputPtr output, CARD8 val) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); - - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_SET_CLOCK_RATE_MULT; - - dev_priv->sdvo_regs[SDVO_I2C_ARG_0] = val; - i830_sdvo_write_outputs(output, 1); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; return TRUE; } @@ -640,15 +508,11 @@ i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, DisplayModePtr mode) { I830Ptr pI830 = I830PTR(pScrn); - CARD16 clock = mode->Clock/10, width = mode->CrtcHDisplay; + 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; - CARD16 sync_flags; - CARD8 c16a[8]; - CARD8 c17a[8]; - CARD16 out_timings[6]; - Bool out1, out2; + struct i830_sdvo_dtd output_dtd; /* do some mode translations */ h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart; @@ -660,62 +524,57 @@ i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, h_sync_offset = mode->CrtcHSyncStart - mode->CrtcHBlankStart; v_sync_offset = mode->CrtcVSyncStart - mode->CrtcVBlankStart; - sync_flags = 0x18; + output_dtd.part1.clock = mode->Clock / 10; + output_dtd.part1.h_active = width & 0xff; + output_dtd.part1.h_blank = h_blank_len & 0xff; + output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | + ((h_blank_len >> 8) & 0xf); + output_dtd.part1.v_active = height & 0xff; + output_dtd.part1.v_blank = v_blank_len & 0xff; + output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | + ((v_blank_len >> 8) & 0xf); + + output_dtd.part2.h_sync_off = h_sync_offset; + output_dtd.part2.h_sync_width = h_sync_len & 0xff; + output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | + (v_sync_len & 0xf); + output_dtd.part2.sync_off_width_high = 0; + output_dtd.part2.dtd_flags = 0x18; + output_dtd.part2.sdvo_flags = 0; + output_dtd.part2.v_sync_off_width = 0; + output_dtd.part2.reserved = 0; if (mode->Flags & V_PHSYNC) - sync_flags |= 0x2; + output_dtd.part2.dtd_flags |= 0x2; if (mode->Flags & V_PVSYNC) - sync_flags |= 0x4; - /* high bits of 0 */ - c16a[7] = clock & 0xff; - c16a[6] = (clock >> 8) & 0xff; - c16a[5] = (width & 0xff); - c16a[4] = (h_blank_len & 0xff); - c16a[3] = (((width >> 8) & 0xf) << 4) | ((h_blank_len >> 8) & 0xf); - c16a[2] = (height & 0xff); - c16a[1] = (v_blank_len & 0xff); - c16a[0] = (((height >> 8) & 0xf) << 4) | ((v_blank_len >> 8) & 0xf); - - c17a[7] = h_sync_offset; - c17a[6] = h_sync_len & 0xff; - c17a[5] = (v_sync_offset & 0xf) << 4 | (v_sync_len & 0xf); - c17a[4] = 0; - c17a[3] = sync_flags; - c17a[2] = 0; - out_timings[0] = c16a[1] | ((short)c16a[0] << 8); - out_timings[1] = c16a[3] | ((short)c16a[2] << 8); - out_timings[2] = c16a[5] | ((short)c16a[4] << 8); - out_timings[3] = c17a[7] | ((short)c17a[6] << 8); - out_timings[4] = c17a[5] | ((short)c17a[4] << 8); - out_timings[5] = c17a[3] | ((short)c17a[2] << 8); - - i830_sdvo_set_target_input(output, FALSE, FALSE); - - i830_sdvo_get_active_outputs(output, &out1, &out2); + output_dtd.part2.dtd_flags |= 0x4; + /* Turn off the screens before adjusting timings */ i830_sdvo_set_active_outputs(output, FALSE, FALSE); + /* Set the output timing to the screen */ i830_sdvo_set_target_output(output, TRUE, FALSE); - i830_sdvo_set_output_timings_part1(output, clock, - out_timings[0], out_timings[1], - out_timings[2]); - i830_sdvo_set_output_timings_part2(output, out_timings[3], out_timings[4], - out_timings[5]); + i830_sdvo_set_output_timing(output, &output_dtd); - i830_sdvo_set_target_input(output, FALSE, FALSE); + /* Set the input timing to the screen */ + i830_sdvo_set_target_input(output, TRUE, FALSE); - i830_sdvo_create_preferred_input_timing(output, clock, width, height); - i830_sdvo_get_preferred_input_timing_part1(output); - i830_sdvo_get_preferred_input_timing_part2(output); + /* We would like to use i830_sdvo_create_preferred_input_timing() to + * provide the device with a timing it can support, if it supports that + * feature. However, presumably we would need to adjust the CRTC to output + * the preferred timing, and we don't support that currently. + */ +#if 0 + success = i830_sdvo_create_preferred_input_timing(output, clock, + width, height); + if (success) { + struct i830_sdvo_dtd *input_dtd; - i830_sdvo_set_target_input(output, FALSE, FALSE); - - i830_sdvo_set_input_timings_part1(output, clock, - curr_table[0], curr_table[1], - curr_table[2]); - i830_sdvo_set_input_timings_part2(output, curr_table[3], curr_table[4], - out_timings[5]); - - i830_sdvo_set_target_input(output, FALSE, FALSE); + i830_sdvo_get_preferred_input_timing(output, &input_dtd); + i830_sdvo_set_input_timing(output, &input_dtd); + } +#else + i830_sdvo_set_input_timing(output, &output_dtd); +#endif switch (i830_sdvo_get_pixel_multiplier(mode)) { case 1: @@ -738,26 +597,22 @@ i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output, DisplayModePtr mode) { I830Ptr pI830 = I830PTR(pScrn); - struct i830_sdvo_priv *dev_priv = output->dev_priv; - Bool ret = TRUE; - Bool out1, out2; + Bool out1, out2, input1, input2; CARD32 dpll, sdvob, sdvoc; int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B; int sdvo_pixel_multiply; + 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 */ - i830_sdvo_get_trained_inputs(output); + i830_sdvo_get_trained_inputs(output, &input1, &input2); - /* THIS IS A DIRTY HACK - sometimes for some reason on startup - * the BIOS doesn't find my DVI monitor - - * without this hack the driver doesn't work.. this causes the modesetting - * to be re-run - */ - if (dev_priv->sdvo_regs[SDVO_I2C_RETURN_0] != 0x1) { - ret = FALSE; + /* 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); @@ -810,28 +665,24 @@ i830_sdvo_save(ScrnInfoPtr pScrn, I830OutputPtr output) i830_sdvo_get_active_outputs(output, &dev_priv->save_sdvo_active_1, &dev_priv->save_sdvo_active_2); - if (dev_priv->caps.caps & 0x1) { + if (dev_priv->caps.sdvo_inputs_mask & 0x1) { i830_sdvo_set_target_input(output, FALSE, FALSE); - i830_sdvo_get_timings(output, &dev_priv->save_input_dtd_1, - SDVO_CMD_GET_INPUT_TIMINGS_PART1); + i830_sdvo_get_input_timing(output, &dev_priv->save_input_dtd_1); } - if (dev_priv->caps.caps & 0x2) { + if (dev_priv->caps.sdvo_inputs_mask & 0x2) { i830_sdvo_set_target_input(output, FALSE, TRUE); - i830_sdvo_get_timings(output, &dev_priv->save_input_dtd_2, - SDVO_CMD_GET_INPUT_TIMINGS_PART1); + 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_timings(output, &dev_priv->save_output_dtd_1, - SDVO_CMD_GET_OUTPUT_TIMINGS_PART1); + 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_timings(output, &dev_priv->save_output_dtd_2, - SDVO_CMD_GET_OUTPUT_TIMINGS_PART1); + i830_sdvo_get_output_timing(output, &dev_priv->save_output_dtd_2); } dev_priv->save_SDVOX = INREG(dev_priv->output_device); @@ -843,28 +694,24 @@ i830_sdvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output) I830Ptr pI830 = I830PTR(pScrn); struct i830_sdvo_priv *dev_priv = output->dev_priv; - if (dev_priv->caps.caps & 0x1) { + if (dev_priv->caps.sdvo_inputs_mask & 0x1) { i830_sdvo_set_target_input(output, FALSE, FALSE); - i830_sdvo_set_timings(output, &dev_priv->save_input_dtd_1, - SDVO_CMD_SET_INPUT_TIMINGS_PART1); + i830_sdvo_set_input_timing(output, &dev_priv->save_input_dtd_1); } - if (dev_priv->caps.caps & 0x2) { + if (dev_priv->caps.sdvo_inputs_mask & 0x2) { i830_sdvo_set_target_input(output, FALSE, TRUE); - i830_sdvo_set_timings(output, &dev_priv->save_input_dtd_2, - SDVO_CMD_SET_INPUT_TIMINGS_PART1); + 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_timings(output, &dev_priv->save_output_dtd_1, - SDVO_CMD_SET_OUTPUT_TIMINGS_PART1); + 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_timings(output, &dev_priv->save_output_dtd_2, - SDVO_CMD_SET_OUTPUT_TIMINGS_PART1); + i830_sdvo_set_output_timing(output, &dev_priv->save_output_dtd_2); } i830_sdvo_set_clock_rate_mult(output, dev_priv->save_sdvo_mult); @@ -890,24 +737,17 @@ i830_sdvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output, return MODE_OK; } -static void +static Bool i830_sdvo_get_capabilities(I830OutputPtr output, i830_sdvo_caps *caps) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 status; - memset(dev_priv->sdvo_regs, 0, 9); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_DEVICE_CAPS; - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); + status = i830_sdvo_read_response(output, caps, sizeof(*caps)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; - caps->vendor_id = dev_priv->sdvo_regs[SDVO_I2C_RETURN_0]; - caps->device_id = dev_priv->sdvo_regs[SDVO_I2C_RETURN_1]; - caps->device_rev_id = dev_priv->sdvo_regs[SDVO_I2C_RETURN_2]; - caps->sdvo_version_major = dev_priv->sdvo_regs[SDVO_I2C_RETURN_3]; - caps->sdvo_version_minor = dev_priv->sdvo_regs[SDVO_I2C_RETURN_4]; - caps->caps = dev_priv->sdvo_regs[SDVO_I2C_RETURN_5]; - caps->output_0_supported = dev_priv->sdvo_regs[SDVO_I2C_RETURN_6]; - caps->output_1_supported = dev_priv->sdvo_regs[SDVO_I2C_RETURN_7]; + return TRUE; } /** Forces the device over to the real I2C bus and uses its GetByte */ @@ -1001,12 +841,10 @@ i830_sdvo_ddc_i2c_address(I2CDevPtr d, I2CSlaveAddr addr) static void i830_sdvo_dump_cmd(I830OutputPtr output, int opcode) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 response[8]; - memset(dev_priv->sdvo_regs, 0, sizeof(dev_priv->sdvo_regs)); - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = opcode; - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, opcode, NULL, 0); + i830_sdvo_read_response(output, response, 8); } static void @@ -1062,17 +900,16 @@ i830_sdvo_dump(ScrnInfoPtr pScrn) Bool i830_sdvo_detect_displays(ScrnInfoPtr pScrn, I830OutputPtr output) { - struct i830_sdvo_priv *dev_priv = output->dev_priv; + CARD8 response[2]; + CARD8 status; - dev_priv->sdvo_regs[SDVO_I2C_OPCODE] = SDVO_CMD_GET_ATTACHED_DISPLAYS; - i830_sdvo_write_outputs(output, 0); - i830_sdvo_read_input_regs(output); + i830_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + status = i830_sdvo_read_response(output, &response, 2); - if (dev_priv->sdvo_regs[SDVO_I2C_CMD_STATUS] != SDVO_CMD_STATUS_SUCCESS) + if (status != SDVO_CMD_STATUS_SUCCESS) return FALSE; - return (dev_priv->sdvo_regs[SDVO_I2C_RETURN_0] != 0 || - dev_priv->sdvo_regs[SDVO_I2C_RETURN_1] != 0); + return (response[0] != 0 || response[1] != 0); } void @@ -1182,10 +1019,13 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) &dev_priv->pixel_clock_max); xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "SDVO device VID/DID: %02X:%02X.%02X, %02X," + "SDVO device VID/DID: %02X:%02X.%02X, " + "input 1: %c, input 2: %c, " "output 1: %c, output 2: %c\n", dev_priv->caps.vendor_id, dev_priv->caps.device_id, - dev_priv->caps.device_rev_id, dev_priv->caps.caps, + 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'); diff --git a/src/i830_sdvo.h b/src/i830_sdvo.h index db7eb97f..b1d86b41 100644 --- a/src/i830_sdvo.h +++ b/src/i830_sdvo.h @@ -25,36 +25,6 @@ * */ -typedef struct _i830_sdvo_caps { - CARD8 vendor_id; - CARD8 device_id; - CARD8 device_rev_id; - CARD8 sdvo_version_major; - CARD8 sdvo_version_minor; - CARD8 caps; - CARD8 output_0_supported; - CARD8 output_1_supported; -} __attribute__((packed)) i830_sdvo_caps; - -typedef struct _i830_sdvo_dtd { - CARD16 clock; - CARD8 h_active; - CARD8 h_blank; - CARD8 h_high; - CARD8 v_active; - CARD8 v_blank; - CARD8 v_high; - - CARD8 h_sync_off; - CARD8 h_sync_width; - CARD8 v_sync_off_width; - CARD8 sync_off_width_high; - CARD8 dtd_flags; - CARD8 sdvo_flags; - CARD8 v_sync_off_high; - CARD8 reserved; -} __attribute__((packed)) i830_sdvo_dtd; - void i830_sdvo_init(ScrnInfoPtr pScrn, int output_device); diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h index a35d5a4e..be3294b4 100644 --- a/src/i830_sdvo_regs.h +++ b/src/i830_sdvo_regs.h @@ -25,6 +25,57 @@ * */ +typedef struct _i830_sdvo_caps { + CARD8 vendor_id; + CARD8 device_id; + CARD8 device_rev_id; + CARD8 sdvo_version_major; + CARD8 sdvo_version_minor; + unsigned int sdvo_inputs_mask:2; + unsigned int smooth_scaling:1; + unsigned int sharp_scaling:1; + unsigned int up_scaling:1; + 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_dtd { + struct { + CARD16 clock; + CARD8 h_active; + CARD8 h_blank; + CARD8 h_high; + CARD8 v_active; + CARD8 v_blank; + CARD8 v_high; + } part1; + + struct { + CARD8 h_sync_off; + CARD8 h_sync_width; + CARD8 v_sync_off_width; + CARD8 sync_off_width_high; + CARD8 dtd_flags; + CARD8 sdvo_flags; + CARD8 v_sync_off_high; + CARD8 reserved; + } part2; +} __attribute__((packed)); + +struct i830_sdvo_pixel_clock_range { + CARD16 min; + CARD16 max; +} __attribute__((packed)); + +struct i830_sdvo_preferred_input_timing_args { + CARD16 clock; + CARD16 width; + CARD16 height; +} __attribute__((packed)); + /* I2C registers for SDVO */ #define SDVO_I2C_ARG_0 0x07 #define SDVO_I2C_ARG_1 0x06 @@ -56,22 +107,11 @@ #define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6 /* SDVO commands, argument/result registers */ + #define SDVO_CMD_RESET 0x01 + +/** Returns a struct i830_sdvo_caps */ #define SDVO_CMD_GET_DEVICE_CAPS 0x02 -# define SDVO_DEVICE_CAPS_VENDOR_ID SDVO_I2C_RETURN_0 -# define SDVO_DEVICE_CAPS_DEVICE_ID SDVO_I2C_RETURN_1 -# define SDVO_DEVICE_CAPS_DEVICE_REV_ID SDVO_I2C_RETURN_2 -# define SDVO_DEVICE_CAPS_SDVOVERSION_MINOR SDVO_I2C_RETURN_3 -# define SDVO_DEVICE_CAPS_SDVOVERSION_MAJOR SDVO_I2C_RETURN_4 -# define SDVO_DEVICE_CAPS_CAPS SDVO_I2C_RETURN_5 -# define SDVO_DEVICE_CAPS_INPUTS_MASK (3 << 0) -# define SDVO_DEVICE_CAPS_SMOOTH_SCALING (1 << 2) -# define SDVO_DEVICE_CAPS_SHARP_SCALING (1 << 3) -# define SDVO_DEVICE_CAPS_UP_SCALING (1 << 4) -# define SDVO_DEVICE_CAPS_DOWN_SCALING (1 << 5) -# define SDVO_DEVICE_CAPS_STALL_SUPPORT (1 << 6) -# define SDVO_DEVICE_CAPS_OUTPUT_0_SUPPORTED SDVO_I2C_RETURN_6 -# define SDVO_DEVICE_CAPS_OUTPUT_1_SUPPORTED SDVO_I2C_RETURN_7 #define SDVO_CMD_GET_FIRMWARE_REV 0x86 # define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0 @@ -148,7 +188,9 @@ #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c +/** Returns a struct i830_sdvo_pixel_clock_range */ #define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d +/** Returns a struct i830_sdvo_pixel_clock_range */ #define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e #define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f