summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_sdvo.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_sdvo.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_sdvo.c385
1 files changed, 198 insertions, 187 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 7d25a64698e2..a636f42ceae5 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -44,6 +44,7 @@
#include "intel_crtc.h"
#include "intel_de.h"
#include "intel_display_types.h"
+#include "intel_fdi.h"
#include "intel_fifo_underrun.h"
#include "intel_gmbus.h"
#include "intel_hdmi.h"
@@ -57,15 +58,16 @@
#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)
#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0)
-#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\
- SDVO_TV_MASK)
+#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK | SDVO_TV_MASK)
-#define IS_TV(c) (c->output_flag & SDVO_TV_MASK)
-#define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK)
-#define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK)
-#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
-#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK))
+#define IS_TV(c) ((c)->output_flag & SDVO_TV_MASK)
+#define IS_TMDS(c) ((c)->output_flag & SDVO_TMDS_MASK)
+#define IS_LVDS(c) ((c)->output_flag & SDVO_LVDS_MASK)
+#define IS_TV_OR_LVDS(c) ((c)->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
+#define IS_DIGITAL(c) ((c)->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK))
+#define HAS_DDC(c) ((c)->output_flag & (SDVO_RGB_MASK | SDVO_TMDS_MASK | \
+ SDVO_LVDS_MASK))
static const char * const tv_format_names[] = {
"NTSC_M" , "NTSC_J" , "NTSC_443",
@@ -79,20 +81,25 @@ static const char * const tv_format_names[] = {
#define TV_FORMAT_NUM ARRAY_SIZE(tv_format_names)
+struct intel_sdvo;
+
+struct intel_sdvo_ddc {
+ struct i2c_adapter ddc;
+ struct intel_sdvo *sdvo;
+ u8 ddc_bus;
+};
+
struct intel_sdvo {
struct intel_encoder base;
struct i2c_adapter *i2c;
u8 slave_addr;
- struct i2c_adapter ddc;
+ struct intel_sdvo_ddc ddc[3];
/* Register for the SDVO device: SDVOB or SDVOC */
i915_reg_t sdvo_reg;
- /* Active outputs controlled by this SDVO output */
- u16 controlled_output;
-
/*
* Capabilities of the SDVO device returned by
* intel_sdvo_get_capabilities()
@@ -105,21 +112,10 @@ struct intel_sdvo {
int pixel_clock_min, pixel_clock_max;
/*
- * For multiple function SDVO device,
- * this is for current attached outputs.
- */
- u16 attached_output;
-
- /*
* Hotplug activation bits for this device
*/
u16 hotplug_active;
- enum port port;
-
- /* DDC bus used by this SDVO encoder */
- u8 ddc_bus;
-
/*
* the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd
*/
@@ -233,7 +229,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
return;
}
- if (intel_sdvo->port == PORT_B)
+ if (intel_sdvo->base.port == PORT_B)
cval = intel_de_read(dev_priv, GEN3_SDVOC);
else
bval = intel_de_read(dev_priv, GEN3_SDVOB);
@@ -410,7 +406,7 @@ static const char *sdvo_cmd_name(u8 cmd)
return NULL;
}
-#define SDVO_NAME(svdo) ((svdo)->port == PORT_B ? "SDVOB" : "SDVOC")
+#define SDVO_NAME(svdo) ((svdo)->base.port == PORT_B ? "SDVOB" : "SDVOC")
static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
const void *args, int args_len)
@@ -653,7 +649,7 @@ intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len
static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo)
{
- struct intel_sdvo_set_target_input_args targets = {0};
+ struct intel_sdvo_set_target_input_args targets = {};
return intel_sdvo_set_value(intel_sdvo,
SDVO_CMD_SET_TARGET_INPUT,
&targets, sizeof(targets));
@@ -1224,12 +1220,13 @@ static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo,
static bool
intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
+ struct intel_sdvo_connector *intel_sdvo_connector,
const struct drm_display_mode *mode)
{
struct intel_sdvo_dtd output_dtd;
if (!intel_sdvo_set_target_output(intel_sdvo,
- intel_sdvo->attached_output))
+ intel_sdvo_connector->output_flag))
return false;
intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
@@ -1270,10 +1267,10 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
return true;
}
-static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
+static int i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = to_i915(pipe_config->uapi.crtc->dev);
- unsigned dotclock = pipe_config->port_clock;
+ unsigned int dotclock = pipe_config->hw.adjusted_mode.crtc_clock;
struct dpll *clock = &pipe_config->dpll;
/*
@@ -1293,11 +1290,14 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
clock->m1 = 12;
clock->m2 = 8;
} else {
- drm_WARN(&dev_priv->drm, 1,
- "SDVO TV clock out of range: %i\n", dotclock);
+ drm_dbg_kms(&dev_priv->drm,
+ "SDVO TV clock out of range: %i\n", dotclock);
+ return -EINVAL;
}
pipe_config->clock_set = true;
+
+ return 0;
}
static bool intel_has_hdmi_sink(struct intel_sdvo_connector *intel_sdvo_connector,
@@ -1352,14 +1352,18 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
struct drm_display_mode *mode = &pipe_config->hw.mode;
+ if (HAS_PCH_SPLIT(to_i915(encoder->base.dev))) {
+ pipe_config->has_pch_encoder = true;
+ if (!intel_fdi_compute_pipe_bpp(pipe_config))
+ return -EINVAL;
+ }
+
DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
+ /* FIXME: Don't increase pipe_bpp */
pipe_config->pipe_bpp = 8*3;
pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB;
pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
- if (HAS_PCH_SPLIT(to_i915(encoder->base.dev)))
- pipe_config->has_pch_encoder = true;
-
/*
* We need to construct preferred input timings based on our
* output timings. To do that, we have to set the output
@@ -1367,7 +1371,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
* the sequence to do it. Oh well.
*/
if (IS_TV(intel_sdvo_connector)) {
- if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
+ if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
+ intel_sdvo_connector,
+ mode))
return -EINVAL;
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
@@ -1385,7 +1391,9 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
if (ret)
return ret;
- if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, fixed_mode))
+ if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
+ intel_sdvo_connector,
+ fixed_mode))
return -EINVAL;
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
@@ -1415,8 +1423,13 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder,
conn_state);
/* Clock computation needs to happen after pixel multiplier. */
- if (IS_TV(intel_sdvo_connector))
- i9xx_adjust_sdvo_tv_clock(pipe_config);
+ if (IS_TV(intel_sdvo_connector)) {
+ int ret;
+
+ ret = i9xx_adjust_sdvo_tv_clock(pipe_config);
+ if (ret)
+ return ret;
+ }
if (conn_state->picture_aspect_ratio)
adjusted_mode->picture_aspect_ratio =
@@ -1521,7 +1534,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
* channel on the motherboard. In a two-input device, the first input
* will be SDVOB and the second SDVOC.
*/
- in_out.in0 = intel_sdvo->attached_output;
+ in_out.in0 = intel_sdvo_connector->output_flag;
in_out.in1 = 0;
intel_sdvo_set_value(intel_sdvo,
@@ -1530,7 +1543,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
/* Set the output timings to the screen */
if (!intel_sdvo_set_target_output(intel_sdvo,
- intel_sdvo->attached_output))
+ intel_sdvo_connector->output_flag))
return;
/* lvds has a special fixed output timing. */
@@ -1598,7 +1611,7 @@ static void intel_sdvo_pre_enable(struct intel_atomic_state *state,
sdvox |= SDVO_BORDER_ENABLE;
} else {
sdvox = intel_de_read(dev_priv, intel_sdvo->sdvo_reg);
- if (intel_sdvo->port == PORT_B)
+ if (intel_sdvo->base.port == PORT_B)
sdvox &= SDVOB_PRESERVE_MASK;
else
sdvox &= SDVOC_PRESERVE_MASK;
@@ -1867,6 +1880,8 @@ static void intel_enable_sdvo(struct intel_atomic_state *state,
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
+ struct intel_sdvo_connector *intel_sdvo_connector =
+ to_intel_sdvo_connector(conn_state->connector);
struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
u32 temp;
bool input1, input2;
@@ -1896,7 +1911,7 @@ static void intel_enable_sdvo(struct intel_atomic_state *state,
if (0)
intel_sdvo_set_encoder_power_state(intel_sdvo,
DRM_MODE_DPMS_ON);
- intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
+ intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo_connector->output_flag);
if (pipe_config->has_audio)
intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state);
@@ -1956,7 +1971,7 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
" device_rev_id: %d\n"
" sdvo_version_major: %d\n"
" sdvo_version_minor: %d\n"
- " sdvo_inputs_mask: %d\n"
+ " sdvo_num_inputs: %d\n"
" smooth_scaling: %d\n"
" sharp_scaling: %d\n"
" up_scaling: %d\n"
@@ -1968,7 +1983,7 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
caps->device_rev_id,
caps->sdvo_version_major,
caps->sdvo_version_minor,
- caps->sdvo_inputs_mask,
+ caps->sdvo_num_inputs,
caps->smooth_scaling,
caps->sharp_scaling,
caps->up_scaling,
@@ -2029,18 +2044,15 @@ intel_sdvo_hotplug(struct intel_encoder *encoder,
return intel_encoder_hotplug(encoder, connector);
}
-static bool
-intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
-{
- /* Is there more than one type of output? */
- return hweight16(intel_sdvo->caps.output_flags) > 1;
-}
-
static const struct drm_edid *
intel_sdvo_get_edid(struct drm_connector *connector)
{
- struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector));
- return drm_edid_read_ddc(connector, &sdvo->ddc);
+ struct i2c_adapter *ddc = connector->ddc;
+
+ if (!ddc)
+ return NULL;
+
+ return drm_edid_read_ddc(connector, ddc);
}
/* Mac mini hack -- use the same DDC as the analog connector */
@@ -2048,43 +2060,23 @@ static const struct drm_edid *
intel_sdvo_get_analog_edid(struct drm_connector *connector)
{
struct drm_i915_private *i915 = to_i915(connector->dev);
- struct i2c_adapter *i2c;
+ struct i2c_adapter *ddc;
- i2c = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin);
+ ddc = intel_gmbus_get_adapter(i915, i915->display.vbt.crt_ddc_pin);
+ if (!ddc)
+ return NULL;
- return drm_edid_read_ddc(connector, i2c);
+ return drm_edid_read_ddc(connector, ddc);
}
static enum drm_connector_status
intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
{
- struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
enum drm_connector_status status;
const struct drm_edid *drm_edid;
drm_edid = intel_sdvo_get_edid(connector);
- if (!drm_edid && intel_sdvo_multifunc_encoder(intel_sdvo)) {
- u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
-
- /*
- * Don't use the 1 as the argument of DDC bus switch to get
- * the EDID. It is used for SDVO SPD ROM.
- */
- for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
- intel_sdvo->ddc_bus = ddc;
- drm_edid = intel_sdvo_get_edid(connector);
- if (drm_edid)
- break;
- }
- /*
- * If we found the EDID on the other bus,
- * assume that is the correct DDC bus.
- */
- if (!drm_edid)
- intel_sdvo->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.
@@ -2094,10 +2086,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
status = connector_status_unknown;
if (drm_edid) {
- const struct edid *edid = drm_edid_raw(drm_edid);
-
/* DDC bus is shared, match EDID to connector type */
- if (edid && edid->input & DRM_EDID_INPUT_DIGITAL)
+ if (drm_edid_is_digital(drm_edid))
status = connector_status_connected;
else
status = connector_status_disconnected;
@@ -2111,8 +2101,7 @@ static bool
intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
const struct drm_edid *drm_edid)
{
- const struct edid *edid = drm_edid_raw(drm_edid);
- bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
+ bool monitor_is_digital = drm_edid_is_digital(drm_edid);
bool connector_is_digital = !!IS_DIGITAL(sdvo);
DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n",
@@ -2132,9 +2121,13 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
- if (!INTEL_DISPLAY_ENABLED(i915))
+ if (!intel_display_device_enabled(i915))
return connector_status_disconnected;
+ if (!intel_sdvo_set_target_output(intel_sdvo,
+ intel_sdvo_connector->output_flag))
+ return connector_status_unknown;
+
if (!intel_sdvo_get_value(intel_sdvo,
SDVO_CMD_GET_ATTACHED_DISPLAYS,
&response, 2))
@@ -2147,8 +2140,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
if (response == 0)
return connector_status_disconnected;
- intel_sdvo->attached_output = response;
-
if ((intel_sdvo_connector->output_flag & response) == 0)
ret = connector_status_disconnected;
else if (IS_TMDS(intel_sdvo_connector))
@@ -2276,6 +2267,8 @@ static const struct drm_display_mode sdvo_tv_modes[] = {
static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
{
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
+ struct intel_sdvo_connector *intel_sdvo_connector =
+ to_intel_sdvo_connector(connector);
const struct drm_connector_state *conn_state = connector->state;
struct intel_sdvo_sdtv_resolution_request tv_res;
u32 reply = 0, format_map = 0;
@@ -2293,7 +2286,7 @@ static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
memcpy(&tv_res, &format_map,
min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request)));
- if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output))
+ if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo_connector->output_flag))
return 0;
BUILD_BUG_ON(sizeof(tv_res) != 3);
@@ -2458,31 +2451,6 @@ intel_sdvo_connector_atomic_set_property(struct drm_connector *connector,
return 0;
}
-static int
-intel_sdvo_connector_register(struct drm_connector *connector)
-{
- struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector));
- int ret;
-
- ret = intel_connector_register(connector);
- if (ret)
- return ret;
-
- return sysfs_create_link(&connector->kdev->kobj,
- &sdvo->ddc.dev.kobj,
- sdvo->ddc.dev.kobj.name);
-}
-
-static void
-intel_sdvo_connector_unregister(struct drm_connector *connector)
-{
- struct intel_sdvo *sdvo = intel_attached_sdvo(to_intel_connector(connector));
-
- sysfs_remove_link(&connector->kdev->kobj,
- sdvo->ddc.dev.kobj.name);
- intel_connector_unregister(connector);
-}
-
static struct drm_connector_state *
intel_sdvo_connector_duplicate_state(struct drm_connector *connector)
{
@@ -2501,8 +2469,8 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.atomic_get_property = intel_sdvo_connector_atomic_get_property,
.atomic_set_property = intel_sdvo_connector_atomic_set_property,
- .late_register = intel_sdvo_connector_register,
- .early_unregister = intel_sdvo_connector_unregister,
+ .late_register = intel_connector_register,
+ .early_unregister = intel_connector_unregister,
.destroy = intel_connector_destroy,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
.atomic_duplicate_state = intel_sdvo_connector_duplicate_state,
@@ -2539,29 +2507,37 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs
.atomic_check = intel_sdvo_atomic_check,
};
-static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
+static void intel_sdvo_encoder_destroy(struct drm_encoder *_encoder)
{
- struct intel_sdvo *intel_sdvo = to_sdvo(to_intel_encoder(encoder));
+ struct intel_encoder *encoder = to_intel_encoder(_encoder);
+ struct intel_sdvo *sdvo = to_sdvo(encoder);
+ int i;
- i2c_del_adapter(&intel_sdvo->ddc);
- intel_encoder_destroy(encoder);
-}
+ for (i = 0; i < ARRAY_SIZE(sdvo->ddc); i++) {
+ if (sdvo->ddc[i].ddc_bus)
+ i2c_del_adapter(&sdvo->ddc[i].ddc);
+ }
+
+ drm_encoder_cleanup(&encoder->base);
+ kfree(sdvo);
+};
static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
- .destroy = intel_sdvo_enc_destroy,
+ .destroy = intel_sdvo_encoder_destroy,
};
-static void
-intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
+static int
+intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo,
+ struct intel_sdvo_connector *connector)
{
u16 mask = 0;
- unsigned int num_bits;
+ int num_bits;
/*
* Make a mask of outputs less than or equal to our own priority in the
* list.
*/
- switch (sdvo->controlled_output) {
+ switch (connector->output_flag) {
case SDVO_OUTPUT_LVDS1:
mask |= SDVO_OUTPUT_LVDS1;
fallthrough;
@@ -2590,7 +2566,7 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
num_bits = 3;
/* Corresponds to SDVO_CONTROL_BUS_DDCx */
- sdvo->ddc_bus = 1 << num_bits;
+ return num_bits;
}
/*
@@ -2600,31 +2576,38 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
* DDC bus number assignment is in a priority order of RGB outputs, then TMDS
* outputs, then LVDS outputs.
*/
-static void
-intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
- struct intel_sdvo *sdvo)
+static struct intel_sdvo_ddc *
+intel_sdvo_select_ddc_bus(struct intel_sdvo *sdvo,
+ struct intel_sdvo_connector *connector)
{
- struct sdvo_device_mapping *mapping;
+ struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev);
+ const struct sdvo_device_mapping *mapping;
+ int ddc_bus;
- if (sdvo->port == PORT_B)
+ if (sdvo->base.port == PORT_B)
mapping = &dev_priv->display.vbt.sdvo_mappings[0];
else
mapping = &dev_priv->display.vbt.sdvo_mappings[1];
if (mapping->initialized)
- sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4);
+ ddc_bus = (mapping->ddc_pin & 0xf0) >> 4;
else
- intel_sdvo_guess_ddc_bus(sdvo);
+ ddc_bus = intel_sdvo_guess_ddc_bus(sdvo, connector);
+
+ if (ddc_bus < 1 || ddc_bus > 3)
+ return NULL;
+
+ return &sdvo->ddc[ddc_bus - 1];
}
static void
-intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
- struct intel_sdvo *sdvo)
+intel_sdvo_select_i2c_bus(struct intel_sdvo *sdvo)
{
- struct sdvo_device_mapping *mapping;
+ struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev);
+ const struct sdvo_device_mapping *mapping;
u8 pin;
- if (sdvo->port == PORT_B)
+ if (sdvo->base.port == PORT_B)
mapping = &dev_priv->display.vbt.sdvo_mappings[0];
else
mapping = &dev_priv->display.vbt.sdvo_mappings[1];
@@ -2635,6 +2618,10 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
else
pin = GMBUS_PIN_DPB;
+ drm_dbg_kms(&dev_priv->drm, "[ENCODER:%d:%s] I2C pin %d, slave addr 0x%x\n",
+ sdvo->base.base.base.id, sdvo->base.base.name,
+ pin, sdvo->slave_addr);
+
sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin);
/*
@@ -2659,12 +2646,12 @@ intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo)
}
static u8
-intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv,
- struct intel_sdvo *sdvo)
+intel_sdvo_get_slave_addr(struct intel_sdvo *sdvo)
{
- struct sdvo_device_mapping *my_mapping, *other_mapping;
+ struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev);
+ const struct sdvo_device_mapping *my_mapping, *other_mapping;
- if (sdvo->port == PORT_B) {
+ if (sdvo->base.port == PORT_B) {
my_mapping = &dev_priv->display.vbt.sdvo_mappings[0];
other_mapping = &dev_priv->display.vbt.sdvo_mappings[1];
} else {
@@ -2691,28 +2678,36 @@ intel_sdvo_get_slave_addr(struct drm_i915_private *dev_priv,
* No SDVO device info is found for another DVO port,
* so use mapping assumption we had before BIOS parsing.
*/
- if (sdvo->port == PORT_B)
+ if (sdvo->base.port == PORT_B)
return 0x70;
else
return 0x72;
}
static int
+intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc,
+ struct intel_sdvo *sdvo, int bit);
+
+static int
intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
struct intel_sdvo *encoder)
{
- struct drm_connector *drm_connector;
+ struct drm_i915_private *i915 = to_i915(encoder->base.base.dev);
+ struct intel_sdvo_ddc *ddc = NULL;
int ret;
- drm_connector = &connector->base.base;
- ret = drm_connector_init(encoder->base.base.dev,
- drm_connector,
- &intel_sdvo_connector_funcs,
- connector->base.base.connector_type);
+ if (HAS_DDC(connector))
+ ddc = intel_sdvo_select_ddc_bus(encoder, connector);
+
+ ret = drm_connector_init_with_ddc(encoder->base.base.dev,
+ &connector->base.base,
+ &intel_sdvo_connector_funcs,
+ connector->base.base.connector_type,
+ ddc ? &ddc->ddc : NULL);
if (ret < 0)
return ret;
- drm_connector_helper_add(drm_connector,
+ drm_connector_helper_add(&connector->base.base,
&intel_sdvo_connector_helper_funcs);
connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
@@ -2721,6 +2716,11 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
intel_connector_attach_encoder(&connector->base, &encoder->base);
+ if (ddc)
+ drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] using %s\n",
+ connector->base.base.base.id, connector->base.base.name,
+ ddc->ddc.name);
+
return 0;
}
@@ -2918,7 +2918,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
if (!intel_panel_preferred_fixed_mode(intel_connector)) {
mutex_lock(&i915->drm.mode_config.mutex);
- intel_ddc_get_modes(connector, &intel_sdvo->ddc);
+ intel_ddc_get_modes(connector, connector->ddc);
intel_panel_add_edid_fixed_modes(intel_connector, false);
mutex_unlock(&i915->drm.mode_config.mutex);
@@ -2982,7 +2982,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
SDVO_OUTPUT_LVDS0,
SDVO_OUTPUT_LVDS1,
};
- struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
u16 flags;
int i;
@@ -2994,10 +2993,6 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo)
return false;
}
- intel_sdvo->controlled_output = flags;
-
- intel_sdvo_select_ddc_bus(i915, intel_sdvo);
-
for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
u16 type = flags & probe_order[i];
@@ -3250,9 +3245,10 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs,
int num)
{
- struct intel_sdvo *sdvo = adapter->algo_data;
+ struct intel_sdvo_ddc *ddc = adapter->algo_data;
+ struct intel_sdvo *sdvo = ddc->sdvo;
- if (!__intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
+ if (!__intel_sdvo_set_control_bus_switch(sdvo, 1 << ddc->ddc_bus))
return -EIO;
return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
@@ -3260,7 +3256,9 @@ static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
{
- struct intel_sdvo *sdvo = adapter->algo_data;
+ struct intel_sdvo_ddc *ddc = adapter->algo_data;
+ struct intel_sdvo *sdvo = ddc->sdvo;
+
return sdvo->i2c->algo->functionality(sdvo->i2c);
}
@@ -3272,21 +3270,27 @@ static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
static void proxy_lock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
- struct intel_sdvo *sdvo = adapter->algo_data;
+ struct intel_sdvo_ddc *ddc = adapter->algo_data;
+ struct intel_sdvo *sdvo = ddc->sdvo;
+
sdvo->i2c->lock_ops->lock_bus(sdvo->i2c, flags);
}
static int proxy_trylock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
- struct intel_sdvo *sdvo = adapter->algo_data;
+ struct intel_sdvo_ddc *ddc = adapter->algo_data;
+ struct intel_sdvo *sdvo = ddc->sdvo;
+
return sdvo->i2c->lock_ops->trylock_bus(sdvo->i2c, flags);
}
static void proxy_unlock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
- struct intel_sdvo *sdvo = adapter->algo_data;
+ struct intel_sdvo_ddc *ddc = adapter->algo_data;
+ struct intel_sdvo *sdvo = ddc->sdvo;
+
sdvo->i2c->lock_ops->unlock_bus(sdvo->i2c, flags);
}
@@ -3296,21 +3300,26 @@ static const struct i2c_lock_operations proxy_lock_ops = {
.unlock_bus = proxy_unlock_bus,
};
-static bool
-intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
- struct drm_i915_private *dev_priv)
+static int
+intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc,
+ struct intel_sdvo *sdvo, int ddc_bus)
{
+ struct drm_i915_private *dev_priv = to_i915(sdvo->base.base.dev);
struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev);
- sdvo->ddc.owner = THIS_MODULE;
- sdvo->ddc.class = I2C_CLASS_DDC;
- snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
- sdvo->ddc.dev.parent = &pdev->dev;
- sdvo->ddc.algo_data = sdvo;
- sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
- sdvo->ddc.lock_ops = &proxy_lock_ops;
+ ddc->sdvo = sdvo;
+ ddc->ddc_bus = ddc_bus;
- return i2c_add_adapter(&sdvo->ddc) == 0;
+ ddc->ddc.owner = THIS_MODULE;
+ ddc->ddc.class = I2C_CLASS_DDC;
+ snprintf(ddc->ddc.name, I2C_NAME_SIZE, "SDVO %c DDC%d",
+ port_name(sdvo->base.port), ddc_bus);
+ ddc->ddc.dev.parent = &pdev->dev;
+ ddc->ddc.algo_data = ddc;
+ ddc->ddc.algo = &intel_sdvo_ddc_proxy;
+ ddc->ddc.lock_ops = &proxy_lock_ops;
+
+ return i2c_add_adapter(&ddc->ddc);
}
static bool is_sdvo_port_valid(struct drm_i915_private *dev_priv, enum port port)
@@ -3345,23 +3354,21 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
if (!intel_sdvo)
return false;
- intel_sdvo->sdvo_reg = sdvo_reg;
- intel_sdvo->port = port;
- intel_sdvo->slave_addr =
- intel_sdvo_get_slave_addr(dev_priv, intel_sdvo) >> 1;
- intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo);
- if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev_priv))
- goto err_i2c_bus;
-
/* encoder type will be decided later */
intel_encoder = &intel_sdvo->base;
intel_encoder->type = INTEL_OUTPUT_SDVO;
intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
intel_encoder->port = port;
+
drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
&intel_sdvo_enc_funcs, 0,
"SDVO %c", port_name(port));
+ intel_sdvo->sdvo_reg = sdvo_reg;
+ intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(intel_sdvo) >> 1;
+
+ intel_sdvo_select_i2c_bus(intel_sdvo);
+
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
u8 byte;
@@ -3393,6 +3400,15 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
intel_sdvo->colorimetry_cap =
intel_sdvo_get_colorimetry_cap(intel_sdvo);
+ for (i = 0; i < ARRAY_SIZE(intel_sdvo->ddc); i++) {
+ int ret;
+
+ ret = intel_sdvo_init_ddc_proxy(&intel_sdvo->ddc[i],
+ intel_sdvo, i + 1);
+ if (ret)
+ goto err;
+ }
+
if (!intel_sdvo_output_setup(intel_sdvo)) {
drm_dbg_kms(&dev_priv->drm,
"SDVO output failed to setup on %s\n",
@@ -3406,7 +3422,7 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
* hotplug lines.
*/
if (intel_sdvo->hotplug_active) {
- if (intel_sdvo->port == PORT_B)
+ if (intel_sdvo->base.port == PORT_B)
intel_encoder->hpd_pin = HPD_SDVO_B;
else
intel_encoder->hpd_pin = HPD_SDVO_C;
@@ -3433,15 +3449,14 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
drm_dbg_kms(&dev_priv->drm, "%s device VID/DID: %02X:%02X.%02X, "
"clock range %dMHz - %dMHz, "
- "input 1: %c, input 2: %c, "
+ "num inputs: %d, "
"output 1: %c, output 2: %c\n",
SDVO_NAME(intel_sdvo),
intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
intel_sdvo->caps.device_rev_id,
intel_sdvo->pixel_clock_min / 1000,
intel_sdvo->pixel_clock_max / 1000,
- (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
- (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+ intel_sdvo->caps.sdvo_num_inputs,
/* check currently supported outputs */
intel_sdvo->caps.output_flags &
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0 |
@@ -3454,13 +3469,9 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv,
err_output:
intel_sdvo_output_cleanup(intel_sdvo);
-
err:
- drm_encoder_cleanup(&intel_encoder->base);
- i2c_del_adapter(&intel_sdvo->ddc);
-err_i2c_bus:
intel_sdvo_unselect_i2c_bus(intel_sdvo);
- kfree(intel_sdvo);
+ intel_sdvo_encoder_destroy(&intel_encoder->base);
return false;
}