+/*
+ * Copyright © 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ */
+/*
+ * Copyright 2006 Dave Airlie <airlied@linux.ie>
+ * Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include "drm_crtc.h"
+#include "intel_sdvo_regs.h"
+
+#include <linux/proc_fs.h>
+#include <linux/wait.h>
+
+struct proc_dir_entry *proc_sdvo_dir = NULL;
+wait_queue_head_t hotplug_queue;
+
+#define MAX_VAL 1000
+#define DPLL_CLOCK_PHASE_9 (1<<9 | 1<<12)
+
+#define PCI_PORT5_REG80_FFUSE 0xD0058000
+#define PCI_PORT5_REG80_SDVO_DISABLE 0x0020
+
+#define SII_1392_WA
+#ifdef SII_1392_WA
+int SII_1392=0;
+extern int drm_psb_no_fb;
+#endif
+
+typedef struct _EXTVDATA
+{
+ u32 Value;
+ u32 Default;
+ u32 Min;
+ u32 Max;
+ u32 Step; // arbitrary unit (e.g. pixel, percent) returned during VP_COMMAND_GET
+} EXTVDATA, *PEXTVDATA;
+
+typedef struct _sdvo_display_params
+{
+ EXTVDATA FlickerFilter; /* Flicker Filter : for TV onl */
+ EXTVDATA AdaptiveFF; /* Adaptive Flicker Filter : for TV onl */
+ EXTVDATA TwoD_FlickerFilter; /* 2D Flicker Filter : for TV onl */
+ EXTVDATA Brightness; /* Brightness : for TV & CRT onl */
+ EXTVDATA Contrast; /* Contrast : for TV & CRT onl */
+ EXTVDATA PositionX; /* Horizontal Position : for all device */
+ EXTVDATA PositionY; /* Vertical Position : for all device */
+ /*EXTVDATA OverScanX; Horizontal Overscan : for TV onl */
+ EXTVDATA DotCrawl; /* Dot crawl value : for TV onl */
+ EXTVDATA ChromaFilter; /* Chroma Filter : for TV onl */
+ /* EXTVDATA OverScanY; Vertical Overscan : for TV onl */
+ EXTVDATA LumaFilter; /* Luma Filter : for TV only */
+ EXTVDATA Sharpness; /* Sharpness : for TV & CRT onl */
+ EXTVDATA Saturation; /* Saturation : for TV & CRT onl */
+ EXTVDATA Hue; /* Hue : for TV & CRT onl */
+ EXTVDATA Dither; /* Dither : For LVDS onl */
+} sdvo_display_params;
+
+typedef enum _SDVO_PICTURE_ASPECT_RATIO_T
+{
+ UAIM_PAR_NO_DATA = 0x00000000,
+ UAIM_PAR_4_3 = 0x00000100,
+ UAIM_PAR_16_9 = 0x00000200,
+ UAIM_PAR_FUTURE = 0x00000300,
+ UAIM_PAR_MASK = 0x00000300,
+} SDVO_PICTURE_ASPECT_RATIO_T;
+
+typedef enum _SDVO_FORMAT_ASPECT_RATIO_T
+{
+ UAIM_FAR_NO_DATA = 0x00000000,
+ UAIM_FAR_SAME_AS_PAR = 0x00002000,
+ UAIM_FAR_4_BY_3_CENTER = 0x00002400,
+ UAIM_FAR_16_BY_9_CENTER = 0x00002800,
+ UAIM_FAR_14_BY_9_CENTER = 0x00002C00,
+ UAIM_FAR_16_BY_9_LETTERBOX_TOP = 0x00000800,
+ UAIM_FAR_14_BY_9_LETTERBOX_TOP = 0x00000C00,
+ UAIM_FAR_GT_16_BY_9_LETTERBOX_CENTER = 0x00002000,
+ UAIM_FAR_4_BY_3_SNP_14_BY_9_CENTER = 0x00003400, /* With shoot and protect 14:9 cente */
+ UAIM_FAR_16_BY_9_SNP_14_BY_9_CENTER = 0x00003800, /* With shoot and protect 14:9 cente */
+ UAIM_FAR_16_BY_9_SNP_4_BY_3_CENTER = 0x00003C00, /* With shoot and protect 4:3 cente */
+ UAIM_FAR_MASK = 0x00003C00,
+} SDVO_FORMAT_ASPECT_RATIO_T;
+
+// TV image aspect ratio
+typedef enum _CP_IMAGE_ASPECT_RATIO
+{
+ CP_ASPECT_RATIO_FF_4_BY_3 = 0,
+ CP_ASPECT_RATIO_14_BY_9_CENTER = 1,
+ CP_ASPECT_RATIO_14_BY_9_TOP = 2,
+ CP_ASPECT_RATIO_16_BY_9_CENTER = 3,
+ CP_ASPECT_RATIO_16_BY_9_TOP = 4,
+ CP_ASPECT_RATIO_GT_16_BY_9_CENTER = 5,
+ CP_ASPECT_RATIO_FF_4_BY_3_PROT_CENTER = 6,
+ CP_ASPECT_RATIO_FF_16_BY_9_ANAMORPHIC = 7,
+} CP_IMAGE_ASPECT_RATIO;
+
+typedef struct _SDVO_ANCILLARY_INFO_T
+{
+ CP_IMAGE_ASPECT_RATIO AspectRatio;
+ u32 RedistCtrlFlag; /* Redistribution control flag (get and set */
+} SDVO_ANCILLARY_INFO_T, *PSDVO_ANCILLARY_INFO_T;
+
+struct intel_sdvo_priv {
+ struct intel_i2c_chan *i2c_bus;
+ int slaveaddr;
+ int output_device;
+
+ u16 active_outputs;
+
+ struct intel_sdvo_caps caps;
+ int pixel_clock_min, pixel_clock_max;
+
+ int save_sdvo_mult;
+ u16 save_active_outputs;
+ struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
+ struct intel_sdvo_dtd save_output_dtd[16];
+ u32 save_SDVOX;
+ /**
+ * SDVO TV encoder support
+ */
+ u32 ActiveDevice; /* CRT, TV, LVDS, TMDS */
+ u32 TVStandard; /* PAL, NTSC */
+ int TVOutput; /* S-Video, CVBS,YPbPr,RGB */
+ int TVMode; /* SDTV/HDTV/SECAM mod */
+ u32 TVStdBitmask;
+ u32 dwSDVOHDTVBitMask;
+ u32 dwSDVOSDTVBitMask;
+ u8 byInputWiring;
+ bool bGetClk;
+ u32 dwMaxDotClk;
+ u32 dwMinDotClk;
+
+ u32 dwMaxInDotClk;
+ u32 dwMinInDotClk;
+
+ u32 dwMaxOutDotClk;
+ u32 dwMinOutDotClk;
+ u32 dwSupportedEnhancements;
+ EXTVDATA OverScanY; /* Vertical Overscan : for TV onl */
+ EXTVDATA OverScanX; /* Horizontal Overscan : for TV onl */
+ sdvo_display_params dispParams;
+ SDVO_ANCILLARY_INFO_T AncillaryInfo;
+};
+
+/* Define TV mode type */
+/* The full set are defined in xf86str.h*/
+#define M_T_TV 0x80
+
+typedef struct _tv_mode_t
+{
+ /* the following data is detailed mode information as it would be passed to the hardware: */
+ struct drm_display_mode mode_entry;
+ u32 dwSupportedSDTVvss;
+ u32 dwSupportedHDTVvss;
+ bool m_preferred;
+ bool isTVMode;
+} tv_mode_t;
+
+static tv_mode_t tv_modes[] = {
+ {
+ .mode_entry =
+ {DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER | M_T_TV, 0x2625a00 / 1000, 800, 840, 968, 1056, 0,
+ 600, 601,
+ 604, 628, 0, V_PHSYNC | V_PVSYNC)},
+ .dwSupportedSDTVvss = TVSTANDARD_SDTV_ALL,
+ .dwSupportedHDTVvss = TVSTANDARD_HDTV_ALL,
+ .m_preferred = TRUE,
+ .isTVMode = TRUE,
+ },
+ {
+ .mode_entry =
+ {DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER | M_T_TV, 0x3dfd240 / 1000, 1024, 0x418, 0x49f, 0x540,
+ 0, 768,
+ 0x303, 0x308, 0x325, 0, V_PHSYNC | V_PVSYNC)},
+ .dwSupportedSDTVvss = TVSTANDARD_SDTV_ALL,
+ .dwSupportedHDTVvss = TVSTANDARD_HDTV_ALL,
+ .m_preferred = FALSE,
+ .isTVMode = TRUE,
+ },
+ {
+ .mode_entry =
+ {DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER | M_T_TV, 0x1978ff0 / 1000, 720, 0x2e1, 0x326, 0x380, 0,
+ 480,
+ 0x1f0, 0x1e1, 0x1f1, 0, V_PHSYNC | V_PVSYNC)},
+ .dwSupportedSDTVvss =
+ TVSTANDARD_NTSC_M | TVSTANDARD_NTSC_M_J | TVSTANDARD_NTSC_433,
+ .dwSupportedHDTVvss = 0x0,
+ .m_preferred = FALSE,
+ .isTVMode = TRUE,
+ },
+ {
+ /*Modeline "720x576_SDVO" 0.96 720 756 788 864 576 616 618 700 +vsync */
+ .mode_entry =
+ {DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER | M_T_TV, 0x1f25a20 / 1000, 720, 756, 788, 864, 0, 576,
+ 616,
+ 618, 700, 0, V_PHSYNC | V_PVSYNC)},
+ .dwSupportedSDTVvss =
+ (TVSTANDARD_PAL_B | TVSTANDARD_PAL_D | TVSTANDARD_PAL_H |
+ TVSTANDARD_PAL_I | TVSTANDARD_PAL_N | TVSTANDARD_SECAM_B |
+ TVSTANDARD_SECAM_D | TVSTANDARD_SECAM_G | TVSTANDARD_SECAM_H |
+ TVSTANDARD_SECAM_K | TVSTANDARD_SECAM_K1 | TVSTANDARD_SECAM_L |
+ TVSTANDARD_PAL_G | TVSTANDARD_SECAM_L1),
+ .dwSupportedHDTVvss = 0x0,
+ .m_preferred = FALSE,
+ .isTVMode = TRUE,
+ },
+ {
+ .mode_entry =
+ {DRM_MODE("1280x720@60",DRM_MODE_TYPE_DRIVER | M_T_TV, 74250000 / 1000, 1280, 1390, 1430, 1650, 0,
+ 720,
+ 725, 730, 750, 0, V_PHSYNC | V_PVSYNC)},
+ .dwSupportedSDTVvss = 0x0,
+ .dwSupportedHDTVvss = HDTV_SMPTE_296M_720p60,
+ .m_preferred = FALSE,
+ .isTVMode = TRUE,
+ },
+ {
+ .mode_entry =
+ {DRM_MODE("1280x720@50", DRM_MODE_TYPE_DRIVER | M_T_TV, 74250000 / 1000, 1280, 1720, 1759, 1980, 0,
+ 720,
+ 725, 730, 750, 0, V_PHSYNC | V_PVSYNC)},
+ .dwSupportedSDTVvss = 0x0,
+ .dwSupportedHDTVvss = HDTV_SMPTE_296M_720p50,
+ .m_preferred = FALSE,
+ .isTVMode = TRUE,
+ },
+ {
+ .mode_entry =
+ {DRM_MODE("1920x1080@60", DRM_MODE_TYPE_DRIVER | M_T_TV, 148500000 / 1000, 1920, 2008, 2051, 2200, 0,
+ 1080,
+ 1084, 1088, 1124, 0, V_PHSYNC | V_PVSYNC)},
+ .dwSupportedSDTVvss = 0x0,
+ .dwSupportedHDTVvss = HDTV_SMPTE_274M_1080i60,
+ .m_preferred = FALSE,
+ .isTVMode = TRUE,
+ },
+};
+
+#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
+
+typedef struct {
+ /* given values */
+ int n;
+ int m1, m2;
+ int p1, p2;
+ /* derived values */
+ int dot;
+ int vco;
+ int m;
+ int p;
+} ex_intel_clock_t;
+
+
+/**
+ * Writes the SDVOB or SDVOC with the given value, but always writes both
+ * SDVOB and SDVOC to work around apparent hardware issues (according to
+ * comments in the BIOS).
+ */
+static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)
+{
+ struct drm_device *dev = output->dev;
+ DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ u32 bval = val, cval = val;
+ int i;
+
+ if (sdvo_priv->output_device == SDVOB)
+ cval = I915_READ(SDVOC);
+ else
+ bval = I915_READ(SDVOB);
+ /*
+ * Write the registers twice for luck. Sometimes,
+ * writing them only once doesn't appear to 'stick'.
+ * The BIOS does this too. Yay, magic
+ */
+ for (i = 0; i < 2; i++)
+ {
+ I915_WRITE(SDVOB, bval);
+ I915_READ(SDVOB);
+ I915_WRITE(SDVOC, cval);
+ I915_READ(SDVOC);
+ }
+}
+
+static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr,
+ u8 *ch)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ u8 out_buf[2];
+ u8 buf[2];
+ int ret;
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = sdvo_priv->i2c_bus->slave_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = out_buf,
+ },
+ {
+ .addr = sdvo_priv->i2c_bus->slave_addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = buf,
+ }
+ };
+
+ out_buf[0] = addr;
+ out_buf[1] = 0;
+
+ if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2)
+ {
+// DRM_DEBUG("got back from addr %02X = %02x\n", out_buf[0], buf[0]);
+ *ch = buf[0];
+ return true;
+ }
+
+ DRM_DEBUG("i2c transfer returned %d\n", ret);
+ return false;
+}
+
+
+#if 0
+static bool intel_sdvo_read_byte_quiet(struct drm_output *output, int addr,
+ u8 *ch)
+{
+ return true;
+
+}
+#endif
+
+static bool intel_sdvo_write_byte(struct drm_output *output, int addr,
+ u8 ch)
+{
+ struct intel_output *intel_output = output->driver_private;
+ u8 out_buf[2];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = intel_output->i2c_bus->slave_addr,
+ .flags = 0,
+ .len = 2,
+ .buf = out_buf,
+ }
+ };
+
+ out_buf[0] = addr;
+ out_buf[1] = ch;
+
+ if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1)
+ {
+ return true;
+ }
+ return false;
+}
+
+#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
+/** Mapping of command numbers to names, for debug output */
+const static struct _sdvo_cmd_name {
+ u8 cmd;
+ char *name;
+} sdvo_cmd_names[] = {
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS),
+ 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_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),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
+ SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
+};
+
+#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC")
+#define SDVO_PRIV(output) ((struct intel_sdvo_priv *) (output)->dev_priv)
+
+static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd,
+ void *args, int args_len)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ int i;
+
+ if (drm_debug) {
+ DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
+ for (i = 0; i < args_len; i++)
+ printk("%02X ", ((u8 *)args)[i]);
+ for (; i < 8; i++)
+ printk(" ");
+ for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
+ if (cmd == sdvo_cmd_names[i].cmd) {
+ printk("(%s)", sdvo_cmd_names[i].name);
+ break;
+ }
+ }
+ if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
+ printk("(%02X)",cmd);
+ printk("\n");
+ }
+
+ for (i = 0; i < args_len; i++) {
+ intel_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]);
+ }
+
+ intel_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd);
+}
+
+static const char *cmd_status_names[] = {
+ "Power on",
+ "Success",
+ "Not supported",
+ "Invalid arg",
+ "Pending",
+ "Target not specified",
+ "Scaling not supported"
+};
+
+static u8 intel_sdvo_read_response(struct drm_output *output, void *response,
+ int response_len)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ int i;
+ u8 status;
+ u8 retry = 50;
+
+ while (retry--) {
+ /* Read the command response */
+ for (i = 0; i < response_len; i++) {
+ intel_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i,
+ &((u8 *)response)[i]);
+ }
+
+ /* read the return status */
+ intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status);
+
+ if (drm_debug) {
+ DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv));
+ for (i = 0; i < response_len; i++)
+ printk("%02X ", ((u8 *)response)[i]);
+ for (; i < 8; i++)
+ printk(" ");
+ if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+ printk("(%s)", cmd_status_names[status]);
+ else
+ printk("(??? %d)", status);
+ printk("\n");
+ }
+
+ if (status != SDVO_CMD_STATUS_PENDING)
+ return status;
+
+ mdelay(50);
+ }
+
+ return status;
+}
+
+int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
+{
+ if (mode->clock >= 100000)
+ return 1;
+ else if (mode->clock >= 50000)
+ return 2;
+ else
+ return 4;
+}
+
+/**
+ * Don't check status code from this as it switches the bus back to the
+ * SDVO chips which defeats the purpose of doing a bus switch in the first
+ * place.
+ */
+void intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target)
+{
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1);
+}
+
+static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0, bool target_1)
+{
+ struct intel_sdvo_set_target_input_args targets = {0};
+ u8 status;
+
+ if (target_0 && target_1)
+ return SDVO_CMD_STATUS_NOTSUPP;
+
+ if (target_1)
+ targets.target_1 = 1;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets,
+ sizeof(targets));
+
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ 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 intel_sdvo_get_trained_inputs(struct drm_output *output, bool *input_1, bool *input_2)
+{
+ struct intel_sdvo_get_trained_inputs_response response;
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0);
+ status = intel_sdvo_read_response(output, &response, sizeof(response));
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ *input_1 = response.input0_trained;
+ *input_2 = response.input1_trained;
+ return true;
+}
+
+static bool intel_sdvo_get_active_outputs(struct drm_output *output,
+ u16 *outputs)
+{
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0);
+ status = intel_sdvo_read_response(output, outputs, sizeof(*outputs));
+
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_set_active_outputs(struct drm_output *output,
+ u16 outputs)
+{
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs,
+ sizeof(outputs));
+ status = intel_sdvo_read_response(output, NULL, 0);
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_set_encoder_power_state(struct drm_output *output,
+ int mode)
+{
+ u8 status, state = SDVO_ENCODER_STATE_ON;
+
+ switch (mode) {
+ case DPMSModeOn:
+ state = SDVO_ENCODER_STATE_ON;
+ break;
+ case DPMSModeStandby:
+ state = SDVO_ENCODER_STATE_STANDBY;
+ break;
+ case DPMSModeSuspend:
+ state = SDVO_ENCODER_STATE_SUSPEND;
+ break;
+ case DPMSModeOff:
+ state = SDVO_ENCODER_STATE_OFF;
+ break;
+ }
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state,
+ sizeof(state));
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_get_input_pixel_clock_range(struct drm_output *output,
+ int *clock_min,
+ int *clock_max)
+{
+ struct intel_sdvo_pixel_clock_range clocks;
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
+ NULL, 0);
+
+ status = intel_sdvo_read_response(output, &clocks, sizeof(clocks));
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ /* Convert the values from units of 10 kHz to kHz. */
+ *clock_min = clocks.min * 10;
+ *clock_max = clocks.max * 10;
+
+ return true;
+}
+
+static bool intel_sdvo_set_target_output(struct drm_output *output,
+ u16 outputs)
+{
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs,
+ sizeof(outputs));
+
+ status = intel_sdvo_read_response(output, NULL, 0);
+ return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_get_timing(struct drm_output *output, u8 cmd,
+ struct intel_sdvo_dtd *dtd)
+{
+ u8 status;
+
+ intel_sdvo_write_cmd(output, cmd, NULL, 0);
+ status = intel_sdvo_read_response(output, &dtd->part1,
+ sizeof(dtd->part1));
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ intel_sdvo_write_cmd(output, cmd + 1, NULL, 0);
+ status = intel_sdvo_read_response(output, &dtd->part2,
+ sizeof(dtd->part2));
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ return true;
+}
+
+static bool intel_sdvo_get_input_timing(struct drm_output *output,
+ struct intel_sdvo_dtd *dtd)
+{
+ return intel_sdvo_get_timing(output,
+ SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_get_output_timing(struct drm_output *output,
+ struct intel_sdvo_dtd *dtd)
+{
+ return intel_sdvo_get_timing(output,
+ SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_set_timing(struct drm_output *output, u8 cmd,
+ struct intel_sdvo_dtd *dtd)
+{
+ u8 status;
+
+ intel_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1));
+ status = intel_sdvo_read_response(output, NULL, 0);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ intel_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+ status = intel_sdvo_read_response(output, NULL, 0);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ return true;
+}
+
+static bool intel_sdvo_set_input_timing(struct drm_output *output,
+ struct intel_sdvo_dtd *dtd)
+{
+ return intel_sdvo_set_timing(output,
+ SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_set_output_timing(struct drm_output *output,
+ struct intel_sdvo_dtd *dtd)
+{
+ return intel_sdvo_set_timing(output,
+ SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
+}
+
+#if 0
+static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output,
+ struct intel_sdvo_dtd *dtd)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
+ NULL, 0);
+
+ status = intel_sdvo_read_response(output, &dtd->part1,
+ sizeof(dtd->part1));
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
+ NULL, 0);
+ status = intel_sdvo_read_response(output, &dtd->part2,
+ sizeof(dtd->part2));
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ return true;
+}
+#endif
+
+static int intel_sdvo_get_clock_rate_mult(struct drm_output *output)
+{
+ u8 response, status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0);
+ status = intel_sdvo_read_response(output, &response, 1);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS) {
+ DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n");
+ return SDVO_CLOCK_RATE_MULT_1X;
+ } else {
+ DRM_DEBUG("Current clock rate multiplier: %d\n", response);
+ }
+
+ return response;
+}
+
+static bool intel_sdvo_set_clock_rate_mult(struct drm_output *output, u8 val)
+{
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
+ status = intel_sdvo_read_response(output, NULL, 0);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ return true;
+}
+
+static bool intel_sdvo_mode_fixup(struct drm_output *output,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO
+ * device will be told of the multiplier during mode_set.
+ */
+ DRM_DEBUG("xxintel_sdvo_fixup\n");
+ adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+ return true;
+}
+
+#if 0
+static void i830_sdvo_map_hdtvstd_bitmask(struct drm_output * output)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ switch (sdvo_priv->TVStandard) {
+ case HDTV_SMPTE_274M_1080i50:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_274M_1080i50;
+ break;
+
+ case HDTV_SMPTE_274M_1080i59:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_274M_1080i59;
+ break;
+
+ case HDTV_SMPTE_274M_1080i60:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_274M_1080i60;
+ break;
+ case HDTV_SMPTE_274M_1080p60:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_274M_1080p60;
+ break;
+ case HDTV_SMPTE_296M_720p59:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_296M_720p59;
+ break;
+
+ case HDTV_SMPTE_296M_720p60:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_296M_720p60;
+ break;
+
+ case HDTV_SMPTE_296M_720p50:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_296M_720p50;
+ break;
+
+ case HDTV_SMPTE_293M_480p59:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_293M_480p59;
+ break;
+
+ case HDTV_SMPTE_293M_480p60:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_EIA_7702A_480p60;
+ break;
+
+ case HDTV_SMPTE_170M_480i59:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_170M_480i59;
+ break;
+
+ case HDTV_ITURBT601_576i50:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_ITURBT601_576i50;
+ break;
+
+ case HDTV_ITURBT601_576p50:
+ sdvo_priv->TVStdBitmask = SDVO_HDTV_STD_ITURBT601_576p50;
+ break;
+ default:
+ DRM_DEBUG("ERROR: Unknown TV Standard!!!\n");
+ /*Invalid return 0 */
+ sdvo_priv->TVStdBitmask = 0;
+ }
+
+}
+
+static void i830_sdvo_map_sdtvstd_bitmask(struct drm_output * output)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ switch (sdvo_priv->TVStandard) {
+ case TVSTANDARD_NTSC_M:
+ sdvo_priv->TVStdBitmask = SDVO_NTSC_M;
+ break;
+
+ case TVSTANDARD_NTSC_M_J:
+ sdvo_priv->TVStdBitmask = SDVO_NTSC_M_J;
+ break;
+
+ case TVSTANDARD_NTSC_433:
+ sdvo_priv->TVStdBitmask = SDVO_NTSC_433;
+ break;
+
+ case TVSTANDARD_PAL_B:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_B;
+ break;
+
+ case TVSTANDARD_PAL_D:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_D;
+ break;
+
+ case TVSTANDARD_PAL_G:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_G;
+ break;
+
+ case TVSTANDARD_PAL_H:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_H;
+ break;
+
+ case TVSTANDARD_PAL_I:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_I;
+ break;
+
+ case TVSTANDARD_PAL_M:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_M;
+ break;
+
+ case TVSTANDARD_PAL_N:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_N;
+ break;
+
+ case TVSTANDARD_PAL_60:
+ sdvo_priv->TVStdBitmask = SDVO_PAL_60;
+ break;
+
+ case TVSTANDARD_SECAM_B:
+ sdvo_priv->TVStdBitmask = SDVO_SECAM_B;
+ break;
+
+ case TVSTANDARD_SECAM_D:
+ sdvo_priv->TVStdBitmask = SDVO_SECAM_D;
+ break;
+
+ case TVSTANDARD_SECAM_G:
+ sdvo_priv->TVStdBitmask = SDVO_SECAM_G;
+ break;
+
+ case TVSTANDARD_SECAM_K:
+ sdvo_priv->TVStdBitmask = SDVO_SECAM_K;
+ break;
+
+ case TVSTANDARD_SECAM_K1:
+ sdvo_priv->TVStdBitmask = SDVO_SECAM_K1;
+ break;
+
+ case TVSTANDARD_SECAM_L:
+ sdvo_priv->TVStdBitmask = SDVO_SECAM_L;
+ break;
+
+ case TVSTANDARD_SECAM_L1:
+ DRM_DEBUG("TVSTANDARD_SECAM_L1 not supported by encoder\n");
+ break;
+
+ case TVSTANDARD_SECAM_H:
+ DRM_DEBUG("TVSTANDARD_SECAM_H not supported by encoder\n");
+ break;
+
+ default:
+ DRM_DEBUG("ERROR: Unknown TV Standard\n");
+ /*Invalid return 0 */
+ sdvo_priv->TVStdBitmask = 0;
+ break;
+ }
+}
+#endif
+
+static bool i830_sdvo_set_tvoutputs_formats(struct drm_output * output)
+{
+ u8 byArgs[6];
+ u8 status;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ if (sdvo_priv->TVMode & (TVMODE_SDTV)) {
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (sdvo_priv->TVStdBitmask & 0xFF);
+ byArgs[1] = (u8) ((sdvo_priv->TVStdBitmask >> 8) & 0xFF);
+ byArgs[2] = (u8) ((sdvo_priv->TVStdBitmask >> 16) & 0xFF);
+ } else {
+ /* Fill up the arguement value */
+ byArgs[0] = 0;
+ byArgs[1] = 0;
+ byArgs[2] = (u8) ((sdvo_priv->TVStdBitmask & 0xFF));
+ byArgs[3] = (u8) ((sdvo_priv->TVStdBitmask >> 8) & 0xFF);
+ byArgs[4] = (u8) ((sdvo_priv->TVStdBitmask >> 16) & 0xFF);
+ byArgs[5] = (u8) ((sdvo_priv->TVStdBitmask >> 24) & 0xFF);
+ }
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMATS, byArgs, 6);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+
+}
+
+static bool i830_sdvo_create_preferred_input_timing(struct drm_output * output,
+ struct drm_display_mode * mode)
+{
+ u8 byArgs[7];
+ u8 status;
+ u32 dwClk;
+ u32 dwHActive, dwVActive;
+ bool bIsInterlaced, bIsScaled;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement values */
+ dwHActive = mode->crtc_hdisplay;
+ dwVActive = mode->crtc_vdisplay;
+
+ dwClk = mode->clock * 1000 / 10000;
+ byArgs[0] = (u8) (dwClk & 0xFF);
+ byArgs[1] = (u8) ((dwClk >> 8) & 0xFF);
+
+ /* HActive & VActive should not exceed 12 bits each. So check it */
+ if ((dwHActive > 0xFFF) || (dwVActive > 0xFFF))
+ return FALSE;
+
+ byArgs[2] = (u8) (dwHActive & 0xFF);
+ byArgs[3] = (u8) ((dwHActive >> 8) & 0xF);
+ byArgs[4] = (u8) (dwVActive & 0xFF);
+ byArgs[5] = (u8) ((dwVActive >> 8) & 0xF);
+
+ bIsInterlaced = 1;
+ bIsScaled = 0;
+
+ byArgs[6] = bIsInterlaced ? 1 : 0;
+ byArgs[6] |= bIsScaled ? 2 : 0;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMINGS,
+ byArgs, 7);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+
+}
+
+static bool i830_sdvo_get_preferred_input_timing(struct drm_output * output,
+ struct intel_sdvo_dtd *output_dtd)
+{
+ return intel_sdvo_get_timing(output,
+ SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
+ output_dtd);
+}
+
+static bool i830_sdvo_set_current_inoutmap(struct drm_output * output, u32 in0outputmask,
+ u32 in1outputmask)
+{
+ u8 byArgs[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement values; */
+ byArgs[0] = (u8) (in0outputmask & 0xFF);
+ byArgs[1] = (u8) ((in0outputmask >> 8) & 0xFF);
+ byArgs[2] = (u8) (in1outputmask & 0xFF);
+ byArgs[3] = (u8) ((in1outputmask >> 8) & 0xFF);
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_IN_OUT_MAP, byArgs, 4);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+
+}
+
+void i830_sdvo_set_iomap(struct drm_output * output)
+{
+ u32 dwCurrentSDVOIn0 = 0;
+ u32 dwCurrentSDVOIn1 = 0;
+ u32 dwDevMask = 0;
+
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ /* Please DO NOT change the following code. */
+ /* SDVOB_IN0 or SDVOB_IN1 ==> sdvo_in0 */
+ /* SDVOC_IN0 or SDVOC_IN1 ==> sdvo_in1 */
+ if (sdvo_priv->byInputWiring & (SDVOB_IN0 | SDVOC_IN0)) {
+ switch (sdvo_priv->ActiveDevice) {
+ case SDVO_DEVICE_LVDS:
+ dwDevMask = SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1;
+ break;
+
+ case SDVO_DEVICE_TMDS:
+ dwDevMask = SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1;
+ break;
+
+ case SDVO_DEVICE_TV:
+ dwDevMask =
+ SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0 |
+ SDVO_OUTPUT_YPRPB1 | SDVO_OUTPUT_SVID1 | SDVO_OUTPUT_CVBS1 |
+ SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1;
+ break;
+
+ case SDVO_DEVICE_CRT:
+ dwDevMask = SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1;
+ break;
+ }
+ dwCurrentSDVOIn0 = (sdvo_priv->active_outputs & dwDevMask);
+ } else if (sdvo_priv->byInputWiring & (SDVOB_IN1 | SDVOC_IN1)) {
+ switch (sdvo_priv->ActiveDevice) {
+ case SDVO_DEVICE_LVDS:
+ dwDevMask = SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1;
+ break;
+
+ case SDVO_DEVICE_TMDS:
+ dwDevMask = SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1;
+ break;
+
+ case SDVO_DEVICE_TV:
+ dwDevMask =
+ SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0 |
+ SDVO_OUTPUT_YPRPB1 | SDVO_OUTPUT_SVID1 | SDVO_OUTPUT_CVBS1 |
+ SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1;
+ break;
+
+ case SDVO_DEVICE_CRT:
+ dwDevMask = SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1;
+ break;
+ }
+ dwCurrentSDVOIn1 = (sdvo_priv->active_outputs & dwDevMask);
+ }
+
+ i830_sdvo_set_current_inoutmap(output, dwCurrentSDVOIn0,
+ dwCurrentSDVOIn1);
+}
+
+static bool i830_sdvo_get_input_output_pixelclock_range(struct drm_output * output,
+ bool direction)
+{
+ u8 byRets[4];
+ u8 status;
+
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+ if (direction) /* output pixel clock */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE,
+ NULL, 0);
+ else
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
+ NULL, 0);
+ status = intel_sdvo_read_response(output, byRets, 4);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ if (direction) {
+ /* Fill up the return values. */
+ sdvo_priv->dwMinOutDotClk =
+ (u32) byRets[0] | ((u32) byRets[1] << 8);
+ sdvo_priv->dwMaxOutDotClk =
+ (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ /* Multiply 10000 with the clocks obtained */
+ sdvo_priv->dwMinOutDotClk = (sdvo_priv->dwMinOutDotClk) * 10000;
+ sdvo_priv->dwMaxOutDotClk = (sdvo_priv->dwMaxOutDotClk) * 10000;
+
+ } else {
+ /* Fill up the return values. */
+ sdvo_priv->dwMinInDotClk = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ sdvo_priv->dwMaxInDotClk = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ /* Multiply 10000 with the clocks obtained */
+ sdvo_priv->dwMinInDotClk = (sdvo_priv->dwMinInDotClk) * 10000;
+ sdvo_priv->dwMaxInDotClk = (sdvo_priv->dwMaxInDotClk) * 10000;
+ }
+ DRM_DEBUG("MinDotClk = 0x%x\n", sdvo_priv->dwMinInDotClk);
+ DRM_DEBUG("MaxDotClk = 0x%x\n", sdvo_priv->dwMaxInDotClk);
+
+ return TRUE;
+
+}
+
+static bool i830_sdvo_get_supported_tvoutput_formats(struct drm_output * output,
+ u32 * pTVStdMask,
+ u32 * pHDTVStdMask, u32 *pTVStdFormat)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ u8 byRets[6];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 6);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values; */
+ *pTVStdMask = (((u32) byRets[0]) |
+ ((u32) byRets[1] << 8) |
+ ((u32) (byRets[2] & 0x7) << 16));
+
+ *pHDTVStdMask = (((u32) byRets[2] & 0xF8) |
+ ((u32) byRets[3] << 8) |
+ ((u32) byRets[4] << 16) | ((u32) byRets[5] << 24));
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMATS, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 6);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values; */
+ if(sdvo_priv->TVMode == TVMODE_SDTV)
+ *pTVStdFormat = (((u32) byRets[0]) |
+ ((u32) byRets[1] << 8) |
+ ((u32) (byRets[2] & 0x7) << 16));
+ else
+ *pTVStdFormat = (((u32) byRets[2] & 0xF8) |
+ ((u32) byRets[3] << 8) |
+ ((u32) byRets[4] << 16) | ((u32) byRets[5] << 24));
+ DRM_DEBUG("BIOS TV format is %d\n",*pTVStdFormat);
+ return TRUE;
+
+}
+
+static bool i830_sdvo_get_supported_enhancements(struct drm_output * output,
+ u32 * psupported_enhancements)
+{
+
+ u8 status;
+ u8 byRets[2];
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 2);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ sdvo_priv->dwSupportedEnhancements = *psupported_enhancements =
+ ((u32) byRets[0] | ((u32) byRets[1] << 8));
+ return TRUE;
+
+}
+
+static bool i830_sdvo_get_max_horizontal_overscan(struct drm_output * output, u32 * pMaxVal,
+ u32 * pDefaultVal)
+{
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_HORIZONTAL_OVERSCAN, NULL,
+ 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_vertical_overscan(struct drm_output * output, u32 * pMaxVal,
+ u32 * pDefaultVal)
+{
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_VERTICAL_OVERSCAN, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_horizontal_position(struct drm_output * output, u32 * pMaxVal,
+ u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_HORIZONTAL_POSITION, NULL,
+ 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_vertical_position(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_VERTICAL_POSITION, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_flickerfilter(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_FLICKER_FILTER, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_brightness(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_contrast(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_CONTRAST, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_sharpness(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_SHARPNESS, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_hue(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_HUE, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_saturation(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_SATURATION, NULL, 0);
+
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_adaptive_flickerfilter(struct drm_output * output,
+ u32 * pMaxVal,
+ u32 * pDefaultVal)
+{
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_ADAPTIVE_FLICKER_FILTER,
+ NULL, 0);
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_lumafilter(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_TV_LUMA_FILTER, NULL, 0);
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_chromafilter(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_TV_CHROMA_FILTER, NULL, 0);
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_get_dotcrawl(struct drm_output * output,
+ u32 * pCurrentVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_DOT_CRAWL, NULL, 0);
+ status = intel_sdvo_read_response(output, byRets, 2);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Tibet issue 1603772: Dot crawl do not persist after reboot/Hibernate */
+ /* Details : Bit0 is considered as DotCrawl Max value. But according to EDS, Bit0 */
+ /* represents the Current DotCrawl value. */
+ /* Fix : The current value is updated with Bit0. */
+
+ /* Fill up the return values. */
+ *pCurrentVal = (u32) (byRets[0] & 0x1);
+ *pDefaultVal = (u32) ((byRets[0] >> 1) & 0x1);
+ return TRUE;
+}
+
+static bool i830_sdvo_get_max_2D_flickerfilter(struct drm_output * output,
+ u32 * pMaxVal, u32 * pDefaultVal)
+{
+
+ u8 byRets[4];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byRets, 0, sizeof(byRets));
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_MAX_2D_FLICKER_FILTER, NULL, 0);
+ status = intel_sdvo_read_response(output, byRets, 4);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ /* Fill up the return values. */
+ *pMaxVal = (u32) byRets[0] | ((u32) byRets[1] << 8);
+ *pDefaultVal = (u32) byRets[2] | ((u32) byRets[3] << 8);
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_horizontal_overscan(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_HORIZONTAL_OVERSCAN, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+ return TRUE;
+}
+
+static bool i830_sdvo_set_vertical_overscan(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_VERTICAL_OVERSCAN, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+ return TRUE;
+}
+
+static bool i830_sdvo_set_horizontal_position(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_HORIZONTAL_POSITION, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_vertical_position(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_VERTICAL_POSITION, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+
+}
+
+static bool i830_sdvo_set_flickerilter(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_FLICKER_FILTER, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_brightness(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_BRIGHTNESS, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_contrast(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTRAST, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_sharpness(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_SHARPNESS, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_hue(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_HUE, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_saturation(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_SATURATION, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_adaptive_flickerfilter(struct drm_output * output, u32 dwVal)
+{
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_ADAPTIVE_FLICKER_FILTER, byArgs,
+ 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+
+}
+
+static bool i830_sdvo_set_lumafilter(struct drm_output * output, u32 dwVal)
+{
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_LUMA_FILTER, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_chromafilter(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_CHROMA_FILTER, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_dotcrawl(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_DOT_CRAWL, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool i830_sdvo_set_2D_flickerfilter(struct drm_output * output, u32 dwVal)
+{
+
+ u8 byArgs[2];
+ u8 status;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Fill up the arguement value */
+ byArgs[0] = (u8) (dwVal & 0xFF);
+ byArgs[1] = (u8) ((dwVal >> 8) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_2D_FLICKER_FILTER, byArgs, 2);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+
+#if 0
+static bool i830_sdvo_set_ancillary_video_information(struct drm_output * output)
+{
+
+ u8 status;
+ u8 byArgs[4];
+ u32 dwAncillaryBits = 0;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ PSDVO_ANCILLARY_INFO_T pAncillaryInfo = &sdvo_priv->AncillaryInfo;
+
+ /* Make all fields of the args/ret to zero */
+ memset(byArgs, 0, sizeof(byArgs));
+
+ /* Handle picture aspect ratio (bits 8, 9) and */
+ /* active format aspect ratio (bits 10, 13) */
+ switch (pAncillaryInfo->AspectRatio) {
+ case CP_ASPECT_RATIO_FF_4_BY_3:
+ dwAncillaryBits |= UAIM_PAR_4_3;
+ dwAncillaryBits |= UAIM_FAR_4_BY_3_CENTER;
+ break;
+ case CP_ASPECT_RATIO_14_BY_9_CENTER:
+ dwAncillaryBits |= UAIM_FAR_14_BY_9_CENTER;
+ break;
+ case CP_ASPECT_RATIO_14_BY_9_TOP:
+ dwAncillaryBits |= UAIM_FAR_14_BY_9_LETTERBOX_TOP;
+ break;
+ case CP_ASPECT_RATIO_16_BY_9_CENTER:
+ dwAncillaryBits |= UAIM_PAR_16_9;
+ dwAncillaryBits |= UAIM_FAR_16_BY_9_CENTER;
+ break;
+ case CP_ASPECT_RATIO_16_BY_9_TOP:
+ dwAncillaryBits |= UAIM_PAR_16_9;
+ dwAncillaryBits |= UAIM_FAR_16_BY_9_LETTERBOX_TOP;
+ break;
+ case CP_ASPECT_RATIO_GT_16_BY_9_CENTER:
+ dwAncillaryBits |= UAIM_PAR_16_9;
+ dwAncillaryBits |= UAIM_FAR_GT_16_BY_9_LETTERBOX_CENTER;
+ break;
+ case CP_ASPECT_RATIO_FF_4_BY_3_PROT_CENTER:
+ dwAncillaryBits |= UAIM_FAR_4_BY_3_SNP_14_BY_9_CENTER;
+ break;
+ case CP_ASPECT_RATIO_FF_16_BY_9_ANAMORPHIC:
+ dwAncillaryBits |= UAIM_PAR_16_9;
+ break;
+ default:
+ DRM_DEBUG("fail to set ancillary video info\n");
+ return FALSE;
+
+ }
+
+ /* Fill up the argument value */
+ byArgs[0] = (u8) ((dwAncillaryBits >> 0) & 0xFF);
+ byArgs[1] = (u8) ((dwAncillaryBits >> 8) & 0xFF);
+ byArgs[2] = (u8) ((dwAncillaryBits >> 16) & 0xFF);
+ byArgs[3] = (u8) ((dwAncillaryBits >> 24) & 0xFF);
+
+ /* Send the arguements & SDVO opcode to the h/w */
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_ANCILLARY_VIDEO_INFORMATION,
+ byArgs, 4);
+ status = intel_sdvo_read_response(output, NULL, 0);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+
+}
+#endif
+static bool i830_tv_program_display_params(struct drm_output * output)
+
+{
+ u8 status;
+ u32 dwMaxVal = 0;
+ u32 dwDefaultVal = 0;
+ u32 dwCurrentVal = 0;
+
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ /* X & Y Positions */
+
+ /* Horizontal postition */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_HORIZONTAL_POSITION) {
+ status =
+ i830_sdvo_get_max_horizontal_position(output, &dwMaxVal,
+ &dwDefaultVal);
+
+ if (status) {
+ /*Tibet issue 1596943: After changing mode from 8x6 to 10x7 open CUI and press Restore Defaults */
+ /*Position changes. */
+
+ /* Tibet:1629992 : can't keep previous TV setting status if re-boot system after TV setting(screen position & size) of CUI */
+ /* Fix : compare whether current postion is greater than max value and then assign the default value. Earlier the check was */
+ /* against the pAim->PositionX.Max value to dwMaxVal. When we boot the PositionX.Max value is 0 and so after every reboot, */
+ /* position is set to default. */
+
+ if (sdvo_priv->dispParams.PositionX.Value > dwMaxVal)
+ sdvo_priv->dispParams.PositionX.Value = dwDefaultVal;
+
+ status =
+ i830_sdvo_set_horizontal_position(output,
+ sdvo_priv->dispParams.PositionX.
+ Value);
+
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.PositionX.Max = dwMaxVal;
+ sdvo_priv->dispParams.PositionX.Min = 0;
+ sdvo_priv->dispParams.PositionX.Default = dwDefaultVal;
+ sdvo_priv->dispParams.PositionX.Step = 1;
+ } else {
+ return status;
+ }
+ }
+
+ /* Vertical position */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_VERTICAL_POSITION) {
+ status =
+ i830_sdvo_get_max_vertical_position(output, &dwMaxVal,
+ &dwDefaultVal);
+
+ if (status) {
+
+ /*Tibet issue 1596943: After changing mode from 8x6 to 10x7 open CUI and press Restore Defaults */
+ /*Position changes. */
+ /*currently if we are out of range get back to default */
+
+ /* Tibet:1629992 : can't keep previous TV setting status if re-boot system after TV setting(screen position & size) of CUI */
+ /* Fix : compare whether current postion is greater than max value and then assign the default value. Earlier the check was */
+ /* against the pAim->PositionY.Max value to dwMaxVal. When we boot the PositionX.Max value is 0 and so after every reboot, */
+ /* position is set to default. */
+
+ if (sdvo_priv->dispParams.PositionY.Value > dwMaxVal)
+ sdvo_priv->dispParams.PositionY.Value = dwDefaultVal;
+
+ status =
+ i830_sdvo_set_vertical_position(output,
+ sdvo_priv->dispParams.PositionY.
+ Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.PositionY.Max = dwMaxVal;
+ sdvo_priv->dispParams.PositionY.Min = 0;
+ sdvo_priv->dispParams.PositionY.Default = dwDefaultVal;
+ sdvo_priv->dispParams.PositionY.Step = 1;
+ } else {
+ return status;
+ }
+ }
+
+ /* Flicker Filter */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_FLICKER_FILTER) {
+ status =
+ i830_sdvo_get_max_flickerfilter(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*currently if we are out of range get back to default */
+ if (sdvo_priv->dispParams.FlickerFilter.Value > dwMaxVal)
+ sdvo_priv->dispParams.FlickerFilter.Value = dwDefaultVal;
+
+ status =
+ i830_sdvo_set_flickerilter(output,
+ sdvo_priv->dispParams.FlickerFilter.
+ Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.FlickerFilter.Max = dwMaxVal;
+ sdvo_priv->dispParams.FlickerFilter.Min = 0;
+ sdvo_priv->dispParams.FlickerFilter.Default = dwDefaultVal;
+ sdvo_priv->dispParams.FlickerFilter.Step = 1;
+ } else {
+ return status;
+ }
+ }
+
+ /* Brightness */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_BRIGHTNESS) {
+
+ status =
+ i830_sdvo_get_max_brightness(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.Brightness.Value > dwMaxVal)
+ sdvo_priv->dispParams.Brightness.Value = dwDefaultVal;
+
+ /* Program the device */
+ status =
+ i830_sdvo_set_brightness(output,
+ sdvo_priv->dispParams.Brightness.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.Brightness.Max = dwMaxVal;
+ sdvo_priv->dispParams.Brightness.Min = 0;
+ sdvo_priv->dispParams.Brightness.Default = dwDefaultVal;
+ sdvo_priv->dispParams.Brightness.Step = 1;
+ } else {
+ return status;
+ }
+
+ }
+
+ /* Contrast */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_CONTRAST) {
+
+ status = i830_sdvo_get_max_contrast(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.Contrast.Value > dwMaxVal)
+ sdvo_priv->dispParams.Contrast.Value = dwDefaultVal;
+
+ /* Program the device */
+ status =
+ i830_sdvo_set_contrast(output,
+ sdvo_priv->dispParams.Contrast.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.Contrast.Max = dwMaxVal;
+ sdvo_priv->dispParams.Contrast.Min = 0;
+ sdvo_priv->dispParams.Contrast.Default = dwDefaultVal;
+
+ sdvo_priv->dispParams.Contrast.Step = 1;
+
+ } else {
+ return status;
+ }
+ }
+
+ /* Sharpness */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_SHARPNESS) {
+
+ status =
+ i830_sdvo_get_max_sharpness(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.Sharpness.Value > dwMaxVal)
+ sdvo_priv->dispParams.Sharpness.Value = dwDefaultVal;
+
+ /* Program the device */
+ status =
+ i830_sdvo_set_sharpness(output,
+ sdvo_priv->dispParams.Sharpness.Value);
+ if (!status)
+ return status;
+ sdvo_priv->dispParams.Sharpness.Max = dwMaxVal;
+ sdvo_priv->dispParams.Sharpness.Min = 0;
+ sdvo_priv->dispParams.Sharpness.Default = dwDefaultVal;
+
+ sdvo_priv->dispParams.Sharpness.Step = 1;
+ } else {
+ return status;
+ }
+ }
+
+ /* Hue */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_HUE) {
+
+ status = i830_sdvo_get_max_hue(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.Hue.Value > dwMaxVal)
+ sdvo_priv->dispParams.Hue.Value = dwDefaultVal;
+
+ /* Program the device */
+ status = i830_sdvo_set_hue(output, sdvo_priv->dispParams.Hue.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.Hue.Max = dwMaxVal;
+ sdvo_priv->dispParams.Hue.Min = 0;
+ sdvo_priv->dispParams.Hue.Default = dwDefaultVal;
+
+ sdvo_priv->dispParams.Hue.Step = 1;
+
+ } else {
+ return status;
+ }
+ }
+
+ /* Saturation */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_SATURATION) {
+ status =
+ i830_sdvo_get_max_saturation(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.Saturation.Value > dwMaxVal)
+ sdvo_priv->dispParams.Saturation.Value = dwDefaultVal;
+
+ /* Program the device */
+ status =
+ i830_sdvo_set_saturation(output,
+ sdvo_priv->dispParams.Saturation.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.Saturation.Max = dwMaxVal;
+ sdvo_priv->dispParams.Saturation.Min = 0;
+ sdvo_priv->dispParams.Saturation.Default = dwDefaultVal;
+ sdvo_priv->dispParams.Saturation.Step = 1;
+ } else {
+ return status;
+ }
+
+ }
+
+ /* Adaptive Flicker filter */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_ADAPTIVE_FLICKER_FILTER) {
+ status =
+ i830_sdvo_get_max_adaptive_flickerfilter(output, &dwMaxVal,
+ &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.AdaptiveFF.Value > dwMaxVal)
+ sdvo_priv->dispParams.AdaptiveFF.Value = dwDefaultVal;
+
+ status =
+ i830_sdvo_set_adaptive_flickerfilter(output,
+ sdvo_priv->dispParams.
+ AdaptiveFF.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.AdaptiveFF.Max = dwMaxVal;
+ sdvo_priv->dispParams.AdaptiveFF.Min = 0;
+ sdvo_priv->dispParams.AdaptiveFF.Default = dwDefaultVal;
+ sdvo_priv->dispParams.AdaptiveFF.Step = 1;
+ } else {
+ return status;
+ }
+ }
+
+ /* 2D Flicker filter */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_2D_FLICKER_FILTER) {
+
+ status =
+ i830_sdvo_get_max_2D_flickerfilter(output, &dwMaxVal,
+ &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.TwoD_FlickerFilter.Value > dwMaxVal)
+ sdvo_priv->dispParams.TwoD_FlickerFilter.Value = dwDefaultVal;
+
+ status =
+ i830_sdvo_set_2D_flickerfilter(output,
+ sdvo_priv->dispParams.
+ TwoD_FlickerFilter.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.TwoD_FlickerFilter.Max = dwMaxVal;
+ sdvo_priv->dispParams.TwoD_FlickerFilter.Min = 0;
+ sdvo_priv->dispParams.TwoD_FlickerFilter.Default = dwDefaultVal;
+ sdvo_priv->dispParams.TwoD_FlickerFilter.Step = 1;
+ } else {
+ return status;
+ }
+ }
+
+ /* Luma Filter */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_TV_MAX_LUMA_FILTER) {
+ status =
+ i830_sdvo_get_max_lumafilter(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.LumaFilter.Value > dwMaxVal)
+ sdvo_priv->dispParams.LumaFilter.Value = dwDefaultVal;
+
+ /* Program the device */
+ status =
+ i830_sdvo_set_lumafilter(output,
+ sdvo_priv->dispParams.LumaFilter.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.LumaFilter.Max = dwMaxVal;
+ sdvo_priv->dispParams.LumaFilter.Min = 0;
+ sdvo_priv->dispParams.LumaFilter.Default = dwDefaultVal;
+ sdvo_priv->dispParams.LumaFilter.Step = 1;
+
+ } else {
+ return status;
+ }
+
+ }
+
+ /* Chroma Filter */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_MAX_TV_CHROMA_FILTER) {
+
+ status =
+ i830_sdvo_get_max_chromafilter(output, &dwMaxVal, &dwDefaultVal);
+
+ if (status) {
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+ if (sdvo_priv->dispParams.ChromaFilter.Value > dwMaxVal)
+ sdvo_priv->dispParams.ChromaFilter.Value = dwDefaultVal;
+
+ /* Program the device */
+ status =
+ i830_sdvo_set_chromafilter(output,
+ sdvo_priv->dispParams.ChromaFilter.
+ Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.ChromaFilter.Max = dwMaxVal;
+ sdvo_priv->dispParams.ChromaFilter.Min = 0;
+ sdvo_priv->dispParams.ChromaFilter.Default = dwDefaultVal;
+ sdvo_priv->dispParams.ChromaFilter.Step = 1;
+ } else {
+ return status;
+ }
+
+ }
+
+ /* Dot Crawl */
+ if (sdvo_priv->dwSupportedEnhancements & SDVO_DOT_CRAWL) {
+ status = i830_sdvo_get_dotcrawl(output, &dwCurrentVal, &dwDefaultVal);
+
+ if (status) {
+
+ dwMaxVal = 1;
+ /*check whether the value is beyond the max value, min value as per EDS is always 0 so */
+ /*no need to check it. */
+
+ /* Tibet issue 1603772: Dot crawl do not persist after reboot/Hibernate */
+ /* Details : "Dotcrawl.value" is compared with "dwDefaultVal". Since */
+ /* dwDefaultVal is always 0, dotCrawl value is always set to 0. */
+ /* Fix : Compare the current dotCrawl value with dwMaxValue. */
+
+ if (sdvo_priv->dispParams.DotCrawl.Value > dwMaxVal)
+
+ sdvo_priv->dispParams.DotCrawl.Value = dwMaxVal;
+
+ status =
+ i830_sdvo_set_dotcrawl(output,
+ sdvo_priv->dispParams.DotCrawl.Value);
+ if (!status)
+ return status;
+
+ sdvo_priv->dispParams.DotCrawl.Max = dwMaxVal;
+ sdvo_priv->dispParams.DotCrawl.Min = 0;
+ sdvo_priv->dispParams.DotCrawl.Default = dwMaxVal;
+ sdvo_priv->dispParams.DotCrawl.Step = 1;
+ } else {
+ return status;
+ }
+ }
+
+ return TRUE;
+}
+
+static bool i830_tv_set_overscan_parameters(struct drm_output * output)
+{
+ u8 status;
+
+ u32 dwDefaultVal = 0;
+ u32 dwMaxVal = 0;
+ u32 dwPercentageValue = 0;
+ u32 dwDefOverscanXValue = 0;
+ u32 dwDefOverscanYValue = 0;
+ u32 dwOverscanValue = 0;
+ u32 dwSupportedEnhancements;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ /* Get supported picture enhancements */
+ status =
+ i830_sdvo_get_supported_enhancements(output,
+ &dwSupportedEnhancements);
+ if (!status)
+ return status;
+
+ /* Horizontal Overscan */
+ if (dwSupportedEnhancements & SDVO_HORIZONTAL_OVERSCAN) {
+ status =
+ i830_sdvo_get_max_horizontal_overscan(output, &dwMaxVal,
+ &dwDefaultVal);
+ if (!status)
+ return status;
+
+ /*Calculate the default value in terms of percentage */
+ dwDefOverscanXValue = ((dwDefaultVal * 100) / dwMaxVal);
+
+ /*Calculate the default value in 0-1000 range */
+ dwDefOverscanXValue = (dwDefOverscanXValue * 10);
+
+ /*Overscan is in the range of 0 to 10000 as per MS spec */
+ if (sdvo_priv->OverScanX.Value > MAX_VAL)
+ sdvo_priv->OverScanX.Value = dwDefOverscanXValue;
+
+ /*Calculate the percentage(0-100%) of the overscan value */
+ dwPercentageValue = (sdvo_priv->OverScanX.Value * 100) / 1000;
+
+ /* Now map the % value to absolute value to be programed to the encoder */
+ dwOverscanValue = (dwMaxVal * dwPercentageValue) / 100;
+
+ status = i830_sdvo_set_horizontal_overscan(output, dwOverscanValue);
+ if (!status)
+ return status;
+
+ sdvo_priv->OverScanX.Max = 1000;
+ sdvo_priv->OverScanX.Min = 0;
+ sdvo_priv->OverScanX.Default = dwDefOverscanXValue;
+ sdvo_priv->OverScanX.Step = 20;
+ }
+
+ /* Horizontal Overscan */
+ /* vertical Overscan */
+ if (dwSupportedEnhancements & SDVO_VERTICAL_OVERSCAN) {
+ status =
+ i830_sdvo_get_max_vertical_overscan(output, &dwMaxVal,
+ &dwDefaultVal);
+ if (!status)
+ return status;
+
+ /*Calculate the default value in terms of percentage */
+ dwDefOverscanYValue = ((dwDefaultVal * 100) / dwMaxVal);
+
+ /*Calculate the default value in 0-1000 range */
+ dwDefOverscanYValue = (dwDefOverscanYValue * 10);
+
+ /*Overscan is in the range of 0 to 10000 as per MS spec */
+ if (sdvo_priv->OverScanY.Value > MAX_VAL)
+ sdvo_priv->OverScanY.Value = dwDefOverscanYValue;
+
+ /*Calculate the percentage(0-100%) of the overscan value */
+ dwPercentageValue = (sdvo_priv->OverScanY.Value * 100) / 1000;
+
+ /* Now map the % value to absolute value to be programed to the encoder */
+ dwOverscanValue = (dwMaxVal * dwPercentageValue) / 100;
+
+ status = i830_sdvo_set_vertical_overscan(output, dwOverscanValue);
+ if (!status)
+ return status;
+
+ sdvo_priv->OverScanY.Max = 1000;
+ sdvo_priv->OverScanY.Min = 0;
+ sdvo_priv->OverScanY.Default = dwDefOverscanYValue;
+ sdvo_priv->OverScanY.Step = 20;
+
+ }
+ /* vertical Overscan */
+ return TRUE;
+}
+
+static bool i830_translate_dtd2timing(struct drm_display_mode * pTimingInfo,
+ struct intel_sdvo_dtd *pDTD)
+{
+
+ u32 dwHBLHigh = 0;
+ u32 dwVBLHigh = 0;
+ u32 dwHSHigh1 = 0;
+ u32 dwHSHigh2 = 0;
+ u32 dwVSHigh1 = 0;
+ u32 dwVSHigh2 = 0;
+ u32 dwVPWLow = 0;
+ bool status = FALSE;
+
+ if ((pDTD == NULL) || (pTimingInfo == NULL)) {
+ return status;
+ }
+
+ pTimingInfo->clock= pDTD->part1.clock * 10000 / 1000; /*fix me if i am wrong */
+
+ pTimingInfo->hdisplay = pTimingInfo->crtc_hdisplay =
+ (u32) pDTD->part1.
+ h_active | ((u32) (pDTD->part1.h_high & 0xF0) << 4);
+
+ pTimingInfo->vdisplay = pTimingInfo->crtc_vdisplay =
+ (u32) pDTD->part1.
+ v_active | ((u32) (pDTD->part1.v_high & 0xF0) << 4);
+
+ pTimingInfo->crtc_hblank_start = pTimingInfo->crtc_hdisplay;
+
+ /* Horizontal Total = Horizontal Active + Horizontal Blanking */
+ dwHBLHigh = (u32) (pDTD->part1.h_high & 0x0F);
+ pTimingInfo->htotal = pTimingInfo->crtc_htotal =
+ pTimingInfo->crtc_hdisplay + (u32) pDTD->part1.h_blank +
+ (dwHBLHigh << 8);
+
+ pTimingInfo->crtc_hblank_end = pTimingInfo->crtc_htotal - 1;
+
+ /* Vertical Total = Vertical Active + Vertical Blanking */
+ dwVBLHigh = (u32) (pDTD->part1.v_high & 0x0F);
+ pTimingInfo->vtotal = pTimingInfo->crtc_vtotal =
+ pTimingInfo->crtc_vdisplay + (u32) pDTD->part1.v_blank +
+ (dwVBLHigh << 8);
+ pTimingInfo->crtc_vblank_start = pTimingInfo->crtc_vdisplay;
+ pTimingInfo->crtc_vblank_end = pTimingInfo->crtc_vtotal - 1;
+
+ /* Horz Sync Start = Horz Blank Start + Horz Sync Offset */
+ dwHSHigh1 = (u32) (pDTD->part2.sync_off_width_high & 0xC0);
+ pTimingInfo->hsync_start = pTimingInfo->crtc_hsync_start =
+ pTimingInfo->crtc_hblank_start + (u32) pDTD->part2.h_sync_off +
+ (dwHSHigh1 << 2);
+
+ /* Horz Sync End = Horz Sync Start + Horz Sync Pulse Width */
+ dwHSHigh2 = (u32) (pDTD->part2.sync_off_width_high & 0x30);
+ pTimingInfo->hsync_end = pTimingInfo->crtc_hsync_end =
+ pTimingInfo->crtc_hsync_start + (u32) pDTD->part2.h_sync_width +
+ (dwHSHigh2 << 4) - 1;
+
+ /* Vert Sync Start = Vert Blank Start + Vert Sync Offset */
+ dwVSHigh1 = (u32) (pDTD->part2.sync_off_width_high & 0x0C);
+ dwVPWLow = (u32) (pDTD->part2.v_sync_off_width & 0xF0);
+
+ pTimingInfo->vsync_start = pTimingInfo->crtc_vsync_start =
+ pTimingInfo->crtc_vblank_start + (dwVPWLow >> 4) + (dwVSHigh1 << 2);
+
+ /* Vert Sync End = Vert Sync Start + Vert Sync Pulse Width */
+ dwVSHigh2 = (u32) (pDTD->part2.sync_off_width_high & 0x03);
+ pTimingInfo->vsync_end = pTimingInfo->crtc_vsync_end =
+ pTimingInfo->crtc_vsync_start +
+ (u32) (pDTD->part2.v_sync_off_width & 0x0F) + (dwVSHigh2 << 4) - 1;
+
+ /* Fillup flags */
+ status = TRUE;
+
+ return status;
+}
+
+static void i830_translate_timing2dtd(struct drm_display_mode * mode, struct intel_sdvo_dtd *dtd)
+{
+ u16 width, height;
+ u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
+ u16 h_sync_offset, v_sync_offset;
+
+ width = mode->crtc_hdisplay;
+ height = mode->crtc_vdisplay;
+
+ /* do some mode translations */
+ h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
+ h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+
+ v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
+ v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+
+ h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
+ v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
+
+ dtd->part1.clock = mode->clock * 1000 / 10000; /*xiaolin, fixme, do i need to by 1k hz */
+ dtd->part1.h_active = width & 0xff;
+ dtd->part1.h_blank = h_blank_len & 0xff;
+ dtd->part1.h_high = (((width >> 8) & 0xf) << 4) |
+ ((h_blank_len >> 8) & 0xf);
+ dtd->part1.v_active = height & 0xff;
+ dtd->part1.v_blank = v_blank_len & 0xff;
+ dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
+ ((v_blank_len >> 8) & 0xf);
+
+ dtd->part2.h_sync_off = h_sync_offset;
+ dtd->part2.h_sync_width = h_sync_len & 0xff;
+ dtd->part2.v_sync_off_width = ((v_sync_offset & 0xf) << 4 |
+ (v_sync_len & 0xf)) + 1;
+ dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
+ ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
+ ((v_sync_len & 0x30) >> 4);
+
+ dtd->part2.dtd_flags = 0x18;
+ if (mode->flags & V_PHSYNC)
+ dtd->part2.dtd_flags |= 0x2;
+ if (mode->flags & V_PVSYNC)
+ dtd->part2.dtd_flags |= 0x4;
+
+ dtd->part2.sdvo_flags = 0;
+ dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
+ dtd->part2.reserved = 0;
+
+}
+
+static bool i830_tv_set_target_io(struct drm_output* output)
+{
+ bool status;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ status = intel_sdvo_set_target_input(output, TRUE, FALSE);
+ if (status)
+ status = intel_sdvo_set_target_output(output, sdvo_priv->active_outputs);
+
+ return status;
+}
+
+static bool i830_tv_get_max_min_dotclock(struct drm_output* output)
+{
+ u32 dwMaxClkRateMul = 1;
+ u32 dwMinClkRateMul = 1;
+ u8 status;
+
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ /* Set Target Input/Outputs */
+ status = i830_tv_set_target_io(output);
+ if (!status) {
+ DRM_DEBUG("SetTargetIO function FAILED!!! \n");
+ return status;
+ }
+
+ /* Get the clock rate multiplies supported by the encoder */
+ dwMinClkRateMul = 1;
+#if 0
+ /* why we need do this, some time, tv can't bring up for the wrong setting in the last time */
+ dwClkRateMulMask = i830_sdvo_get_clock_rate_mult(output);
+
+ /* Find the minimum clock rate multiplier supported */
+
+ if (dwClkRateMulMask & SDVO_CLOCK_RATE_MULT_1X)
+ dwMinClkRateMul = 1;
+ else if (dwClkRateMulMask & SDVO_CLOCK_RATE_MULT_2X)
+ dwMinClkRateMul = 2;
+ else if (dwClkRateMulMask & SDVO_CLOCK_RATE_MULT_3X)
+ dwMinClkRateMul = 3;
+ else if (dwClkRateMulMask & SDVO_CLOCK_RATE_MULT_4X)
+ dwMinClkRateMul = 4;
+ else if (dwClkRateMulMask & SDVO_CLOCK_RATE_MULT_5X)
+ dwMinClkRateMul = 5;
+ else
+ return FALSE;
+#endif
+ /* Get the min and max input Dot Clock supported by the encoder */
+ status = i830_sdvo_get_input_output_pixelclock_range(output, FALSE); /* input */
+
+ if (!status) {
+ DRM_DEBUG("SDVOGetInputPixelClockRange() FAILED!!! \n");
+ return status;
+ }
+
+ /* Get the min and max output Dot Clock supported by the encoder */
+ status = i830_sdvo_get_input_output_pixelclock_range(output, TRUE); /* output */
+
+ if (!status) {
+ DRM_DEBUG("SDVOGetOutputPixelClockRange() FAILED!!! \n");
+ return status;
+ }
+
+ /* Maximum Dot Clock supported should be the minimum of the maximum */
+ /* dot clock supported by the encoder & the SDVO bus clock rate */
+ sdvo_priv->dwMaxDotClk =
+ ((sdvo_priv->dwMaxInDotClk * dwMaxClkRateMul) <
+ (sdvo_priv->dwMaxOutDotClk)) ? (sdvo_priv->dwMaxInDotClk *
+ dwMaxClkRateMul) : (sdvo_priv->dwMaxOutDotClk);
+
+ /* Minimum Dot Clock supported should be the maximum of the minimum */
+ /* dot clocks supported by the input & output */
+ sdvo_priv->dwMinDotClk =
+ ((sdvo_priv->dwMinInDotClk * dwMinClkRateMul) >
+ (sdvo_priv->dwMinOutDotClk)) ? (sdvo_priv->dwMinInDotClk *
+ dwMinClkRateMul) : (sdvo_priv->dwMinOutDotClk);
+
+ DRM_DEBUG("leave, i830_tv_get_max_min_dotclock() !!! \n");
+
+ return TRUE;
+
+}
+
+bool i830_tv_mode_check_support(struct drm_output* output, struct drm_display_mode* pMode)
+{
+ u32 dwDotClk = 0;
+ bool status;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ dwDotClk = pMode->clock * 1000;
+
+ /*TODO: Need to fix this from SoftBios side........ */
+ if (sdvo_priv->TVMode == TVMODE_HDTV) {
+ if (((pMode->hdisplay == 1920) && (pMode->vdisplay== 1080)) ||
+ ((pMode->hdisplay== 1864) && (pMode->vdisplay== 1050)) ||
+ ((pMode->hdisplay== 1704) && (pMode->vdisplay== 960)) ||
+ ((pMode->hdisplay== 640) && (pMode->vdisplay== 448)))
+ return true;
+ }
+
+ if (sdvo_priv->bGetClk) {
+ status = i830_tv_get_max_min_dotclock(output);
+ if (!status) {
+ DRM_DEBUG("get max min dotclok failed\n");
+ return status;
+ }
+ sdvo_priv->bGetClk = false;
+ }
+
+ /* Check the Dot clock first. If the requested Dot Clock should fall */
+ /* in the supported range for the mode to be supported */
+ if ((dwDotClk <= sdvo_priv->dwMinDotClk) || (dwDotClk >= sdvo_priv->dwMaxDotClk)) {
+ DRM_DEBUG("dwDotClk value is out of range\n");
+ /*TODO: now consider VBT add and Remove mode. */
+ /* This mode can't be supported */
+ return false;
+ }
+ DRM_DEBUG("i830_tv_mode_check_support leave\n");
+ return true;
+
+}
+
+void print_Pll(char *prefix, ex_intel_clock_t * clock)
+{
+ DRM_DEBUG("%s: dotclock %d vco %d ((m %d, m1 %d, m2 %d), n %d, (p %d, p1 %d, p2 %d))\n",
+ prefix, clock->dot, clock->vco, clock->m, clock->m1, clock->m2,
+ clock->n, clock->p, clock->p1, clock->p2);
+}
+
+extern int intel_panel_fitter_pipe (struct drm_device *dev);
+extern int intel_get_core_clock_speed(struct drm_device *dev);
+
+void i830_sdvo_tv_settiming(struct drm_crtc *crtc, struct drm_display_mode * mode,
+ struct drm_display_mode * adjusted_mode)
+{
+
+ struct drm_device *dev = crtc->dev;
+ DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private;
+
+ int pipe = 0;
+ int fp_reg = (pipe == 0) ? FPA0 : FPB0;
+ int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+ int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+ int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
+ int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
+ int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
+ int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
+ int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
+ int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
+ int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
+ int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
+ int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
+ int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+ ex_intel_clock_t clock;
+ u32 dpll = 0, fp = 0, dspcntr, pipeconf;
+ bool ok, is_sdvo = FALSE;
+ int centerX = 0, centerY = 0;
+ u32 ulPortMultiplier, ulTemp, ulDotClock;
+ int sdvo_pixel_multiply;
+ u32 dotclock;
+
+ /* Set up some convenient bools for what outputs are connected to
+ * our pipe, used in DPLL setup.
+ */
+ if (!crtc->fb) {
+ DRM_ERROR("Can't set mode without attached fb\n");
+ return;
+ }
+ is_sdvo = TRUE;
+ ok = TRUE;
+ ulDotClock = mode->clock * 1000 / 1000; /*xiaolin, fixme, do i need to by 1k hz */
+ for (ulPortMultiplier = 1; ulPortMultiplier <= 5; ulPortMultiplier++) {
+ ulTemp = ulDotClock * ulPortMultiplier;
+ if ((ulTemp >= 100000) && (ulTemp <= 200000)) {
+ if ((ulPortMultiplier == 3) || (ulPortMultiplier == 5))
+ continue;
+ else
+ break;
+ }
+ }
+ /* ulPortMultiplier is 2, dotclok is 1babc, fall into the first one case */
+ /* add two to each m and n value -- optimizes (slightly) the search algo. */
+ dotclock = ulPortMultiplier * (mode->clock * 1000) / 1000;
+ DRM_DEBUG("mode->clock is %x, dotclock is %x,!\n", mode->clock,dotclock);
+
+ if ((dotclock >= 100000) && (dotclock < 140500)) {
+ DRM_DEBUG("dotclock is between 10000 and 140500!\n");
+ clock.p1 = 0x2;
+ clock.p2 = 0x00;
+ clock.n = 0x3;
+ clock.m1 = 0x10;
+ clock.m2 = 0x8;
+ } else if ((dotclock >= 140500) && (dotclock <= 200000)) {
+
+ DRM_DEBUG("dotclock is between 140500 and 200000!\n");
+ clock.p1 = 0x1;
+ /*CG was using 0x10 from spreadsheet it should be 0 */
+ /*pClock_Data->Clk_P2 = 0x10; */
+ clock.p2 = 0x00;
+ clock.n = 0x6;
+ clock.m1 = 0xC;
+ clock.m2 = 0x8;
+ } else
+ ok = FALSE;
+
+ if (!ok)
+ DRM_DEBUG("Couldn't find PLL settings for mode!\n");
+
+ fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+
+ dpll = DPLL_VGA_MODE_DIS | DPLL_CLOCK_PHASE_9;
+
+ dpll |= DPLLB_MODE_DAC_SERIAL;
+
+ sdvo_pixel_multiply = ulPortMultiplier;
+ dpll |= DPLL_DVO_HIGH_SPEED;
+ dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+
+ /* compute bitmask from p1 value */
+ dpll |= (clock.p1 << 16);
+ dpll |= (clock.p2 << 24);
+
+ dpll |= PLL_REF_INPUT_TVCLKINBC;
+
+ /* Set up the display plane register */
+ dspcntr = DISPPLANE_GAMMA_ENABLE;
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ dspcntr |= DISPPLANE_8BPP;
+ break;
+ case 16:
+ if (crtc->fb->depth == 15)
+ dspcntr |= DISPPLANE_15_16BPP;
+ else
+ dspcntr |= DISPPLANE_16BPP;
+ break;
+ case 32:
+ dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+ break;
+ default:
+ DRM_DEBUG("unknown display bpp\n");
+ }
+
+ if (pipe == 0)
+ dspcntr |= DISPPLANE_SEL_PIPE_A;
+ else
+ dspcntr |= DISPPLANE_SEL_PIPE_B;
+
+ pipeconf = I915_READ(pipeconf_reg);
+ if (pipe == 0) {
+ /* Enable pixel doubling when the dot clock is > 90% of the (display)
+ * core speed.
+ *
+ * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
+ * pipe == 0 check?
+ */
+ if (mode->clock * 1000 > (intel_get_core_clock_speed(dev)) * 9 / 10) /*xiaolin, fixme, do i need to by 1k hz */
+ { pipeconf |= PIPEACONF_DOUBLE_WIDE; DRM_DEBUG("PIPEACONF_DOUBLE_WIDE\n");}
+ else
+ { pipeconf &= ~PIPEACONF_DOUBLE_WIDE; DRM_DEBUG("non PIPEACONF_DOUBLE_WIDE\n");}
+ }
+
+ dspcntr |= DISPLAY_PLANE_ENABLE;
+ pipeconf |= PIPEACONF_ENABLE;
+ dpll |= DPLL_VCO_ENABLE;
+
+ /* Disable the panel fitter if it was on our pipe */
+ if (intel_panel_fitter_pipe(dev) == pipe)
+ I915_WRITE(PFIT_CONTROL, 0);
+
+ print_Pll("chosen", &clock);
+ DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+ drm_mode_debug_printmodeline(dev, mode);
+ DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d\n",
+ mode->mode_id, mode->name, mode->crtc_htotal, mode->crtc_hdisplay,
+ mode->crtc_hblank_end, mode->crtc_hblank_start,
+ mode->crtc_vtotal, mode->crtc_vdisplay,
+ mode->crtc_vblank_end, mode->crtc_vblank_start);
+ DRM_DEBUG("clock regs: 0x%08x, 0x%08x,dspntr is 0x%8x, pipeconf is 0x%8x\n", (int)dpll,
+ (int)fp,(int)dspcntr,(int)pipeconf);
+
+ if (dpll & DPLL_VCO_ENABLE) {
+ I915_WRITE(fp_reg, fp);
+ I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
+ (void)I915_READ(dpll_reg);
+ udelay(150);
+ }
+ I915_WRITE(fp_reg, fp);
+ I915_WRITE(dpll_reg, dpll);
+ (void)I915_READ(dpll_reg);
+ /* Wait for the clocks to stabilize. */
+ udelay(150);
+
+ /* write it again -- the BIOS does, after all */
+ I915_WRITE(dpll_reg, dpll);
+ I915_READ(dpll_reg);
+ /* Wait for the clocks to stabilize. */
+ udelay(150);
+
+ I915_WRITE(htot_reg, (mode->crtc_hdisplay - 1) |
+ ((mode->crtc_htotal - 1) << 16));
+ I915_WRITE(hblank_reg, (mode->crtc_hblank_start - 1) |
+ ((mode->crtc_hblank_end - 1) << 16));
+ I915_WRITE(hsync_reg, (mode->crtc_hsync_start - 1) |
+ ((mode->crtc_hsync_end - 1) << 16));
+ I915_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) |
+ ((mode->crtc_vtotal - 1) << 16));
+ I915_WRITE(vblank_reg, (mode->crtc_vblank_start - 1) |
+ ((mode->crtc_vblank_end - 1) << 16));
+ I915_WRITE(vsync_reg, (mode->crtc_vsync_start - 1) |
+ ((mode->crtc_vsync_end - 1) << 16));
+ I915_WRITE(dspstride_reg, crtc->fb->pitch);
+
+ if (0) {
+
+ centerX = (adjusted_mode->crtc_hdisplay - mode->hdisplay) / 2;
+ centerY = (adjusted_mode->crtc_vdisplay - mode->vdisplay) / 2;
+ I915_WRITE(dspsize_reg,
+ ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
+
+ I915_WRITE(dsppos_reg, centerY << 16 | centerX);
+ I915_WRITE(pipesrc_reg,
+ ((adjusted_mode->crtc_hdisplay -
+ 1) << 16) | (adjusted_mode->crtc_vdisplay - 1));
+ } else {
+ /* pipesrc and dspsize control the size that is scaled from, which should
+ * always be the user's requested size.
+ */
+ I915_WRITE(dspsize_reg,
+ ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
+ I915_WRITE(dsppos_reg, 0);
+ I915_WRITE(pipesrc_reg,
+ ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+
+ }
+ I915_WRITE(pipeconf_reg, pipeconf);
+ I915_READ(pipeconf_reg);
+
+ intel_wait_for_vblank(dev);
+
+ I915_WRITE(dspcntr_reg, dspcntr);
+ /* Flush the plane changes */
+ //intel_pipe_set_base(crtc, 0, 0);
+ /* Disable the VGA plane that we never use */
+ //I915_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+ //intel_wait_for_vblank(dev);
+
+}
+
+static void intel_sdvo_mode_set(struct drm_output *output,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = output->dev;
+ DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = output->crtc;
+ struct intel_crtc *intel_crtc = crtc->driver_private;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ u32 sdvox;
+ struct intel_sdvo_dtd output_dtd;
+ int sdvo_pixel_multiply;
+ bool success;
+ struct drm_display_mode * save_mode;
+ DRM_DEBUG("xxintel_sdvo_mode_set\n");
+
+ if (!mode)
+ return;
+
+ if (sdvo_priv->ActiveDevice == SDVO_DEVICE_TV) {
+ if (!i830_tv_mode_check_support(output, mode)) {
+ DRM_DEBUG("mode setting failed, use the forced mode\n");
+ mode = &tv_modes[0].mode_entry;
+ drm_mode_set_crtcinfo(mode, 0);
+ }
+ }
+ save_mode = mode;
+#if 0
+ width = mode->crtc_hdisplay;
+ height = mode->crtc_vdisplay;
+
+ /* do some mode translations */
+ h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
+ h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+
+ v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
+ v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+
+ h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
+ v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
+
+ 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 = ((h_sync_offset & 0x300) >> 2) |
+ ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
+ ((v_sync_len & 0x30) >> 4);
+
+ output_dtd.part2.dtd_flags = 0x18;
+ if (mode->flags & V_PHSYNC)
+ output_dtd.part2.dtd_flags |= 0x2;
+ if (mode->flags & V_PVSYNC)
+ output_dtd.part2.dtd_flags |= 0x4;
+
+ output_dtd.part2.sdvo_flags = 0;
+ output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0;
+ output_dtd.part2.reserved = 0;
+#else
+ /* disable and enable the display output */
+ intel_sdvo_set_target_output(output, 0);
+
+ //intel_sdvo_set_active_outputs(output, sdvo_priv->active_outputs);
+ memset(&output_dtd, 0, sizeof(struct intel_sdvo_dtd));
+ /* check if this mode can be supported or not */
+
+ i830_translate_timing2dtd(mode, &output_dtd);
+#endif
+ intel_sdvo_set_target_output(output, 0);
+ /* set the target input & output first */
+ /* Set the input timing to the screen. Assume always input 0. */
+ intel_sdvo_set_target_output(output, sdvo_priv->active_outputs);
+ intel_sdvo_set_output_timing(output, &output_dtd);
+ intel_sdvo_set_target_input(output, true, false);
+
+ if (sdvo_priv->ActiveDevice == SDVO_DEVICE_TV) {
+ i830_tv_set_overscan_parameters(output);
+ /* Set TV standard */
+ #if 0
+ if (sdvo_priv->TVMode == TVMODE_HDTV)
+ i830_sdvo_map_hdtvstd_bitmask(output);
+ else
+ i830_sdvo_map_sdtvstd_bitmask(output);
+ #endif
+ /* Set TV format */
+ i830_sdvo_set_tvoutputs_formats(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.
+ */
+ success = i830_sdvo_create_preferred_input_timing(output, mode);
+ if (success) {
+ i830_sdvo_get_preferred_input_timing(output, &output_dtd);
+ }
+ /* Set the overscan values now as input timing is dependent on overscan values */
+
+ }
+
+
+ /* 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 = intel_sdvo_create_preferred_input_timing(output, clock,
+ width, height);
+ if (success) {
+ struct intel_sdvo_dtd *input_dtd;
+
+ intel_sdvo_get_preferred_input_timing(output, &input_dtd);
+ intel_sdvo_set_input_timing(output, &input_dtd);
+ }
+#else
+ /* Set input timing (in DTD) */
+ intel_sdvo_set_input_timing(output, &output_dtd);
+#endif
+ if (sdvo_priv->ActiveDevice == SDVO_DEVICE_TV) {
+
+ DRM_DEBUG("xxintel_sdvo_mode_set tv path\n");
+ i830_tv_program_display_params(output);
+ /* translate dtd 2 timing */
+ i830_translate_dtd2timing(mode, &output_dtd);
+ /* Program clock rate multiplier, 2x,clock is = 0x360b730 */
+ if ((mode->clock * 1000 >= 24000000)
+ && (mode->clock * 1000 < 50000000)) {
+ intel_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_4X);
+ } else if ((mode->clock * 1000 >= 50000000)
+ && (mode->clock * 1000 < 100000000)) {
+ intel_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_2X);
+ } else if ((mode->clock * 1000 >= 100000000)
+ && (mode->clock * 1000 < 200000000)) {
+ intel_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_1X);
+ } else
+ DRM_DEBUG("i830_sdvo_set_clock_rate is failed\n");
+
+ i830_sdvo_tv_settiming(output->crtc, mode, adjusted_mode);
+ //intel_crtc_mode_set(output->crtc, mode,adjusted_mode,0,0);
+ mode = save_mode;
+ } else {
+ DRM_DEBUG("xxintel_sdvo_mode_set - non tv path\n");
+ switch (intel_sdvo_get_pixel_multiplier(mode)) {
+ case 1:
+ intel_sdvo_set_clock_rate_mult(output,
+ SDVO_CLOCK_RATE_MULT_1X);
+ break;
+ case 2:
+ intel_sdvo_set_clock_rate_mult(output,
+ SDVO_CLOCK_RATE_MULT_2X);
+ break;
+ case 4:
+ intel_sdvo_set_clock_rate_mult(output,
+ SDVO_CLOCK_RATE_MULT_4X);
+ break;
+ }
+ }
+ /* Set the SDVO control regs. */
+ if (0/*IS_I965GM(dev)*/) {
+ sdvox = SDVO_BORDER_ENABLE;
+ } else {
+ sdvox = I915_READ(sdvo_priv->output_device);
+ switch (sdvo_priv->output_device) {
+ case SDVOB:
+ sdvox &= SDVOB_PRESERVE_MASK;
+ break;
+ case SDVOC:
+ sdvox &= SDVOC_PRESERVE_MASK;
+ break;
+ }
+ sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
+ }
+ if (intel_crtc->pipe == 1)
+ sdvox |= SDVO_PIPE_B_SELECT;
+
+ sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
+ if (IS_I965G(dev)) {
+ /* done in crtc_mode_set as the dpll_md reg must be written
+ early */
+ } else if (IS_POULSBO(dev) || IS_I945G(dev) || IS_I945GM(dev)) {
+ /* done in crtc_mode_set as it lives inside the
+ dpll register */
+ } else {
+ sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+ }
+
+ intel_sdvo_write_sdvox(output, sdvox);
+ i830_sdvo_set_iomap(output);
+}
+
+static void intel_sdvo_dpms(struct drm_output *output, int mode)
+{
+ struct drm_device *dev = output->dev;
+ DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ u32 temp;
+
+ DRM_DEBUG("xxintel_sdvo_dpms, dpms mode is %d, active output is %d\n",mode,sdvo_priv->active_outputs);
+
+#ifdef SII_1392_WA
+ if((SII_1392==1) && (drm_psb_no_fb ==1)) {
+ DRM_DEBUG("don't touch 1392 card when no_fb=1\n");
+ return;
+ }
+#endif
+
+ if (mode != DPMSModeOn) {
+ intel_sdvo_set_active_outputs(output, sdvo_priv->output_device);
+ if (0)
+ intel_sdvo_set_encoder_power_state(output, mode);
+
+ if (mode == DPMSModeOff) {
+ temp = I915_READ(sdvo_priv->output_device);
+ if ((temp & SDVO_ENABLE) != 0) {
+ intel_sdvo_write_sdvox(output, temp & ~SDVO_ENABLE);
+ }
+ }
+ } else {
+ bool input1, input2;
+ int i;
+ u8 status;
+
+ temp = I915_READ(sdvo_priv->output_device);
+ if ((temp & SDVO_ENABLE) == 0)
+ intel_sdvo_write_sdvox(output, temp | SDVO_ENABLE);
+ for (i = 0; i < 2; i++)
+ intel_wait_for_vblank(dev);
+
+ status = intel_sdvo_get_trained_inputs(output, &input1,
+ &input2);
+
+
+ /* Warn if the device reported failure to sync.
+ * A lot of SDVO devices fail to notify of sync, but it's
+ * a given it the status is a success, we succeeded.
+ */
+ if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
+ DRM_DEBUG("First %s output reported failure to sync\n",
+ SDVO_NAME(sdvo_priv));
+ }
+
+ if (0)
+ intel_sdvo_set_encoder_power_state(output, mode);
+
+ DRM_DEBUG("xiaolin active output is %d\n",sdvo_priv->active_outputs);
+ intel_sdvo_set_active_outputs(output, sdvo_priv->active_outputs);
+ }
+ return;
+}
+
+static void intel_sdvo_save(struct drm_output *output)
+{
+ struct drm_device *dev = output->dev;
+ DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ DRM_DEBUG("xxintel_sdvo_save\n");
+
+ sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(output);
+ intel_sdvo_get_active_outputs(output, &sdvo_priv->save_active_outputs);
+
+ if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+ intel_sdvo_set_target_input(output, true, false);
+ intel_sdvo_get_input_timing(output,
+ &sdvo_priv->save_input_dtd_1);
+ }
+
+ if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+ intel_sdvo_set_target_input(output, false, true);
+ intel_sdvo_get_input_timing(output,
+ &sdvo_priv->save_input_dtd_2);
+ }
+
+ intel_sdvo_set_target_output(output, sdvo_priv->active_outputs);
+ intel_sdvo_get_output_timing(output,
+ &sdvo_priv->save_output_dtd[sdvo_priv->active_outputs]);
+ sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device);
+}
+
+static void intel_sdvo_restore(struct drm_output *output)
+{
+ struct drm_device *dev = output->dev;
+ DRM_DRIVER_PRIVATE_T *dev_priv = dev->dev_private;
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ int i;
+ bool input1, input2;
+ u8 status;
+ DRM_DEBUG("xxintel_sdvo_restore\n");
+
+ intel_sdvo_set_active_outputs(output, 0);
+
+ intel_sdvo_set_target_output(output, sdvo_priv->save_active_outputs);
+ intel_sdvo_set_output_timing(output,
+ &sdvo_priv->save_output_dtd[sdvo_priv->save_active_outputs]);
+ if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+ intel_sdvo_set_target_input(output, true, false);
+ intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_1);
+ }
+
+ if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+ intel_sdvo_set_target_input(output, false, true);
+ intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_2);
+ }
+
+ intel_sdvo_set_clock_rate_mult(output, sdvo_priv->save_sdvo_mult);
+
+ I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX);
+
+ if (sdvo_priv->save_SDVOX & SDVO_ENABLE)
+ {
+ for (i = 0; i < 2; i++)
+ intel_wait_for_vblank(dev);
+ status = intel_sdvo_get_trained_inputs(output, &input1, &input2);
+ if (status == SDVO_CMD_STATUS_SUCCESS && !input1)
+ DRM_DEBUG("First %s output reported failure to sync\n",
+ SDVO_NAME(sdvo_priv));
+ }
+
+ i830_sdvo_set_iomap(output);
+ intel_sdvo_set_active_outputs(output, sdvo_priv->save_active_outputs);
+}
+
+static bool i830_tv_mode_find(struct drm_output * output,struct drm_display_mode * pMode)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ bool find = FALSE;
+ int i;
+
+ DRM_DEBUG("i830_tv_mode_find,0x%x\n", sdvo_priv->TVStandard);
+
+ for (i = 0; i < NUM_TV_MODES; i++)
+ {
+ const tv_mode_t *tv_mode = &tv_modes[i];
+ if (strcmp (tv_mode->mode_entry.name, pMode->name) == 0
+ && (pMode->type & M_T_TV)) {
+ find = TRUE;
+ break;
+ }
+ }
+ return find;
+}
+
+
+static int intel_sdvo_mode_valid(struct drm_output *output,
+ struct drm_display_mode *mode)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ bool status = TRUE;
+ DRM_DEBUG("xxintel_sdvo_mode_valid\n");
+
+ if (sdvo_priv->ActiveDevice == SDVO_DEVICE_TV) {
+ status = i830_tv_mode_check_support(output, mode);
+ if (status) {
+ if(i830_tv_mode_find(output,mode)) {
+ DRM_DEBUG("%s is ok\n", mode->name);
+ return MODE_OK;
+ }
+ else
+ return MODE_CLOCK_RANGE;
+ } else {
+ DRM_DEBUG("%s is failed\n",
+ mode->name);
+ return MODE_CLOCK_RANGE;
+ }
+ }
+
+ if (mode->flags & V_DBLSCAN)
+ return MODE_NO_DBLESCAN;
+
+ if (sdvo_priv->pixel_clock_min > mode->clock)
+ return MODE_CLOCK_LOW;
+
+ if (sdvo_priv->pixel_clock_max < mode->clock)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_sdvo_caps *caps)
+{
+ u8 status;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0);
+ status = intel_sdvo_read_response(output, caps, sizeof(*caps));
+ if (status != SDVO_CMD_STATUS_SUCCESS)
+ return false;
+
+ return true;
+}
+
+void i830_tv_get_default_params(struct drm_output * output)
+{
+ u32 dwSupportedSDTVBitMask = 0;
+ u32 dwSupportedHDTVBitMask = 0;
+ u32 dwTVStdBitmask = 0;
+
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+
+ /* Get supported TV Standard */
+ i830_sdvo_get_supported_tvoutput_formats(output, &dwSupportedSDTVBitMask,
+ &dwSupportedHDTVBitMask,&dwTVStdBitmask);
+
+ sdvo_priv->dwSDVOSDTVBitMask = dwSupportedSDTVBitMask;
+ sdvo_priv->dwSDVOHDTVBitMask = dwSupportedHDTVBitMask;
+ sdvo_priv->TVStdBitmask = dwTVStdBitmask;
+
+}
+
+static enum drm_output_status intel_sdvo_detect(struct drm_output *output)
+{
+ u8 response[2];
+ u8 status;
+ u8 count = 5;
+
+ char deviceName[256];
+ char *name_suffix;
+ char *name_prefix;
+ unsigned char bytes[2];
+
+ struct drm_device *dev = output->dev;
+
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ DRM_DEBUG("xxintel_sdvo_detect\n");
+ intel_sdvo_dpms(output, DPMSModeOn);
+
+ if (!intel_sdvo_get_capabilities(output, &sdvo_priv->caps)) {
+ /*No SDVO support, power down the pipe */
+ intel_sdvo_dpms(output, DPMSModeOff);
+ return output_status_disconnected;
+ }
+
+#ifdef SII_1392_WA
+ if ((sdvo_priv->caps.vendor_id == 0x04) && (sdvo_priv->caps.device_id==0xAE)){
+ /*Leave the control of 1392 to X server*/
+ SII_1392=1;
+ printk("%s: detect 1392 card, leave the setting to up level\n", __FUNCTION__);
+ if (drm_psb_no_fb == 0)
+ intel_sdvo_dpms(output, DPMSModeOff);
+ return output_status_disconnected;
+ }
+#endif
+ while (count--) {
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+ status = intel_sdvo_read_response(output, &response, 2);
+
+ if(count >3 && status == SDVO_CMD_STATUS_PENDING) {
+ intel_sdvo_write_cmd(output,SDVO_CMD_RESET,NULL,0);
+ intel_sdvo_read_response(output, &response, 2);
+ continue;
+ }
+
+ if ((status != SDVO_CMD_STATUS_SUCCESS) || (response[0] == 0 && response[1] == 0)) {
+ udelay(500);
+ continue;
+ } else
+ break;
+ }
+ if (response[0] != 0 || response[1] != 0) {
+ /*Check what device types are connected to the hardware CRT/HDTV/S-Video/Composite */
+ /*in case of CRT and multiple TV's attached give preference in the order mentioned below */
+ /* 1. RGB */
+ /* 2. HDTV */
+ /* 3. S-Video */
+ /* 4. composite */
+ if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "TMDS";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_TMDS;
+ } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "TMDS";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_TMDS;
+ } else if (response[0] & SDVO_OUTPUT_RGB0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "RGB0";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_CRT;
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_RGB1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "RGB1";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_CRT;
+ } else if (response[0] & SDVO_OUTPUT_YPRPB0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_YPRPB0;
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_YPRPB1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_YPRPB1;
+ }
+ /* SCART is given Second preference */
+ else if (response[0] & SDVO_OUTPUT_SCART0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SCART0;
+
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_SCART1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SCART1;
+ }
+ /* if S-Video type TV is connected along with Composite type TV give preference to S-Video */
+ else if (response[0] & SDVO_OUTPUT_SVID0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SVID0;
+
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_SVID1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SVID1;
+ }
+ /* Composite is given least preference */
+ else if (response[0] & SDVO_OUTPUT_CVBS0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_CVBS0;
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_CVBS1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_CVBS1;
+ } else {
+ DRM_DEBUG("no display attached\n");
+
+ memcpy(bytes, &sdvo_priv->caps.output_flags, 2);
+ DRM_DEBUG("%s: No active TMDS or RGB outputs (0x%02x%02x) 0x%08x\n",
+ SDVO_NAME(sdvo_priv), bytes[0], bytes[1],
+ sdvo_priv->caps.output_flags);
+ name_prefix = "Unknown";
+ }
+
+ /* init para for TV connector */
+ if (sdvo_priv->active_outputs & SDVO_OUTPUT_TV0) {
+ DRM_INFO("TV is attaced\n");
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "TV0";
+ /* Init TV mode setting para */
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_TV;
+ sdvo_priv->bGetClk = TRUE;
+ if (sdvo_priv->active_outputs == SDVO_OUTPUT_YPRPB0 ||
+ sdvo_priv->active_outputs == SDVO_OUTPUT_YPRPB1) {
+ /*sdvo_priv->TVStandard = HDTV_SMPTE_274M_1080i60;*/
+ sdvo_priv->TVMode = TVMODE_HDTV;
+ } else {
+ /*sdvo_priv->TVStandard = TVSTANDARD_NTSC_M;*/
+ sdvo_priv->TVMode = TVMODE_SDTV;
+ }
+
+ /*intel_output->pDevice->TVEnabled = TRUE;*/
+
+ i830_tv_get_default_params(output);
+ /*Init Display parameter for TV */
+ sdvo_priv->OverScanX.Value = 0xffffffff;
+ sdvo_priv->OverScanY.Value = 0xffffffff;
+ sdvo_priv->dispParams.Brightness.Value = 0x80;
+ sdvo_priv->dispParams.FlickerFilter.Value = 0xffffffff;
+ sdvo_priv->dispParams.AdaptiveFF.Value = 7;
+ sdvo_priv->dispParams.TwoD_FlickerFilter.Value = 0xffffffff;
+ sdvo_priv->dispParams.Contrast.Value = 0x40;
+ sdvo_priv->dispParams.PositionX.Value = 0x200;
+ sdvo_priv->dispParams.PositionY.Value = 0x200;
+ sdvo_priv->dispParams.DotCrawl.Value = 1;
+ sdvo_priv->dispParams.ChromaFilter.Value = 1;
+ sdvo_priv->dispParams.LumaFilter.Value = 2;
+ sdvo_priv->dispParams.Sharpness.Value = 4;
+ sdvo_priv->dispParams.Saturation.Value = 0x45;
+ sdvo_priv->dispParams.Hue.Value = 0x40;
+ sdvo_priv->dispParams.Dither.Value = 0;
+
+ }
+ else {
+ name_prefix = "RGB0";
+ DRM_INFO("non TV is attaced\n");
+ }
+ if (sdvo_priv->output_device == SDVOB) {
+ name_suffix = "-1";
+ } else {
+ name_suffix = "-2";
+ }
+
+ strcpy(deviceName, name_prefix);
+ strcat(deviceName, name_suffix);
+
+ if(output->name && (strcmp(output->name,deviceName) != 0)){
+ DRM_DEBUG("change the output name to %s\n", deviceName);
+ if (!drm_output_rename(output, deviceName)) {
+ drm_output_destroy(output);
+ return output_status_disconnected;
+ }
+
+ }
+ i830_sdvo_set_iomap(output);
+
+ DRM_INFO("get attached displays=0x%x,0x%x,connectedouputs=0x%x\n",
+ response[0], response[1], sdvo_priv->active_outputs);
+ return output_status_connected;
+ } else {
+ /*No SDVO display device attached */
+ intel_sdvo_dpms(output, DPMSModeOff);
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_NONE;
+ return output_status_disconnected;
+ }
+}
+
+static int i830_sdvo_get_tvmode_from_table(struct drm_output *output)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct drm_device *dev = output->dev;
+
+ int i, modes = 0;
+
+ for (i = 0; i < NUM_TV_MODES; i++)
+ if (((sdvo_priv->TVMode == TVMODE_HDTV) && /*hdtv mode list */
+ (tv_modes[i].dwSupportedHDTVvss & TVSTANDARD_HDTV_ALL)) ||
+ ((sdvo_priv->TVMode == TVMODE_SDTV) && /*sdtv mode list */
+ (tv_modes[i].dwSupportedSDTVvss & TVSTANDARD_SDTV_ALL))) {
+ struct drm_display_mode *newmode;
+ newmode = drm_mode_duplicate(dev, &tv_modes[i].mode_entry);
+ drm_mode_set_crtcinfo(newmode,0);
+ drm_mode_probed_add(output, newmode);
+ modes++;
+ }
+
+ return modes;
+
+}
+
+static int intel_sdvo_get_modes(struct drm_output *output)
+{
+ struct intel_output *intel_output = output->driver_private;
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+ DRM_DEBUG("xxintel_sdvo_get_modes\n");
+
+ if (sdvo_priv->ActiveDevice == SDVO_DEVICE_TV) {
+ DRM_DEBUG("SDVO_DEVICE_TV\n");
+ i830_sdvo_get_tvmode_from_table(output);
+ if (list_empty(&output->probed_modes))
+ return 0;
+ return 1;
+
+ } else {
+ /* set the bus switch and get the modes */
+ intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2);
+ intel_ddc_get_modes(output);
+
+ if (list_empty(&output->probed_modes))
+ return 0;
+ return 1;
+ }
+#if 0
+ /* Mac mini hack. On this device, I get DDC through the analog, which
+ * load-detects as disconnected. I fail to DDC through the SDVO DDC,
+ * but it does load-detect as connected. So, just steal the DDC bits
+ * from analog when we fail at finding it the right way.
+ */
+ /* TODO */
+ return NULL;
+
+ return NULL;
+#endif
+}
+
+static void intel_sdvo_destroy(struct drm_output *output)
+{
+ struct intel_output *intel_output = output->driver_private;
+ DRM_DEBUG("xxintel_sdvo_destroy\n");
+
+ if (intel_output->i2c_bus)
+ intel_i2c_destroy(intel_output->i2c_bus);
+
+ if (intel_output) {
+ kfree(intel_output);
+ output->driver_private = NULL;
+ }
+}
+
+static const struct drm_output_funcs intel_sdvo_output_funcs = {
+ .dpms = intel_sdvo_dpms,
+ .save = intel_sdvo_save,
+ .restore = intel_sdvo_restore,
+ .mode_valid = intel_sdvo_mode_valid,
+ .mode_fixup = intel_sdvo_mode_fixup,
+ .prepare = intel_output_prepare,
+ .mode_set = intel_sdvo_mode_set,
+ .commit = intel_output_commit,
+ .detect = intel_sdvo_detect,
+ .get_modes = intel_sdvo_get_modes,
+ .cleanup = intel_sdvo_destroy
+};
+
+extern char hotplug_env;
+static int intel_sdvo_proc_read_hotplug(char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+ memset(buf, 0, count);
+
+ if (count < 1)
+ return 0;
+
+ wait_event_interruptible(hotplug_queue, hotplug_env == '1');
+ buf[0] = hotplug_env;
+
+ return count;
+}
+
+static int intel_sdvo_proc_write_hotplug(struct file *file, const char * user_buffer, unsigned long count, void *data)
+{
+ hotplug_env = '0';
+ return count;
+}
+
+void intel_sdvo_init(struct drm_device *dev, int output_device)
+{
+ struct drm_output *output;
+ struct intel_output *intel_output;
+ struct intel_sdvo_priv *sdvo_priv;
+ struct intel_i2c_chan *i2cbus = NULL;
+ u8 ch[0x40];
+ int i;
+ char name[DRM_OUTPUT_LEN];
+ char *name_prefix;
+ char *name_suffix;
+
+ int count = 3;
+ u8 response[2];
+ u8 status;
+ unsigned char bytes[2];
+
+ struct proc_dir_entry *ent;
+ char name_hotplug[64] = "dri/sdvo";
+ char name_file[64] = "hotplug";
+
+ DRM_DEBUG("xxintel_sdvo_init\n");
+
+ init_waitqueue_head(&hotplug_queue);
+
+ if (IS_POULSBO(dev)) {
+ struct pci_dev * pci_root = pci_get_bus_and_slot(0, 0);
+ u32 sku_value = 0;
+ bool sku_bSDVOEnable = true;
+ if(pci_root)
+ {
+ pci_write_config_dword(pci_root, 0xD0, PCI_PORT5_REG80_FFUSE);
+ pci_read_config_dword(pci_root, 0xD4, &sku_value);
+ sku_bSDVOEnable = (sku_value & PCI_PORT5_REG80_SDVO_DISABLE)?false : true;
+ DRM_INFO("intel_sdvo_init: sku_value is 0x%08x\n", sku_value);
+ DRM_INFO("intel_sdvo_init: sku_bSDVOEnable is %d\n", sku_bSDVOEnable);
+ if (sku_bSDVOEnable == false)
+ return;
+ }
+ }
+
+ output = drm_output_create(dev, &intel_sdvo_output_funcs, NULL);
+ if (!output)
+ return;
+
+ intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
+ if (!intel_output) {
+ drm_output_destroy(output);
+ return;
+ }
+
+ sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
+ intel_output->type = INTEL_OUTPUT_SDVO;
+ output->driver_private = intel_output;
+ output->interlace_allowed = 0;
+ output->doublescan_allowed = 0;
+
+ /* setup the DDC bus. */
+ if (output_device == SDVOB)
+ i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+ else
+ i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+
+ if (i2cbus == NULL) {
+ drm_output_destroy(output);
+ return;
+ }
+
+ sdvo_priv->i2c_bus = i2cbus;
+
+ if (output_device == SDVOB) {
+ name_suffix = "-1";
+ sdvo_priv->i2c_bus->slave_addr = 0x38;
+ sdvo_priv->byInputWiring = SDVOB_IN0;
+ } else {
+ name_suffix = "-2";
+ sdvo_priv->i2c_bus->slave_addr = 0x39;
+ }
+
+ sdvo_priv->output_device = output_device;
+ intel_output->i2c_bus = i2cbus;
+ intel_output->dev_priv = sdvo_priv;
+
+
+ /* Read the regs to test if we can talk to the device */
+ for (i = 0; i < 0x40; i++) {
+ if (!intel_sdvo_read_byte(output, i, &ch[i])) {
+ DRM_DEBUG("No SDVO device found on SDVO%c\n",
+ output_device == SDVOB ? 'B' : 'C');
+ drm_output_destroy(output);
+ return;
+ }
+ }
+
+
+ proc_sdvo_dir = proc_mkdir(name_hotplug, NULL);
+ if (!proc_sdvo_dir) {
+ printk("create /proc/dri/sdvo folder error\n");
+ }
+
+ ent = create_proc_entry(name_file,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, proc_sdvo_dir);
+ if (!ent) {
+ printk("create /proc/dri/sdvo/hotplug error\n");
+ }
+
+ ent->read_proc = intel_sdvo_proc_read_hotplug;
+ ent->write_proc = intel_sdvo_proc_write_hotplug;
+ ent->data = dev;
+
+ intel_sdvo_get_capabilities(output, &sdvo_priv->caps);
+
+ // Set active hot-plug OpCode.
+ uint8_t state_orig;
+ uint8_t state_set;
+ uint8_t byArgs_orig[2];
+ uint8_t byArgs_set[2];
+ uint32_t value;
+
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+ state_orig = intel_sdvo_read_response(output, byArgs_orig, 2);
+
+ value = (uint32_t)byArgs_orig[1];
+ value = (value << 8);
+ value |= (uint32_t)byArgs_orig[0];
+
+ value = value | (0x1);
+
+ byArgs_orig[0] = (uint8_t)(value & 0xFF);
+ byArgs_orig[1] = (uint8_t)((value >> 8) & 0xFF);
+ intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, byArgs_orig, 2);
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+ state_set = intel_sdvo_read_response(output, byArgs_set, 2);
+
+#ifdef SII_1392_WA
+ if ((sdvo_priv->caps.vendor_id == 0x04) && (sdvo_priv->caps.device_id==0xAE)){
+ /*Leave the control of 1392 to X server*/
+ SII_1392=1;
+ printk("%s: detect 1392 card, leave the setting to up level\n", __FUNCTION__);
+ if (drm_psb_no_fb == 0)
+ intel_sdvo_dpms(output, DPMSModeOff);
+ sdvo_priv->active_outputs = 0;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "SDVO";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_NONE;
+ strcpy(name, name_prefix);
+ strcat(name, name_suffix);
+ if (!drm_output_rename(output, name)) {
+ drm_output_destroy(output);
+ return;
+ }
+ return;
+ }
+#endif
+ memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs));
+
+ while (count--) {
+ intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+ status = intel_sdvo_read_response(output, &response, 2);
+
+ if (status != SDVO_CMD_STATUS_SUCCESS) {
+ udelay(1000);
+ continue;
+ }
+ if (status == SDVO_CMD_STATUS_SUCCESS)
+ break;
+ }
+ if (response[0] != 0 || response[1] != 0) {
+ /*Check what device types are connected to the hardware CRT/HDTV/S-Video/Composite */
+ /*in case of CRT and multiple TV's attached give preference in the order mentioned below */
+ /* 1. RGB */
+ /* 2. HDTV */
+ /* 3. S-Video */
+ /* 4. composite */
+ if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "TMDS";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_TMDS;
+ } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "TMDS";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_TMDS;
+ } else if (response[0] & SDVO_OUTPUT_RGB0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "RGB0";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_CRT;
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_RGB1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "RGB1";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_CRT;
+ } else if (response[0] & SDVO_OUTPUT_YPRPB0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_YPRPB0;
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_YPRPB1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_YPRPB1;
+ }
+ /* SCART is given Second preference */
+ else if (response[0] & SDVO_OUTPUT_SCART0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SCART0;
+
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_SCART1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SCART1;
+ }
+ /* if S-Video type TV is connected along with Composite type TV give preference to S-Video */
+ else if (response[0] & SDVO_OUTPUT_SVID0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SVID0;
+
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_SVID1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_SVID1;
+ }
+ /* Composite is given least preference */
+ else if (response[0] & SDVO_OUTPUT_CVBS0) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_CVBS0;
+ } else if ((response[1] << 8 | response[0]) & SDVO_OUTPUT_CVBS1) {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_CVBS1;
+ } else {
+ DRM_DEBUG("no display attached\n");
+
+ memcpy(bytes, &sdvo_priv->caps.output_flags, 2);
+ DRM_INFO("%s: No active TMDS or RGB outputs (0x%02x%02x) 0x%08x\n",
+ SDVO_NAME(sdvo_priv), bytes[0], bytes[1],
+ sdvo_priv->caps.output_flags);
+ name_prefix = "Unknown";
+ }
+
+ /* init para for TV connector */
+ if (sdvo_priv->active_outputs & SDVO_OUTPUT_TV0) {
+ DRM_INFO("TV is attaced\n");
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "TV0";
+ /* Init TV mode setting para */
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_TV;
+ sdvo_priv->bGetClk = TRUE;
+ if (sdvo_priv->active_outputs == SDVO_OUTPUT_YPRPB0 ||
+ sdvo_priv->active_outputs == SDVO_OUTPUT_YPRPB1) {
+ sdvo_priv->TVStandard = HDTV_SMPTE_274M_1080i60;
+ sdvo_priv->TVMode = TVMODE_HDTV;
+ } else {
+ sdvo_priv->TVStandard = TVSTANDARD_NTSC_M;
+ sdvo_priv->TVMode = TVMODE_SDTV;
+ }
+ /*intel_output->pDevice->TVEnabled = TRUE;*/
+ /*Init Display parameter for TV */
+ sdvo_priv->OverScanX.Value = 0xffffffff;
+ sdvo_priv->OverScanY.Value = 0xffffffff;
+ sdvo_priv->dispParams.Brightness.Value = 0x80;
+ sdvo_priv->dispParams.FlickerFilter.Value = 0xffffffff;
+ sdvo_priv->dispParams.AdaptiveFF.Value = 7;
+ sdvo_priv->dispParams.TwoD_FlickerFilter.Value = 0xffffffff;
+ sdvo_priv->dispParams.Contrast.Value = 0x40;
+ sdvo_priv->dispParams.PositionX.Value = 0x200;
+ sdvo_priv->dispParams.PositionY.Value = 0x200;
+ sdvo_priv->dispParams.DotCrawl.Value = 1;
+ sdvo_priv->dispParams.ChromaFilter.Value = 1;
+ sdvo_priv->dispParams.LumaFilter.Value = 2;
+ sdvo_priv->dispParams.Sharpness.Value = 4;
+ sdvo_priv->dispParams.Saturation.Value = 0x45;
+ sdvo_priv->dispParams.Hue.Value = 0x40;
+ sdvo_priv->dispParams.Dither.Value = 0;
+ }
+ else {
+ name_prefix = "RGB0";
+ DRM_INFO("non TV is attaced\n");
+ }
+
+ strcpy(name, name_prefix);
+ strcat(name, name_suffix);
+ if (!drm_output_rename(output, name)) {
+ drm_output_destroy(output);
+ return;
+ }
+ } else {
+ /*No SDVO display device attached */
+ intel_sdvo_dpms(output, DPMSModeOff);
+ sdvo_priv->active_outputs = 0;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix = "SDVO";
+ sdvo_priv->ActiveDevice = SDVO_DEVICE_NONE;
+ strcpy(name, name_prefix);
+ strcat(name, name_suffix);
+ if (!drm_output_rename(output, name)) {
+ drm_output_destroy(output);
+ return;
+ }
+
+ }
+
+ /*(void)intel_sdvo_set_active_outputs(output, sdvo_priv->active_outputs);*/
+
+ /* Set the input timing to the screen. Assume always input 0. */
+ intel_sdvo_set_target_input(output, true, false);
+
+ intel_sdvo_get_input_pixel_clock_range(output,
+ &sdvo_priv->pixel_clock_min,
+ &sdvo_priv->pixel_clock_max);
+
+
+ DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, "
+ "clock range %dMHz - %dMHz, "
+ "input 1: %c, input 2: %c, "
+ "output 1: %c, output 2: %c\n",
+ SDVO_NAME(sdvo_priv),
+ sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
+ sdvo_priv->caps.device_rev_id,
+ sdvo_priv->pixel_clock_min / 1000,
+ sdvo_priv->pixel_clock_max / 1000,
+ (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
+ (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+ /* check currently supported outputs */
+ sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
+ sdvo_priv->caps.output_flags &
+ (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
+
+ intel_output->ddc_bus = i2cbus;
+}