diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_connectors.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 178 |
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); |