aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_connectors.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_connectors.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c178
1 files changed, 95 insertions, 83 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 4c4c924..f1a1e8a 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -44,6 +44,8 @@ extern void
radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
struct drm_connector *drm_connector);
+bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector);
+
void radeon_connector_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
@@ -449,24 +451,65 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr
return 0;
}
+/*
+ * Some integrated ATI Radeon chipset implementations (e. g.
+ * Asus M2A-VM HDMI) may indicate the availability of a DDC,
+ * even when there's no monitor connected. For these connectors
+ * following DDC probe extension will be applied: check also for the
+ * availability of EDID with at least a correct EDID header. Only then,
+ * DDC is assumed to be available. This prevents drm_get_edid() and
+ * drm_edid_block_valid() from periodically dumping data and kernel
+ * errors into the logs and onto the terminal.
+ */
+static bool radeon_connector_needs_extended_probe(struct radeon_device *dev,
+ uint32_t supported_device,
+ int connector_type)
+{
+ /* Asus M2A-VM HDMI board sends data to i2c bus even,
+ * if HDMI add-on card is not plugged in or HDMI is disabled in
+ * BIOS. Valid DDC can only be assumed, if also a valid EDID header
+ * can be retrieved via i2c bus during DDC probe */
+ if ((dev->pdev->device == 0x791e) &&
+ (dev->pdev->subsystem_vendor == 0x1043) &&
+ (dev->pdev->subsystem_device == 0x826d)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
+ /* ECS A740GM-M with ATI RADEON 2100 sends data to i2c bus
+ * for a DVI connector that is not implemented */
+ if ((dev->pdev->device == 0x796e) &&
+ (dev->pdev->subsystem_vendor == 0x1019) &&
+ (dev->pdev->subsystem_device == 0x2615)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_DVID) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
+ /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100
+ * (RS690M) sends data to i2c bus for a HDMI connector that
+ * is not implemented */
+ if ((dev->pdev->device == 0x791f) &&
+ (dev->pdev->subsystem_vendor == 0x1179) &&
+ (dev->pdev->subsystem_device == 0xff68)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
+
+ /* Default: no EDID header probe required for DDC probing */
+ return false;
+}
+
static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
struct drm_connector *connector)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
- struct drm_display_mode *t, *mode;
-
- /* If the EDID preferred mode doesn't match the native mode, use it */
- list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
- if (mode->type & DRM_MODE_TYPE_PREFERRED) {
- if (mode->hdisplay != native_mode->hdisplay ||
- mode->vdisplay != native_mode->vdisplay)
- memcpy(native_mode, mode, sizeof(*mode));
- }
- }
/* Try to get native mode details from EDID if necessary */
if (!native_mode->clock) {
+ struct drm_display_mode *t, *mode;
+
list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
if (mode->hdisplay == native_mode->hdisplay &&
mode->vdisplay == native_mode->vdisplay) {
@@ -477,7 +520,6 @@ static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
}
}
}
-
if (!native_mode->clock) {
DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
radeon_encoder->rmx_type = RMX_OFF;
@@ -689,7 +731,8 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
ret = connector_status_disconnected;
if (radeon_connector->ddc_bus)
- dret = radeon_ddc_probe(radeon_connector);
+ dret = radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe);
if (dret) {
radeon_connector->detected_by_load = false;
if (radeon_connector->edid) {
@@ -846,27 +889,6 @@ static int radeon_dvi_get_modes(struct drm_connector *connector)
return ret;
}
-static bool radeon_check_hpd_status_unchanged(struct drm_connector *connector)
-{
- struct drm_device *dev = connector->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_connector *radeon_connector = to_radeon_connector(connector);
- enum drm_connector_status status;
-
- /* We only trust HPD on R600 and newer ASICS. */
- if (rdev->family >= CHIP_R600
- && radeon_connector->hpd.hpd != RADEON_HPD_NONE) {
- if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
- status = connector_status_connected;
- else
- status = connector_status_disconnected;
- if (connector->status == status)
- return true;
- }
-
- return false;
-}
-
/*
* DVI is complicated
* Do a DDC probe, if DDC probe passes, get the full EDID so
@@ -891,11 +913,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
enum drm_connector_status ret = connector_status_disconnected;
bool dret = false;
- if (!force && radeon_check_hpd_status_unchanged(connector))
- return connector->status;
-
if (radeon_connector->ddc_bus)
- dret = radeon_ddc_probe(radeon_connector);
+ dret = radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe);
if (dret) {
radeon_connector->detected_by_load = false;
if (radeon_connector->edid) {
@@ -1104,7 +1124,7 @@ static int radeon_dvi_mode_valid(struct drm_connector *connector,
(radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B))
return MODE_OK;
else if (radeon_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_A) {
- if (0) {
+ if (ASIC_IS_DCE3(rdev)) {
/* HDMI 1.3+ supports max clock of 340 Mhz */
if (mode->clock > 340000)
return MODE_CLOCK_HIGH;
@@ -1164,23 +1184,13 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
(connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) {
struct drm_display_mode *mode;
- if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
- if (!radeon_dig_connector->edp_on)
- atombios_set_edp_panel_power(connector,
- ATOM_TRANSMITTER_ACTION_POWER_ON);
- ret = radeon_ddc_get_modes(radeon_connector);
- if (!radeon_dig_connector->edp_on)
- atombios_set_edp_panel_power(connector,
- ATOM_TRANSMITTER_ACTION_POWER_OFF);
- } else {
- /* need to setup ddc on the bridge */
- if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
- ENCODER_OBJECT_ID_NONE) {
- if (encoder)
- radeon_atom_ext_encoder_setup_ddc(encoder);
- }
- ret = radeon_ddc_get_modes(radeon_connector);
- }
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
+ ret = radeon_ddc_get_modes(radeon_connector);
+ if (!radeon_dig_connector->edp_on)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_OFF);
if (ret > 0) {
if (encoder) {
@@ -1191,6 +1201,7 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
return ret;
}
+ encoder = radeon_best_single_encoder(connector);
if (!encoder)
return 0;
@@ -1207,8 +1218,7 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
}
} else {
/* need to setup ddc on the bridge */
- if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
- ENCODER_OBJECT_ID_NONE) {
+ if (radeon_connector_encoder_is_dp_bridge(connector)) {
if (encoder)
radeon_atom_ext_encoder_setup_ddc(encoder);
}
@@ -1218,12 +1228,13 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
return ret;
}
-u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector)
+bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector)
{
struct drm_mode_object *obj;
struct drm_encoder *encoder;
struct radeon_encoder *radeon_encoder;
int i;
+ bool found = false;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == 0)
@@ -1239,13 +1250,14 @@ u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_TRAVIS:
case ENCODER_OBJECT_ID_NUTMEG:
- return radeon_encoder->encoder_id;
+ found = true;
+ break;
default:
break;
}
}
- return ENCODER_OBJECT_ID_NONE;
+ return found;
}
bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
@@ -1297,9 +1309,6 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
- if (!force && radeon_check_hpd_status_unchanged(connector))
- return connector->status;
-
if (radeon_connector->edid) {
kfree(radeon_connector->edid);
radeon_connector->edid = NULL;
@@ -1325,24 +1334,12 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
if (!radeon_dig_connector->edp_on)
atombios_set_edp_panel_power(connector,
ATOM_TRANSMITTER_ACTION_POWER_OFF);
- } else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
- ENCODER_OBJECT_ID_NONE) {
- /* DP bridges are always DP */
- radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
- /* get the DPCD from the bridge */
- radeon_dp_getdpcd(radeon_connector);
-
- if (encoder) {
- /* setup ddc on the bridge */
- radeon_atom_ext_encoder_setup_ddc(encoder);
- if (radeon_ddc_probe(radeon_connector)) /* try DDC */
- ret = connector_status_connected;
- else if (radeon_connector->dac_load_detect) { /* try load detection */
- struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
- ret = encoder_funcs->detect(encoder, connector);
- }
- }
} else {
+ /* need to setup ddc on the bridge */
+ if (radeon_connector_encoder_is_dp_bridge(connector)) {
+ if (encoder)
+ radeon_atom_ext_encoder_setup_ddc(encoder);
+ }
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
ret = connector_status_connected;
@@ -1353,10 +1350,21 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
if (radeon_dp_getdpcd(radeon_connector))
ret = connector_status_connected;
} else {
- if (radeon_ddc_probe(radeon_connector))
+ if (radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe))
ret = connector_status_connected;
}
}
+
+ if ((ret == connector_status_disconnected) &&
+ radeon_connector->dac_load_detect) {
+ struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+ struct drm_encoder_helper_funcs *encoder_funcs;
+ if (encoder) {
+ encoder_funcs = encoder->helper_private;
+ ret = encoder_funcs->detect(encoder, connector);
+ }
+ }
}
radeon_connector_update_scratch_regs(connector, ret);
@@ -1498,7 +1506,9 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_connector->shared_ddc = shared_ddc;
radeon_connector->connector_object_id = connector_object_id;
radeon_connector->hpd = *hpd;
-
+ radeon_connector->requires_extended_probe =
+ radeon_connector_needs_extended_probe(rdev, supported_device,
+ connector_type);
radeon_connector->router = *router;
if (router->ddc_valid || router->cd_valid) {
radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
@@ -1845,7 +1855,9 @@ radeon_add_legacy_connector(struct drm_device *dev,
radeon_connector->devices = supported_device;
radeon_connector->connector_object_id = connector_object_id;
radeon_connector->hpd = *hpd;
-
+ radeon_connector->requires_extended_probe =
+ radeon_connector_needs_extended_probe(rdev, supported_device,
+ connector_type);
switch (connector_type) {
case DRM_MODE_CONNECTOR_VGA:
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);