From patchwork Tue Mar 9 02:21:58 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhenyu Wang X-Patchwork-Id: 84212 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o292O7oc010651 for ; Tue, 9 Mar 2010 02:24:44 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C2B519ED4B; Mon, 8 Mar 2010 18:24:06 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from azsmga101.ch.intel.com (mga07.intel.com [143.182.124.22]) by gabe.freedesktop.org (Postfix) with ESMTP id 4FBEB9EED1 for ; Mon, 8 Mar 2010 18:24:02 -0800 (PST) Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga101.ch.intel.com with ESMTP; 08 Mar 2010 18:24:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.49,605,1262592000"; d="scan'208";a="252355287" Received: from debian-t61.sh.intel.com (HELO localhost.localdomain) ([10.239.36.141]) by azsmga001.ch.intel.com with ESMTP; 08 Mar 2010 18:24:00 -0800 From: Zhenyu Wang To: eric@anholt.net Date: Tue, 9 Mar 2010 10:21:58 +0800 Message-Id: <1268101319-4841-4-git-send-email-zhenyuw@linux.intel.com> X-Mailer: git-send-email 1.7.0 In-Reply-To: <1268101319-4841-1-git-send-email-zhenyuw@linux.intel.com> References: <1268101319-4841-1-git-send-email-zhenyuw@linux.intel.com> Cc: intel-gfx@lists.freedesktop.org Subject: [Intel-gfx] [PATCH 3/4] drm/i915: implement multifunction SDVO device support X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 09 Mar 2010 02:24:44 +0000 (UTC) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 60057eb..6181594 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -36,6 +36,17 @@ #include "i915_drv.h" #include "intel_sdvo_regs.h" +#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1) +#define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1) +#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1) +#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0) + +#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\ + SDVO_TV_MASK) + +#define SDVO_CONNECTOR_IS_TV(c) (c->output_flag & SDVO_TV_MASK) +#define SDVO_CONNECTOR_IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) + static char *tv_format_names[] = { "NTSC_M" , "NTSC_J" , "NTSC_443", "PAL_B" , "PAL_D" , "PAL_G" , @@ -48,7 +59,7 @@ static char *tv_format_names[] = { #define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names)) -struct intel_sdvo_priv { +struct intel_sdvo_encoder { u8 slave_addr; /* Register for the SDVO device: SDVOB or SDVOC */ @@ -72,6 +83,9 @@ struct intel_sdvo_priv { */ uint16_t attached_output; + /* DDC bus used by this SDVO output */ + uint8_t ddc_bus; + /** * This is set if we're going to treat the device as TV-out. * @@ -81,15 +95,6 @@ struct intel_sdvo_priv { */ bool is_tv; - /* This is for current tv format name */ - char *tv_format_name; - - /* This contains all current supported TV format */ - char *tv_format_supported[TV_FORMAT_NUM]; - int format_supported_num; - struct drm_property *tv_format_property; - struct drm_property *tv_format_name_property[TV_FORMAT_NUM]; - /** * This is set if we treat the device as HDMI, instead of DVI. */ @@ -101,38 +106,50 @@ struct intel_sdvo_priv { bool is_lvds; /** - * This is sdvo flags for input timing. - */ - uint8_t sdvo_flags; - - /** * This is sdvo fixed pannel mode pointer */ struct drm_display_mode *sdvo_lvds_fixed_mode; - /** - * Returned SDTV resolutions allowed for the current format, if the - * device reported it. - */ - struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions; - /* * supported encoding mode, used to determine whether HDMI is * supported */ struct intel_sdvo_encode encode; - /* DDC bus used by this SDVO output */ - uint8_t ddc_bus; + /** + * This is sdvo flags for input timing. + */ + uint8_t sdvo_flags; - /* Mac mini hack -- use the same DDC as the analog connector */ - struct i2c_adapter *analog_ddc_bus; + /* This is for current tv format name */ + char *tv_format_name; 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; +}; + +struct intel_sdvo_connector { + /* Mark the type of connector */ + uint16_t output_flag; + + /* This contains all current supported TV format */ + char *tv_format_supported[TV_FORMAT_NUM]; + int format_supported_num; + struct drm_property *tv_format_property; + struct drm_property *tv_format_name_property[TV_FORMAT_NUM]; + + /** + * Returned SDTV resolutions allowed for the current format, if the + * device reported it. + */ + struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions; + + /* Mac mini hack -- use the same DDC as the analog connector */ + struct i2c_adapter *analog_ddc_bus; + /* add the property for the SDVO-TV */ struct drm_property *left_property; struct drm_property *right_property; @@ -160,8 +177,13 @@ struct intel_sdvo_priv { }; static bool -intel_sdvo_output_setup(struct intel_encoder *intel_encoder, - struct intel_connector *intel_connector, uint16_t flags); +intel_sdvo_output_setup(struct intel_encoder *intel_encoder); +static void +intel_sdvo_tv_create_property(struct drm_encoder *encoder, + struct drm_connector *connector); +static void +intel_sdvo_create_enhance_property(struct drm_encoder *encoder, + struct drm_connector *connector); /** * Writes the SDVOB or SDVOC with the given value, but always writes both @@ -172,11 +194,11 @@ static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val) { struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; u32 bval = val, cval = val; int i; - if (sdvo_priv->output_device == SDVOB) { + if (sdvo_encoder->output_device == SDVOB) { cval = I915_READ(SDVOC); } else { bval = I915_READ(SDVOB); @@ -198,20 +220,20 @@ static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val) static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, u8 *ch) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; u8 out_buf[2]; u8 buf[2]; int ret; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = sdvo_encoder->slave_addr >> 1, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = sdvo_priv->slave_addr >> 1, + .addr = sdvo_encoder->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, .buf = buf, @@ -234,11 +256,11 @@ static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, static bool intel_sdvo_write_byte(struct intel_encoder *intel_encoder, int addr, u8 ch) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; u8 out_buf[2]; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = sdvo_encoder->slave_addr >> 1, .flags = 0, .len = 2, .buf = out_buf, @@ -357,11 +379,11 @@ static const struct _sdvo_cmd_name { static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd, void *args, int args_len) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; int i; DRM_DEBUG_KMS("%s: W: %02X ", - SDVO_NAME(sdvo_priv), cmd); + SDVO_NAME(sdvo_encoder), cmd); for (i = 0; i < args_len; i++) DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) @@ -406,10 +428,10 @@ static void intel_sdvo_debug_response(struct intel_encoder *intel_encoder, void *response, int response_len, u8 status) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; int i; - DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_priv)); + DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_encoder)); for (i = 0; i < response_len; i++) DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); for (; i < 8; i++) @@ -471,24 +493,24 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encoder, u8 target) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; u8 out_buf[2], cmd_buf[2], ret_value[2], ret; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = sdvo_encoder->slave_addr >> 1, .flags = 0, .len = 2, .buf = out_buf, }, /* the following two are to read the response */ { - .addr = sdvo_priv->slave_addr >> 1, + .addr = sdvo_encoder->slave_addr >> 1, .flags = 0, .len = 1, .buf = cmd_buf, }, { - .addr = sdvo_priv->slave_addr >> 1, + .addr = sdvo_encoder->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, .buf = ret_value, @@ -717,7 +739,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder, uint16_t height) { struct intel_sdvo_preferred_input_timing_args args; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; uint8_t status; memset(&args, 0, sizeof(args)); @@ -726,9 +748,9 @@ intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder, args.height = height; args.interlace = 0; - if (sdvo_priv->is_lvds && - (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width || - sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height)) + if (sdvo_encoder->is_lvds && + (sdvo_encoder->sdvo_lvds_fixed_mode->hdisplay != width || + sdvo_encoder->sdvo_lvds_fixed_mode->vdisplay != height)) args.scaled = 1; intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, @@ -1051,12 +1073,12 @@ static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder) { struct intel_sdvo_tv_format format; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; uint32_t format_map, i; uint8_t status; for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == sdvo_priv->tv_format_name) + if (tv_format_names[i] == sdvo_encoder->tv_format_name) break; format_map = 1 << i; @@ -1070,7 +1092,7 @@ static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder) status = intel_sdvo_read_response(intel_encoder, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) DRM_DEBUG_KMS("%s: Failed to set TV format\n", - SDVO_NAME(sdvo_priv)); + SDVO_NAME(sdvo_encoder)); } static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, @@ -1078,9 +1100,9 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *dev_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; - if (dev_priv->is_tv) { + if (sdvo_encoder->is_tv) { struct intel_sdvo_dtd output_dtd; bool success; @@ -1094,7 +1116,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, /* Set output timings */ intel_sdvo_get_dtd_from_mode(&output_dtd, mode); intel_sdvo_set_target_output(intel_encoder, - dev_priv->controlled_output); + sdvo_encoder->attached_output); intel_sdvo_set_output_timing(intel_encoder, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ @@ -1111,7 +1133,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, intel_sdvo_get_preferred_input_timing(intel_encoder, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + sdvo_encoder->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -1122,23 +1144,22 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, } else { return false; } - } else if (dev_priv->is_lvds) { + } else if (sdvo_encoder->is_lvds) { struct intel_sdvo_dtd output_dtd; bool success; - drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0); + drm_mode_set_crtcinfo(sdvo_encoder->sdvo_lvds_fixed_mode, 0); /* Set output timings */ intel_sdvo_get_dtd_from_mode(&output_dtd, - dev_priv->sdvo_lvds_fixed_mode); + sdvo_encoder->sdvo_lvds_fixed_mode); intel_sdvo_set_target_output(intel_encoder, - dev_priv->controlled_output); + sdvo_encoder->attached_output); intel_sdvo_set_output_timing(intel_encoder, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ intel_sdvo_set_target_input(intel_encoder, true, false); - success = intel_sdvo_create_preferred_input_timing( intel_encoder, mode->clock / 10, @@ -1151,7 +1172,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, intel_sdvo_get_preferred_input_timing(intel_encoder, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + sdvo_encoder->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -1181,7 +1202,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; u32 sdvox = 0; int sdvo_pixel_multiply; struct intel_sdvo_in_out_map in_out; @@ -1197,40 +1218,40 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, * channel on the motherboard. In a two-input device, the first input * will be SDVOB and the second SDVOC. */ - in_out.in0 = sdvo_priv->controlled_output; + in_out.in0 = sdvo_encoder->attached_output; in_out.in1 = 0; intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_IN_OUT_MAP, &in_out, sizeof(in_out)); status = intel_sdvo_read_response(intel_encoder, NULL, 0); - if (sdvo_priv->is_hdmi) { + if (sdvo_encoder->is_hdmi) { intel_sdvo_set_avi_infoframe(intel_encoder, mode); sdvox |= SDVO_AUDIO_ENABLE; } /* We have tried to get input timing in mode_fixup, and filled into adjusted_mode */ - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { + if (sdvo_encoder->is_tv || sdvo_encoder->is_lvds) { intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); - input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags; + input_dtd.part2.sdvo_flags = sdvo_encoder->sdvo_flags; } else intel_sdvo_get_dtd_from_mode(&input_dtd, mode); /* If it's a TV, we already set the output timing in mode_fixup. * Otherwise, the output timing is equal to the input timing. */ - if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) { + if (!sdvo_encoder->is_tv && !sdvo_encoder->is_lvds) { /* Set the output timing to the screen */ intel_sdvo_set_target_output(intel_encoder, - sdvo_priv->controlled_output); + sdvo_encoder->attached_output); intel_sdvo_set_output_timing(intel_encoder, &input_dtd); } /* Set the input timing to the screen. Assume always input 0. */ intel_sdvo_set_target_input(intel_encoder, true, false); - if (sdvo_priv->is_tv) + if (sdvo_encoder->is_tv) intel_sdvo_set_tv_format(intel_encoder); /* We would like to use intel_sdvo_create_preferred_input_timing() to @@ -1272,8 +1293,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; } else { - sdvox |= I915_READ(sdvo_priv->output_device); - switch (sdvo_priv->output_device) { + sdvox |= I915_READ(sdvo_encoder->output_device); + switch (sdvo_encoder->output_device) { case SDVOB: sdvox &= SDVOB_PRESERVE_MASK; break; @@ -1295,7 +1316,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL) + if (sdvo_encoder->sdvo_flags & SDVO_NEED_TO_STALL) sdvox |= SDVO_STALL_SELECT; intel_sdvo_write_sdvox(intel_encoder, sdvox); } @@ -1305,7 +1326,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; u32 temp; if (mode != DRM_MODE_DPMS_ON) { @@ -1314,7 +1335,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) intel_sdvo_set_encoder_power_state(intel_encoder, mode); if (mode == DRM_MODE_DPMS_OFF) { - temp = I915_READ(sdvo_priv->output_device); + temp = I915_READ(sdvo_encoder->output_device); if ((temp & SDVO_ENABLE) != 0) { intel_sdvo_write_sdvox(intel_encoder, temp & ~SDVO_ENABLE); } @@ -1324,7 +1345,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) int i; u8 status; - temp = I915_READ(sdvo_priv->output_device); + temp = I915_READ(sdvo_encoder->output_device); if ((temp & SDVO_ENABLE) == 0) intel_sdvo_write_sdvox(intel_encoder, temp | SDVO_ENABLE); for (i = 0; i < 2; i++) @@ -1340,12 +1361,12 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) */ if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { DRM_DEBUG_KMS("First %s output reported failure to " - "sync\n", SDVO_NAME(sdvo_priv)); + "sync\n", SDVO_NAME(sdvo_encoder)); } if (0) intel_sdvo_set_encoder_power_state(intel_encoder, mode); - intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->controlled_output); + intel_sdvo_set_active_outputs(intel_encoder, sdvo_encoder->attached_output); } return; } @@ -1356,39 +1377,39 @@ static void intel_sdvo_save(struct drm_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; int o; - sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_encoder); - intel_sdvo_get_active_outputs(intel_encoder, &sdvo_priv->save_active_outputs); + sdvo_encoder->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_encoder); + intel_sdvo_get_active_outputs(intel_encoder, &sdvo_encoder->save_active_outputs); - if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { + if (sdvo_encoder->caps.sdvo_inputs_mask & 0x1) { intel_sdvo_set_target_input(intel_encoder, true, false); intel_sdvo_get_input_timing(intel_encoder, - &sdvo_priv->save_input_dtd_1); + &sdvo_encoder->save_input_dtd_1); } - if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { + if (sdvo_encoder->caps.sdvo_inputs_mask & 0x2) { intel_sdvo_set_target_input(intel_encoder, false, true); intel_sdvo_get_input_timing(intel_encoder, - &sdvo_priv->save_input_dtd_2); + &sdvo_encoder->save_input_dtd_2); } for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) { u16 this_output = (1 << o); - if (sdvo_priv->caps.output_flags & this_output) + if (sdvo_encoder->caps.output_flags & this_output) { intel_sdvo_set_target_output(intel_encoder, this_output); intel_sdvo_get_output_timing(intel_encoder, - &sdvo_priv->save_output_dtd[o]); + &sdvo_encoder->save_output_dtd[o]); } } - if (sdvo_priv->is_tv) { + if (sdvo_encoder->is_tv) { /* XXX: Save TV format/enhancements. */ } - sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device); + sdvo_encoder->save_SDVOX = I915_READ(sdvo_encoder->output_device); } static void intel_sdvo_restore(struct drm_connector *connector) @@ -1396,7 +1417,7 @@ static void intel_sdvo_restore(struct drm_connector *connector) struct drm_device *dev = connector->dev; struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; int o; int i; bool input1, input2; @@ -1407,41 +1428,41 @@ static void intel_sdvo_restore(struct drm_connector *connector) for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) { u16 this_output = (1 << o); - if (sdvo_priv->caps.output_flags & this_output) { + if (sdvo_encoder->caps.output_flags & this_output) { intel_sdvo_set_target_output(intel_encoder, this_output); - intel_sdvo_set_output_timing(intel_encoder, &sdvo_priv->save_output_dtd[o]); + intel_sdvo_set_output_timing(intel_encoder, &sdvo_encoder->save_output_dtd[o]); } } - if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { + if (sdvo_encoder->caps.sdvo_inputs_mask & 0x1) { intel_sdvo_set_target_input(intel_encoder, true, false); - intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_1); + intel_sdvo_set_input_timing(intel_encoder, &sdvo_encoder->save_input_dtd_1); } - if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { + if (sdvo_encoder->caps.sdvo_inputs_mask & 0x2) { intel_sdvo_set_target_input(intel_encoder, false, true); - intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_2); + intel_sdvo_set_input_timing(intel_encoder, &sdvo_encoder->save_input_dtd_2); } - intel_sdvo_set_clock_rate_mult(intel_encoder, sdvo_priv->save_sdvo_mult); + intel_sdvo_set_clock_rate_mult(intel_encoder, sdvo_encoder->save_sdvo_mult); - if (sdvo_priv->is_tv) { + if (sdvo_encoder->is_tv) { /* XXX: Restore TV format/enhancements. */ } - intel_sdvo_write_sdvox(intel_encoder, sdvo_priv->save_SDVOX); + intel_sdvo_write_sdvox(intel_encoder, sdvo_encoder->save_SDVOX); - if (sdvo_priv->save_SDVOX & SDVO_ENABLE) + if (sdvo_encoder->save_SDVOX & SDVO_ENABLE) { for (i = 0; i < 2; i++) intel_wait_for_vblank(dev); status = intel_sdvo_get_trained_inputs(intel_encoder, &input1, &input2); if (status == SDVO_CMD_STATUS_SUCCESS && !input1) DRM_DEBUG_KMS("First %s output reported failure to " - "sync\n", SDVO_NAME(sdvo_priv)); + "sync\n", SDVO_NAME(sdvo_encoder)); } - intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->save_active_outputs); + intel_sdvo_set_active_outputs(intel_encoder, sdvo_encoder->save_active_outputs); } static int intel_sdvo_mode_valid(struct drm_connector *connector, @@ -1449,25 +1470,25 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, { struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; - if (sdvo_priv->pixel_clock_min > mode->clock) + if (sdvo_encoder->pixel_clock_min > mode->clock) return MODE_CLOCK_LOW; - if (sdvo_priv->pixel_clock_max < mode->clock) + if (sdvo_encoder->pixel_clock_max < mode->clock) return MODE_CLOCK_HIGH; - if (sdvo_priv->is_lvds == true) { - if (sdvo_priv->sdvo_lvds_fixed_mode == NULL) + if (sdvo_encoder->is_lvds == true) { + if (sdvo_encoder->sdvo_lvds_fixed_mode == NULL) return MODE_PANEL; - if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay) + if (mode->hdisplay > sdvo_encoder->sdvo_lvds_fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay) + if (mode->vdisplay > sdvo_encoder->sdvo_lvds_fixed_mode->vdisplay) return MODE_PANEL; } @@ -1563,30 +1584,30 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) static bool intel_sdvo_multifunc_encoder(struct intel_encoder *intel_encoder) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; int caps = 0; - if (sdvo_priv->caps.output_flags & + if (sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) caps++; - if (sdvo_priv->caps.output_flags & + if (sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)) caps++; - if (sdvo_priv->caps.output_flags & + if (sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1)) caps++; - if (sdvo_priv->caps.output_flags & + if (sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1)) caps++; - if (sdvo_priv->caps.output_flags & + if (sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1)) caps++; - if (sdvo_priv->caps.output_flags & + if (sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1)) caps++; - if (sdvo_priv->caps.output_flags & + if (sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)) caps++; @@ -1629,7 +1650,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; @@ -1638,43 +1660,44 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response) /* This is only applied to SDVO cards with multiple outputs */ if (edid == NULL && intel_sdvo_multifunc_encoder(intel_encoder)) { uint8_t saved_ddc, temp_ddc; - saved_ddc = sdvo_priv->ddc_bus; - temp_ddc = sdvo_priv->ddc_bus >> 1; + saved_ddc = sdvo_encoder->ddc_bus; + temp_ddc = sdvo_encoder->ddc_bus >> 1; /* * Don't use the 1 as the argument of DDC bus switch to get * the EDID. It is used for SDVO SPD ROM. */ while(temp_ddc > 1) { - sdvo_priv->ddc_bus = temp_ddc; + sdvo_encoder->ddc_bus = temp_ddc; edid = drm_get_edid(connector, intel_connector->ddc_bus); if (edid) { /* * When we can get the EDID, maybe it is the * correct DDC bus. Update it. */ - sdvo_priv->ddc_bus = temp_ddc; + sdvo_encoder->ddc_bus = temp_ddc; break; } temp_ddc >>= 1; } if (edid == NULL) - sdvo_priv->ddc_bus = saved_ddc; + sdvo_encoder->ddc_bus = saved_ddc; } /* when there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector */ if (edid == NULL && - sdvo_priv->analog_ddc_bus && + sdvo_connector->analog_ddc_bus && !intel_analog_is_connected(connector->dev)) edid = drm_get_edid(connector, - sdvo_priv->analog_ddc_bus); + sdvo_connector->analog_ddc_bus); + if (edid != NULL) { /* Don't report the output as connected if it's a DVI-I * connector with a non-digital EDID coming out. */ if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { if (edid->input & DRM_EDID_INPUT_DIGITAL) - sdvo_priv->is_hdmi = + sdvo_encoder->is_hdmi = drm_detect_hdmi_monitor(edid); else status = connector_status_disconnected; @@ -1696,11 +1719,13 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + enum drm_connector_status ret; intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); - if (sdvo_priv->is_tv) { + if (sdvo_encoder->is_tv) { /* add 30ms delay when the output type is SDVO-TV */ mdelay(30); } @@ -1714,23 +1739,36 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect if (response == 0) return connector_status_disconnected; - if (intel_sdvo_multifunc_encoder(intel_encoder) && - sdvo_priv->attached_output != response) { - if (sdvo_priv->controlled_output != response && - intel_sdvo_output_setup(intel_encoder, intel_connector, - response) != true) - return connector_status_unknown; - sdvo_priv->attached_output = response; + sdvo_encoder->attached_output = response; + + if ((sdvo_connector->output_flag & response) == 0) + ret = connector_status_disconnected; + else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) + ret = intel_sdvo_hdmi_sink_detect(connector, response); + else + ret = connector_status_connected; + + /* May update encoder flag for like clock for SDVO TV, etc.*/ + if (ret == connector_status_connected) { + sdvo_encoder->is_tv = false; + sdvo_encoder->is_lvds = false; + intel_encoder->needs_tv_clock = false; + + if (response & SDVO_TV_MASK) { + sdvo_encoder->is_tv = true; + intel_encoder->needs_tv_clock = true; + } + if (response & SDVO_LVDS_MASK) + sdvo_encoder->is_lvds = true; } - return intel_sdvo_hdmi_sink_detect(connector, response); + + return ret; } static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_best_encoder(connector); - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; int num_modes; /* set the bus switch and get the modes */ @@ -1743,14 +1781,14 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) * which case we'll look there for the digital DDC data. */ if (num_modes == 0 && - sdvo_priv->analog_ddc_bus && + sdvo_connector->analog_ddc_bus && !intel_analog_is_connected(intel_connector->base.dev)) { struct i2c_adapter *digital_ddc_bus; /* Switch to the analog ddc bus and try that */ digital_ddc_bus = intel_connector->ddc_bus; - intel_connector->ddc_bus = sdvo_priv->analog_ddc_bus; + intel_connector->ddc_bus = sdvo_connector->analog_ddc_bus; (void) intel_ddc_get_modes(intel_connector); @@ -1827,7 +1865,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0, format_map = 0; int i; @@ -1838,7 +1876,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) * format. */ for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == sdvo_priv->tv_format_name) + if (tv_format_names[i] == sdvo_encoder->tv_format_name) break; format_map = (1 << i); @@ -1847,7 +1885,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) sizeof(format_map) ? sizeof(format_map) : sizeof(struct intel_sdvo_sdtv_resolution_request)); - intel_sdvo_set_target_output(intel_encoder, sdvo_priv->controlled_output); + intel_sdvo_set_target_output(intel_encoder, sdvo_encoder->attached_output); intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, &tv_res, sizeof(tv_res)); @@ -1871,7 +1909,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; struct drm_i915_private *dev_priv = connector->dev->dev_private; struct drm_display_mode *newmode; @@ -1899,7 +1937,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) end: list_for_each_entry(newmode, &connector->probed_modes, head) { if (newmode->type & DRM_MODE_TYPE_PREFERRED) { - sdvo_priv->sdvo_lvds_fixed_mode = + sdvo_encoder->sdvo_lvds_fixed_mode = drm_mode_duplicate(connector->dev, newmode); break; } @@ -1909,13 +1947,12 @@ end: static int intel_sdvo_get_modes(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_best_encoder(connector); - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; - if (sdvo_priv->is_tv) + if (SDVO_CONNECTOR_IS_TV(sdvo_connector)) intel_sdvo_get_tv_modes(connector); - else if (sdvo_priv->is_lvds == true) + else if (SDVO_CONNECTOR_IS_LVDS(sdvo_connector)) intel_sdvo_get_lvds_modes(connector); else intel_sdvo_get_ddc_modes(connector); @@ -1928,65 +1965,56 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) static void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_best_encoder(connector); - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct drm_device *dev = connector->dev; - if (sdvo_priv->is_tv) { - if (sdvo_priv->left_property) - drm_property_destroy(dev, sdvo_priv->left_property); - if (sdvo_priv->right_property) - drm_property_destroy(dev, sdvo_priv->right_property); - if (sdvo_priv->top_property) - drm_property_destroy(dev, sdvo_priv->top_property); - if (sdvo_priv->bottom_property) - drm_property_destroy(dev, sdvo_priv->bottom_property); - if (sdvo_priv->hpos_property) - drm_property_destroy(dev, sdvo_priv->hpos_property); - if (sdvo_priv->vpos_property) - drm_property_destroy(dev, sdvo_priv->vpos_property); - } - if (sdvo_priv->is_tv) { - if (sdvo_priv->saturation_property) + if (SDVO_CONNECTOR_IS_TV(sdvo_connector)) { + if (sdvo_connector->left_property) + drm_property_destroy(dev, sdvo_connector->left_property); + if (sdvo_connector->right_property) + drm_property_destroy(dev, sdvo_connector->right_property); + if (sdvo_connector->top_property) + drm_property_destroy(dev, sdvo_connector->top_property); + if (sdvo_connector->bottom_property) + drm_property_destroy(dev, sdvo_connector->bottom_property); + if (sdvo_connector->hpos_property) + drm_property_destroy(dev, sdvo_connector->hpos_property); + if (sdvo_connector->vpos_property) + drm_property_destroy(dev, sdvo_connector->vpos_property); + if (sdvo_connector->saturation_property) drm_property_destroy(dev, - sdvo_priv->saturation_property); - if (sdvo_priv->contrast_property) + sdvo_connector->saturation_property); + if (sdvo_connector->contrast_property) drm_property_destroy(dev, - sdvo_priv->contrast_property); - if (sdvo_priv->hue_property) - drm_property_destroy(dev, sdvo_priv->hue_property); + sdvo_connector->contrast_property); + if (sdvo_connector->hue_property) + drm_property_destroy(dev, sdvo_connector->hue_property); } - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { - if (sdvo_priv->brightness_property) + if (SDVO_CONNECTOR_IS_TV(sdvo_connector) || + SDVO_CONNECTOR_IS_LVDS(sdvo_connector)) { + if (sdvo_connector->brightness_property) drm_property_destroy(dev, - sdvo_priv->brightness_property); + sdvo_connector->brightness_property); } return; } static void intel_sdvo_destroy(struct drm_connector *connector) { - struct drm_encoder *encoder = intel_best_encoder(connector); - struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; if (intel_connector->ddc_bus) intel_i2c_destroy(intel_connector->ddc_bus); - if (sdvo_priv->analog_ddc_bus) - intel_i2c_destroy(sdvo_priv->analog_ddc_bus); - - if (sdvo_priv->sdvo_lvds_fixed_mode != NULL) - drm_mode_destroy(connector->dev, - sdvo_priv->sdvo_lvds_fixed_mode); + if (sdvo_connector->analog_ddc_bus) + intel_i2c_destroy(sdvo_connector->analog_ddc_bus); - if (sdvo_priv->tv_format_property) + if (sdvo_connector->tv_format_property) drm_property_destroy(connector->dev, - sdvo_priv->tv_format_property); + sdvo_connector->tv_format_property); - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) - intel_sdvo_destroy_enhance_property(connector); + intel_sdvo_destroy_enhance_property(connector); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -2001,7 +2029,9 @@ intel_sdvo_set_property(struct drm_connector *connector, { struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct drm_crtc *crtc = encoder->crtc; int ret = 0; bool changed = false; @@ -2012,101 +2042,102 @@ intel_sdvo_set_property(struct drm_connector *connector, if (ret < 0) goto out; - if (property == sdvo_priv->tv_format_property) { + if (property == sdvo_connector->tv_format_property) { if (val >= TV_FORMAT_NUM) { ret = -EINVAL; goto out; } - if (sdvo_priv->tv_format_name == - sdvo_priv->tv_format_supported[val]) + if (sdvo_encoder->tv_format_name == + sdvo_connector->tv_format_supported[val]) goto out; - sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[val]; + sdvo_encoder->tv_format_name = sdvo_connector->tv_format_supported[val]; changed = true; } - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { + if (SDVO_CONNECTOR_IS_TV(sdvo_connector) || + SDVO_CONNECTOR_IS_LVDS(sdvo_connector)) { cmd = 0; temp_value = val; - if (sdvo_priv->left_property == property) { + if (sdvo_connector->left_property == property) { drm_connector_property_set_value(connector, - sdvo_priv->right_property, val); - if (sdvo_priv->left_margin == temp_value) + sdvo_connector->right_property, val); + if (sdvo_connector->left_margin == temp_value) goto out; - sdvo_priv->left_margin = temp_value; - sdvo_priv->right_margin = temp_value; - temp_value = sdvo_priv->max_hscan - - sdvo_priv->left_margin; + sdvo_connector->left_margin = temp_value; + sdvo_connector->right_margin = temp_value; + temp_value = sdvo_connector->max_hscan - + sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (sdvo_priv->right_property == property) { + } else if (sdvo_connector->right_property == property) { drm_connector_property_set_value(connector, - sdvo_priv->left_property, val); - if (sdvo_priv->right_margin == temp_value) + sdvo_connector->left_property, val); + if (sdvo_connector->right_margin == temp_value) goto out; - sdvo_priv->left_margin = temp_value; - sdvo_priv->right_margin = temp_value; - temp_value = sdvo_priv->max_hscan - - sdvo_priv->left_margin; + sdvo_connector->left_margin = temp_value; + sdvo_connector->right_margin = temp_value; + temp_value = sdvo_connector->max_hscan - + sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (sdvo_priv->top_property == property) { + } else if (sdvo_connector->top_property == property) { drm_connector_property_set_value(connector, - sdvo_priv->bottom_property, val); - if (sdvo_priv->top_margin == temp_value) + sdvo_connector->bottom_property, val); + if (sdvo_connector->top_margin == temp_value) goto out; - sdvo_priv->top_margin = temp_value; - sdvo_priv->bottom_margin = temp_value; - temp_value = sdvo_priv->max_vscan - - sdvo_priv->top_margin; + sdvo_connector->top_margin = temp_value; + sdvo_connector->bottom_margin = temp_value; + temp_value = sdvo_connector->max_vscan - + sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (sdvo_priv->bottom_property == property) { + } else if (sdvo_connector->bottom_property == property) { drm_connector_property_set_value(connector, - sdvo_priv->top_property, val); - if (sdvo_priv->bottom_margin == temp_value) + sdvo_connector->top_property, val); + if (sdvo_connector->bottom_margin == temp_value) goto out; - sdvo_priv->top_margin = temp_value; - sdvo_priv->bottom_margin = temp_value; - temp_value = sdvo_priv->max_vscan - - sdvo_priv->top_margin; + sdvo_connector->top_margin = temp_value; + sdvo_connector->bottom_margin = temp_value; + temp_value = sdvo_connector->max_vscan - + sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (sdvo_priv->hpos_property == property) { - if (sdvo_priv->cur_hpos == temp_value) + } else if (sdvo_connector->hpos_property == property) { + if (sdvo_connector->cur_hpos == temp_value) goto out; cmd = SDVO_CMD_SET_POSITION_H; - sdvo_priv->cur_hpos = temp_value; - } else if (sdvo_priv->vpos_property == property) { - if (sdvo_priv->cur_vpos == temp_value) + sdvo_connector->cur_hpos = temp_value; + } else if (sdvo_connector->vpos_property == property) { + if (sdvo_connector->cur_vpos == temp_value) goto out; cmd = SDVO_CMD_SET_POSITION_V; - sdvo_priv->cur_vpos = temp_value; - } else if (sdvo_priv->saturation_property == property) { - if (sdvo_priv->cur_saturation == temp_value) + sdvo_connector->cur_vpos = temp_value; + } else if (sdvo_connector->saturation_property == property) { + if (sdvo_connector->cur_saturation == temp_value) goto out; cmd = SDVO_CMD_SET_SATURATION; - sdvo_priv->cur_saturation = temp_value; - } else if (sdvo_priv->contrast_property == property) { - if (sdvo_priv->cur_contrast == temp_value) + sdvo_connector->cur_saturation = temp_value; + } else if (sdvo_connector->contrast_property == property) { + if (sdvo_connector->cur_contrast == temp_value) goto out; cmd = SDVO_CMD_SET_CONTRAST; - sdvo_priv->cur_contrast = temp_value; - } else if (sdvo_priv->hue_property == property) { - if (sdvo_priv->cur_hue == temp_value) + sdvo_connector->cur_contrast = temp_value; + } else if (sdvo_connector->hue_property == property) { + if (sdvo_connector->cur_hue == temp_value) goto out; cmd = SDVO_CMD_SET_HUE; - sdvo_priv->cur_hue = temp_value; - } else if (sdvo_priv->brightness_property == property) { - if (sdvo_priv->cur_brightness == temp_value) + sdvo_connector->cur_hue = temp_value; + } else if (sdvo_connector->brightness_property == property) { + if (sdvo_connector->cur_brightness == temp_value) goto out; cmd = SDVO_CMD_SET_BRIGHTNESS; - sdvo_priv->cur_brightness = temp_value; + sdvo_connector->cur_brightness = temp_value; } if (cmd) { intel_sdvo_write_cmd(intel_encoder, cmd, &temp_value, 2); @@ -2153,9 +2184,15 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; if (intel_encoder->i2c_bus) intel_i2c_destroy(intel_encoder->i2c_bus); + + if (sdvo_encoder->sdvo_lvds_fixed_mode != NULL) + drm_mode_destroy(encoder->dev, + sdvo_encoder->sdvo_lvds_fixed_mode); + drm_encoder_cleanup(encoder); kfree(encoder); } @@ -2173,7 +2210,7 @@ static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { * outputs, then LVDS outputs. */ static void -intel_sdvo_select_ddc_bus(struct intel_sdvo_priv *dev_priv) +intel_sdvo_select_ddc_bus(struct intel_sdvo_encoder *dev_priv) { uint16_t mask = 0; unsigned int num_bits; @@ -2210,15 +2247,18 @@ intel_sdvo_select_ddc_bus(struct intel_sdvo_priv *dev_priv) } static bool -intel_sdvo_get_digital_encoding_mode(struct intel_encoder *intel_encoder) +intel_sdvo_get_digital_encoding_mode(struct intel_encoder *intel_encoder, int device) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; uint8_t status; - intel_sdvo_set_target_output(intel_encoder, sdvo_priv->controlled_output); + if (device == 0) + intel_sdvo_set_target_output(intel_encoder, SDVO_OUTPUT_TMDS0); + else + intel_sdvo_set_target_output(intel_encoder, SDVO_OUTPUT_TMDS1); intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ENCODE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &sdvo_priv->is_hdmi, 1); + status = intel_sdvo_read_response(intel_encoder, &sdvo_encoder->is_hdmi, 1); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; @@ -2229,16 +2269,13 @@ intel_sdvo_chan_to_intel_connector(struct intel_i2c_chan *chan) { struct drm_device *dev = chan->drm_dev; struct drm_connector *connector; - struct intel_connector *intel_connector = NULL; - list_for_each_entry(connector, - &dev->mode_config.connector_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (to_intel_connector(connector)->ddc_bus == &chan->adapter) { - intel_connector = to_intel_connector(connector); - break; + return to_intel_connector(connector); } } - return intel_connector; + return NULL; } static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, @@ -2248,7 +2285,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, struct drm_encoder *encoder; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; - struct intel_sdvo_priv *sdvo_priv; + struct intel_sdvo_encoder *sdvo_encoder; struct i2c_algo_bit_data *algo_data; const struct i2c_algorithm *algo; @@ -2263,10 +2300,10 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, encoder = intel_best_encoder(connector); intel_encoder = to_intel_encoder(encoder); - sdvo_priv = intel_encoder->dev_priv; + sdvo_encoder = intel_encoder->dev_priv; algo = intel_encoder->i2c_bus->algo; - intel_sdvo_set_control_bus_switch(intel_encoder, sdvo_priv->ddc_bus); + intel_sdvo_set_control_bus_switch(intel_encoder, sdvo_encoder->ddc_bus); return algo->master_xfer(i2c_adap, msgs, num); } @@ -2312,125 +2349,266 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device) } static bool -intel_sdvo_output_setup(struct intel_encoder *intel_encoder, - struct intel_connector *intel_connector, - uint16_t flags) +intel_sdvo_connector_alloc (struct drm_device *dev, struct intel_connector **ret) +{ + struct intel_connector *intel_connector; + struct intel_sdvo_connector *sdvo_connector; + struct drm_connector *connector; + + *ret = kzalloc(sizeof(*intel_connector) + + sizeof(*sdvo_connector), GFP_KERNEL); + if (!*ret) + return false; + intel_connector = *ret; + connector = &intel_connector->base; + sdvo_connector = (struct intel_sdvo_connector *)(intel_connector + 1); + intel_connector->dev_priv = sdvo_connector; + + intel_connector->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVO DDC BUS"); + sdvo_connector->analog_ddc_bus = intel_i2c_create(dev, GPIOA, + "SDVO/VGA DDC BUS"); + if (!intel_connector->ddc_bus || !sdvo_connector->analog_ddc_bus) { + kfree(intel_connector); + return false; + } + /* Wrap with our custom algo which switches to DDC mode */ + intel_connector->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; + return true; +} + +static void +intel_sdvo_connector_create (struct drm_encoder *encoder, struct drm_connector *connector) +{ + drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs, + connector->connector_type); + + drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + + drm_mode_connector_attach_encoder(connector, encoder); + drm_sysfs_connector_add(connector); +} + +static bool +intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) { struct drm_encoder *encoder = &intel_encoder->base; - struct drm_connector *connector = &intel_connector->base; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; - bool ret = true, registered = false; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *sdvo_connector; - sdvo_priv->is_tv = false; - intel_encoder->needs_tv_clock = false; - sdvo_priv->is_lvds = false; + if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector)) + return false; - if (device_is_registered(&connector->kdev)) { - drm_sysfs_connector_remove(connector); - registered = true; - } + sdvo_connector = intel_connector->dev_priv; - if (flags & - (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) { - if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) - sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0; - else - sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; + if (device == 0) { + sdvo_encoder->controlled_output |= SDVO_OUTPUT_TMDS0; + sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; + } else if (device == 1) { + sdvo_encoder->controlled_output |= SDVO_OUTPUT_TMDS1; + sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; + } - encoder->encoder_type = DRM_MODE_ENCODER_TMDS; - connector->connector_type = DRM_MODE_CONNECTOR_DVID; + connector = &intel_connector->base; + encoder->encoder_type = DRM_MODE_ENCODER_TMDS; + connector->connector_type = DRM_MODE_CONNECTOR_DVID; - if (intel_sdvo_get_supp_encode(intel_encoder, - &sdvo_priv->encode) && - intel_sdvo_get_digital_encoding_mode(intel_encoder) && - sdvo_priv->is_hdmi) { + if (intel_sdvo_get_supp_encode(intel_encoder, &sdvo_encoder->encode) + && intel_sdvo_get_digital_encoding_mode(intel_encoder, device) + && sdvo_encoder->is_hdmi) { /* enable hdmi encoding mode if supported */ intel_sdvo_set_encode(intel_encoder, SDVO_ENCODE_HDMI); intel_sdvo_set_colorimetry(intel_encoder, SDVO_COLORIMETRY_RGB256); connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; - intel_encoder->clone_mask = - (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); - } - } else if (flags & SDVO_OUTPUT_SVID0) { - - sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; - encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; - connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; - sdvo_priv->is_tv = true; - intel_encoder->needs_tv_clock = true; - intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; - } else if (flags & SDVO_OUTPUT_RGB0) { - - sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; - encoder->encoder_type = DRM_MODE_ENCODER_DAC; - connector->connector_type = DRM_MODE_CONNECTOR_VGA; - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); - } else if (flags & SDVO_OUTPUT_RGB1) { - - sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; - encoder->encoder_type = DRM_MODE_ENCODER_DAC; - connector->connector_type = DRM_MODE_CONNECTOR_VGA; - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); - } else if (flags & SDVO_OUTPUT_CVBS0) { - - sdvo_priv->controlled_output = SDVO_OUTPUT_CVBS0; - encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; - connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; - sdvo_priv->is_tv = true; - intel_encoder->needs_tv_clock = true; - intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; - } else if (flags & SDVO_OUTPUT_LVDS0) { - - sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; - encoder->encoder_type = DRM_MODE_ENCODER_LVDS; - connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - sdvo_priv->is_lvds = true; - intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) | - (1 << INTEL_SDVO_LVDS_CLONE_BIT); - } else if (flags & SDVO_OUTPUT_LVDS1) { - - sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; - encoder->encoder_type = DRM_MODE_ENCODER_LVDS; - connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - sdvo_priv->is_lvds = true; - intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) | - (1 << INTEL_SDVO_LVDS_CLONE_BIT); - } else { + } + intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | + (1 << INTEL_ANALOG_CLONE_BIT); + + intel_sdvo_connector_create(encoder, connector); + + return true; +} + +static bool +intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *sdvo_connector; + + if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector)) + return false; + + connector = &intel_connector->base; + encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; + connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; + sdvo_connector = intel_connector->dev_priv; + + sdvo_encoder->controlled_output |= type; + sdvo_connector->output_flag = type; + + sdvo_encoder->is_tv = true; + intel_encoder->needs_tv_clock = true; + intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; + + intel_sdvo_connector_create(encoder, connector); + + intel_sdvo_tv_create_property(encoder, connector); + + intel_sdvo_create_enhance_property(encoder, connector); + + return true; +} + +static bool +intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *sdvo_connector; + + if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector)) + return false; + + connector = &intel_connector->base; + encoder->encoder_type = DRM_MODE_ENCODER_DAC; + connector->connector_type = DRM_MODE_CONNECTOR_VGA; + sdvo_connector = intel_connector->dev_priv; + + if (device == 0) { + sdvo_encoder->controlled_output |= SDVO_OUTPUT_RGB0; + sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; + } else if (device == 1) { + sdvo_encoder->controlled_output |= SDVO_OUTPUT_RGB1; + sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; + } + + intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | + (1 << INTEL_ANALOG_CLONE_BIT); + + intel_sdvo_connector_create(encoder, connector); + return true; +} + +static bool +intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *sdvo_connector; + + if (!intel_sdvo_connector_alloc(encoder->dev, &intel_connector)) + return false; + + connector = &intel_connector->base; + encoder->encoder_type = DRM_MODE_ENCODER_LVDS; + connector->connector_type = DRM_MODE_CONNECTOR_LVDS; + sdvo_connector = intel_connector->dev_priv; + + sdvo_encoder->is_lvds = true; + + if (device == 0) { + sdvo_encoder->controlled_output |= SDVO_OUTPUT_LVDS0; + sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; + } else if (device == 1) { + sdvo_encoder->controlled_output |= SDVO_OUTPUT_LVDS1; + sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; + } + + intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) | + (1 << INTEL_SDVO_LVDS_CLONE_BIT); + + intel_sdvo_connector_create(encoder, connector); + intel_sdvo_create_enhance_property(encoder, connector); + return true; +} + +static bool +intel_sdvo_output_setup(struct intel_encoder *intel_encoder) +{ + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + int flags = sdvo_encoder->caps.output_flags; + + intel_encoder->needs_tv_clock = false; + sdvo_encoder->is_tv = false; + sdvo_encoder->is_lvds = false; + + /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ + + if (flags & SDVO_OUTPUT_TMDS0) + if (!intel_sdvo_dvi_init(intel_encoder, 0)) + return false; + + if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK) + if (!intel_sdvo_dvi_init(intel_encoder, 1)) + return false; + + /* TV has no XXX1 function block */ + if (flags & SDVO_OUTPUT_SVID0) + if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_SVID0)) + return false; + + if (flags & SDVO_OUTPUT_CVBS0) + if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_CVBS0)) + return false; + + if (flags & SDVO_OUTPUT_RGB0) + if (!intel_sdvo_analog_init(intel_encoder, 0)) + return false; + + if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK) + if (!intel_sdvo_analog_init(intel_encoder, 1)) + return false; + + if (flags & SDVO_OUTPUT_LVDS0) + if (!intel_sdvo_lvds_init(intel_encoder, 0)) + return false; + + if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK) + if (!intel_sdvo_lvds_init(intel_encoder, 1)) + return false; + if ((flags & SDVO_OUTPUT_MASK) == 0) { unsigned char bytes[2]; - sdvo_priv->controlled_output = 0; - memcpy(bytes, &sdvo_priv->caps.output_flags, 2); + sdvo_encoder->controlled_output = 0; + memcpy(bytes, &sdvo_encoder->caps.output_flags, 2); DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(sdvo_priv), + SDVO_NAME(sdvo_encoder), bytes[0], bytes[1]); - ret = false; + return false; } intel_encoder->crtc_mask = (1 << 0) | (1 << 1); - if (ret && registered) - ret = drm_sysfs_connector_add(connector) == 0 ? true : false; - - - return ret; + return true; } -static void intel_sdvo_tv_create_property(struct drm_connector *connector) +static void intel_sdvo_tv_create_property(struct drm_encoder *encoder, + struct drm_connector *connector) { - struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_sdvo_encoder *sdvo_encoder = intel_encoder->dev_priv; + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct intel_sdvo_tv_format format; uint32_t format_map, i; uint8_t status; intel_sdvo_set_target_output(intel_encoder, - sdvo_priv->controlled_output); + sdvo_encoder->attached_output); intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0); @@ -2445,36 +2623,37 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector) if (format_map == 0) return; - sdvo_priv->format_supported_num = 0; + sdvo_connector->format_supported_num = 0; for (i = 0 ; i < TV_FORMAT_NUM; i++) if (format_map & (1 << i)) { - sdvo_priv->tv_format_supported - [sdvo_priv->format_supported_num++] = + sdvo_connector->tv_format_supported + [sdvo_connector->format_supported_num++] = tv_format_names[i]; } - sdvo_priv->tv_format_property = + sdvo_connector->tv_format_property = drm_property_create( connector->dev, DRM_MODE_PROP_ENUM, - "mode", sdvo_priv->format_supported_num); + "mode", sdvo_connector->format_supported_num); - for (i = 0; i < sdvo_priv->format_supported_num; i++) + for (i = 0; i < sdvo_connector->format_supported_num; i++) drm_property_add_enum( - sdvo_priv->tv_format_property, i, - i, sdvo_priv->tv_format_supported[i]); + sdvo_connector->tv_format_property, i, + i, sdvo_connector->tv_format_supported[i]); - sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[0]; + sdvo_encoder->tv_format_name = sdvo_connector->tv_format_supported[0]; drm_connector_attach_property( - connector, sdvo_priv->tv_format_property, 0); + connector, sdvo_connector->tv_format_property, 0); } -static void intel_sdvo_create_enhance_property(struct drm_connector *connector) +static void intel_sdvo_create_enhance_property(struct drm_encoder *encoder, + struct drm_connector *connector) { - struct drm_encoder *encoder = intel_best_encoder(connector); struct intel_encoder *intel_encoder = to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct intel_sdvo_enhancements_reply sdvo_data; struct drm_device *dev = connector->dev; uint8_t status; @@ -2493,7 +2672,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("No enhancement is supported\n"); return; } - if (sdvo_priv->is_tv) { + if (SDVO_CONNECTOR_IS_TV(sdvo_connector)) { /* when horizontal overscan is supported, Add the left/right * property */ @@ -2515,25 +2694,25 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO h_overscan\n"); return; } - sdvo_priv->max_hscan = data_value[0]; - sdvo_priv->left_margin = data_value[0] - response; - sdvo_priv->right_margin = sdvo_priv->left_margin; - sdvo_priv->left_property = + sdvo_connector->max_hscan = data_value[0]; + sdvo_connector->left_margin = data_value[0] - response; + sdvo_connector->right_margin = sdvo_connector->left_margin; + sdvo_connector->left_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "left_margin", 2); - sdvo_priv->left_property->values[0] = 0; - sdvo_priv->left_property->values[1] = data_value[0]; + sdvo_connector->left_property->values[0] = 0; + sdvo_connector->left_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->left_property, - sdvo_priv->left_margin); - sdvo_priv->right_property = + sdvo_connector->left_property, + sdvo_connector->left_margin); + sdvo_connector->right_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "right_margin", 2); - sdvo_priv->right_property->values[0] = 0; - sdvo_priv->right_property->values[1] = data_value[0]; + sdvo_connector->right_property->values[0] = 0; + sdvo_connector->right_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->right_property, - sdvo_priv->right_margin); + sdvo_connector->right_property, + sdvo_connector->right_margin); DRM_DEBUG_KMS("h_overscan: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2556,25 +2735,25 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO v_overscan\n"); return; } - sdvo_priv->max_vscan = data_value[0]; - sdvo_priv->top_margin = data_value[0] - response; - sdvo_priv->bottom_margin = sdvo_priv->top_margin; - sdvo_priv->top_property = + sdvo_connector->max_vscan = data_value[0]; + sdvo_connector->top_margin = data_value[0] - response; + sdvo_connector->bottom_margin = sdvo_connector->top_margin; + sdvo_connector->top_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "top_margin", 2); - sdvo_priv->top_property->values[0] = 0; - sdvo_priv->top_property->values[1] = data_value[0]; + sdvo_connector->top_property->values[0] = 0; + sdvo_connector->top_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->top_property, - sdvo_priv->top_margin); - sdvo_priv->bottom_property = + sdvo_connector->top_property, + sdvo_connector->top_margin); + sdvo_connector->bottom_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "bottom_margin", 2); - sdvo_priv->bottom_property->values[0] = 0; - sdvo_priv->bottom_property->values[1] = data_value[0]; + sdvo_connector->bottom_property->values[0] = 0; + sdvo_connector->bottom_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->bottom_property, - sdvo_priv->bottom_margin); + sdvo_connector->bottom_property, + sdvo_connector->bottom_margin); DRM_DEBUG_KMS("v_overscan: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2596,16 +2775,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO get h_postion\n"); return; } - sdvo_priv->max_hpos = data_value[0]; - sdvo_priv->cur_hpos = response; - sdvo_priv->hpos_property = + sdvo_connector->max_hpos = data_value[0]; + sdvo_connector->cur_hpos = response; + sdvo_connector->hpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hpos", 2); - sdvo_priv->hpos_property->values[0] = 0; - sdvo_priv->hpos_property->values[1] = data_value[0]; + sdvo_connector->hpos_property->values[0] = 0; + sdvo_connector->hpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->hpos_property, - sdvo_priv->cur_hpos); + sdvo_connector->hpos_property, + sdvo_connector->cur_hpos); DRM_DEBUG_KMS("h_position: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2627,22 +2806,20 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO get v_postion\n"); return; } - sdvo_priv->max_vpos = data_value[0]; - sdvo_priv->cur_vpos = response; - sdvo_priv->vpos_property = + sdvo_connector->max_vpos = data_value[0]; + sdvo_connector->cur_vpos = response; + sdvo_connector->vpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "vpos", 2); - sdvo_priv->vpos_property->values[0] = 0; - sdvo_priv->vpos_property->values[1] = data_value[0]; + sdvo_connector->vpos_property->values[0] = 0; + sdvo_connector->vpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->vpos_property, - sdvo_priv->cur_vpos); + sdvo_connector->vpos_property, + sdvo_connector->cur_vpos); DRM_DEBUG_KMS("v_position: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } - } - if (sdvo_priv->is_tv) { if (sdvo_data.saturation) { intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_MAX_SATURATION, NULL, 0); @@ -2660,17 +2837,17 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO get sat\n"); return; } - sdvo_priv->max_saturation = data_value[0]; - sdvo_priv->cur_saturation = response; - sdvo_priv->saturation_property = + sdvo_connector->max_saturation = data_value[0]; + sdvo_connector->cur_saturation = response; + sdvo_connector->saturation_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "saturation", 2); - sdvo_priv->saturation_property->values[0] = 0; - sdvo_priv->saturation_property->values[1] = + sdvo_connector->saturation_property->values[0] = 0; + sdvo_connector->saturation_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->saturation_property, - sdvo_priv->cur_saturation); + sdvo_connector->saturation_property, + sdvo_connector->cur_saturation); DRM_DEBUG_KMS("saturation: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2692,16 +2869,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO get contrast\n"); return; } - sdvo_priv->max_contrast = data_value[0]; - sdvo_priv->cur_contrast = response; - sdvo_priv->contrast_property = + sdvo_connector->max_contrast = data_value[0]; + sdvo_connector->cur_contrast = response; + sdvo_connector->contrast_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "contrast", 2); - sdvo_priv->contrast_property->values[0] = 0; - sdvo_priv->contrast_property->values[1] = data_value[0]; + sdvo_connector->contrast_property->values[0] = 0; + sdvo_connector->contrast_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->contrast_property, - sdvo_priv->cur_contrast); + sdvo_connector->contrast_property, + sdvo_connector->cur_contrast); DRM_DEBUG_KMS("contrast: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2723,22 +2900,24 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO get hue\n"); return; } - sdvo_priv->max_hue = data_value[0]; - sdvo_priv->cur_hue = response; - sdvo_priv->hue_property = + sdvo_connector->max_hue = data_value[0]; + sdvo_connector->cur_hue = response; + sdvo_connector->hue_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hue", 2); - sdvo_priv->hue_property->values[0] = 0; - sdvo_priv->hue_property->values[1] = + sdvo_connector->hue_property->values[0] = 0; + sdvo_connector->hue_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->hue_property, - sdvo_priv->cur_hue); + sdvo_connector->hue_property, + sdvo_connector->cur_hue); DRM_DEBUG_KMS("hue: max %d, default %d, current %d\n", data_value[0], data_value[1], response); } } - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { + + if (SDVO_CONNECTOR_IS_TV(sdvo_connector) || + SDVO_CONNECTOR_IS_LVDS(sdvo_connector)) { if (sdvo_data.brightness) { intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0); @@ -2756,17 +2935,17 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("Incorrect SDVO get brigh\n"); return; } - sdvo_priv->max_brightness = data_value[0]; - sdvo_priv->cur_brightness = response; - sdvo_priv->brightness_property = + sdvo_connector->max_brightness = data_value[0]; + sdvo_connector->cur_brightness = response; + sdvo_connector->brightness_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "brightness", 2); - sdvo_priv->brightness_property->values[0] = 0; - sdvo_priv->brightness_property->values[1] = + sdvo_connector->brightness_property->values[0] = 0; + sdvo_connector->brightness_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->brightness_property, - sdvo_priv->cur_brightness); + sdvo_connector->brightness_property, + sdvo_connector->cur_brightness); DRM_DEBUG_KMS("brightness: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2778,23 +2957,21 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) bool intel_sdvo_init(struct drm_device *dev, int output_device) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_connector *connector; - struct intel_connector *intel_connector; + struct drm_encoder *encoder; struct intel_encoder *intel_encoder; - struct intel_sdvo_priv *sdvo_priv; + struct intel_sdvo_encoder *sdvo_encoder; u8 ch[0x40]; int i; - intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); - intel_encoder = kzalloc(sizeof(*intel_encoder) + sizeof(*sdvo_priv), GFP_KERNEL); + intel_encoder = kzalloc(sizeof(*intel_encoder) + sizeof(*sdvo_encoder), GFP_KERNEL); - if (!intel_connector || !intel_encoder) + if (!intel_encoder) return false; - sdvo_priv = (struct intel_sdvo_priv *)(intel_encoder + 1); - sdvo_priv->output_device = output_device; + sdvo_encoder = (struct intel_sdvo_encoder *)(intel_encoder + 1); + sdvo_encoder->output_device = output_device; - intel_encoder->dev_priv = sdvo_priv; + intel_encoder->dev_priv = sdvo_encoder; intel_encoder->type = INTEL_OUTPUT_SDVO; /* setup the DDC bus. */ @@ -2804,9 +2981,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) intel_encoder->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); if (!intel_encoder->i2c_bus) - goto err_inteloutput; + goto err; - sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, output_device); + sdvo_encoder->slave_addr = intel_sdvo_get_slave_addr(dev, output_device); /* Save the bit-banging i2c functionality for use by the DDC wrapper */ intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality; @@ -2816,102 +2993,59 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) if (!intel_sdvo_read_byte(intel_encoder, i, &ch[i])) { DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", output_device == SDVOB ? 'B' : 'C'); - goto err_i2c; + goto err; } } - /* setup the DDC bus. */ - if (output_device == SDVOB) { - intel_connector->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, - "SDVOB/VGA DDC BUS"); + if (output_device == SDVOB) dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; - } else { - intel_connector->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, - "SDVOC/VGA DDC BUS"); + else dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; - } - if (intel_connector->ddc_bus == NULL) - goto err_i2c; - - /* Wrap with our custom algo which switches to DDC mode */ - intel_connector->ddc_bus->algo = &intel_sdvo_i2c_bit_algo; + encoder = &intel_encoder->base; + /* encoder type will be decided later */ + drm_encoder_init(dev, encoder, &intel_sdvo_enc_funcs, 0); + drm_encoder_helper_add(encoder, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ - intel_sdvo_get_capabilities(intel_encoder, &sdvo_priv->caps); + intel_sdvo_get_capabilities(intel_encoder, &sdvo_encoder->caps); - if (intel_sdvo_output_setup(intel_encoder, intel_connector, - sdvo_priv->caps.output_flags) != true) { + if (intel_sdvo_output_setup(intel_encoder) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", output_device == SDVOB ? 'B' : 'C'); - goto err_i2c; + goto err; } - - connector = &intel_connector->base; - drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, - connector->connector_type); - - drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - connector->display_info.subpixel_order = SubPixelHorizontalRGB; - - drm_encoder_init(dev, &intel_encoder->base, - &intel_sdvo_enc_funcs, intel_encoder->base.encoder_type); - - drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); - - drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->base); - if (sdvo_priv->is_tv) - intel_sdvo_tv_create_property(connector); - - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) - intel_sdvo_create_enhance_property(connector); - - drm_sysfs_connector_add(connector); - - intel_sdvo_select_ddc_bus(sdvo_priv); + intel_sdvo_select_ddc_bus(sdvo_encoder); /* Set the input timing to the screen. Assume always input 0. */ intel_sdvo_set_target_input(intel_encoder, true, false); intel_sdvo_get_input_pixel_clock_range(intel_encoder, - &sdvo_priv->pixel_clock_min, - &sdvo_priv->pixel_clock_max); + &sdvo_encoder->pixel_clock_min, + &sdvo_encoder->pixel_clock_max); DRM_DEBUG_KMS("%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', + SDVO_NAME(sdvo_encoder), + sdvo_encoder->caps.vendor_id, sdvo_encoder->caps.device_id, + sdvo_encoder->caps.device_rev_id, + sdvo_encoder->pixel_clock_min / 1000, + sdvo_encoder->pixel_clock_max / 1000, + (sdvo_encoder->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (sdvo_encoder->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', /* check currently supported outputs */ - sdvo_priv->caps.output_flags & + sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', - sdvo_priv->caps.output_flags & + sdvo_encoder->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; -err_i2c: - if (sdvo_priv->analog_ddc_bus != NULL) - intel_i2c_destroy(sdvo_priv->analog_ddc_bus); - if (intel_connector->ddc_bus != NULL) - intel_i2c_destroy(intel_connector->ddc_bus); - if (intel_encoder->i2c_bus != NULL) - intel_i2c_destroy(intel_encoder->i2c_bus); -err_inteloutput: +err: kfree(intel_encoder); - kfree(intel_connector); - return false; }