drm/radeon: Poll for both connect/disconnect on analog connectors
[pandora-kernel.git] / drivers / gpu / drm / radeon / radeon_connectors.c
index dec6cbe..40633f3 100644 (file)
@@ -44,8 +44,6 @@ 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;
@@ -66,14 +64,38 @@ void radeon_connector_hotplug(struct drm_connector *connector)
 
        /* just deal with DP (not eDP) here. */
        if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
-               int saved_dpms = connector->dpms;
-
-               /* Only turn off the display it it's physically disconnected */
-               if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
-                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-               else if (radeon_dp_needs_link_train(radeon_connector))
-                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-               connector->dpms = saved_dpms;
+               struct radeon_connector_atom_dig *dig_connector =
+                       radeon_connector->con_priv;
+
+               /* if existing sink type was not DP no need to retrain */
+               if (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                       return;
+
+               /* first get sink type as it may be reset after (un)plug */
+               dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
+               /* don't do anything if sink is not display port, i.e.,
+                * passive dp->(dvi|hdmi) adaptor
+                */
+               if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
+                       int saved_dpms = connector->dpms;
+                       /* Only turn off the display if it's physically disconnected */
+                       if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
+                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+                       } else if (radeon_dp_needs_link_train(radeon_connector)) {
+                               /* Don't try to start link training before we
+                                * have the dpcd */
+                               if (!radeon_dp_getdpcd(radeon_connector))
+                                       return;
+
+                               /* set it to OFF so that drm_helper_connector_dpms()
+                                * won't return immediately since the current state
+                                * is ON at this point.
+                                */
+                               connector->dpms = DRM_MODE_DPMS_OFF;
+                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+                       }
+                       connector->dpms = saved_dpms;
+               }
        }
 }
 
@@ -432,55 +454,6 @@ 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)
 {
@@ -721,8 +694,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
                ret = connector_status_disconnected;
 
        if (radeon_connector->ddc_bus)
-               dret = radeon_ddc_probe(radeon_connector,
-                                       radeon_connector->requires_extended_probe);
+               dret = radeon_ddc_probe(radeon_connector, false);
        if (dret) {
                radeon_connector->detected_by_load = false;
                if (radeon_connector->edid) {
@@ -764,7 +736,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
                if (radeon_connector->dac_load_detect && encoder) {
                        encoder_funcs = encoder->helper_private;
                        ret = encoder_funcs->detect(encoder, connector);
-                       if (ret == connector_status_connected)
+                       if (ret != connector_status_disconnected)
                                radeon_connector->detected_by_load = true;
                }
        }
@@ -904,8 +876,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
        bool dret = false;
 
        if (radeon_connector->ddc_bus)
-               dret = radeon_ddc_probe(radeon_connector,
-                                       radeon_connector->requires_extended_probe);
+               dret = radeon_ddc_probe(radeon_connector, false);
        if (dret) {
                radeon_connector->detected_by_load = false;
                if (radeon_connector->edid) {
@@ -999,14 +970,19 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
 
                        encoder = obj_to_encoder(obj);
 
+                       if (encoder->encoder_type != DRM_MODE_ENCODER_DAC &&
+                           encoder->encoder_type != DRM_MODE_ENCODER_TVDAC)
+                               continue;
+
                        encoder_funcs = encoder->helper_private;
                        if (encoder_funcs->detect) {
                                if (ret != connector_status_connected) {
                                        ret = encoder_funcs->detect(encoder, connector);
                                        if (ret == connector_status_connected) {
                                                radeon_connector->use_digital = false;
-                                               radeon_connector->detected_by_load = true;
                                        }
+                                       if (ret != connector_status_disconnected)
+                                               radeon_connector->detected_by_load = true;
                                }
                                break;
                        }
@@ -1024,6 +1000,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
         * cases the DVI port is actually a virtual KVM port connected to the service
         * processor.
         */
+out:
        if ((!rdev->is_atom_bios) &&
            (ret == connector_status_disconnected) &&
            rdev->mode_info.bios_hardcoded_edid_size) {
@@ -1031,7 +1008,6 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
                ret = connector_status_connected;
        }
 
-out:
        /* updated in get modes as well since we need to know if it's analog or digital */
        radeon_connector_update_scratch_regs(connector, ret);
        return ret;
@@ -1203,7 +1179,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
                }
        } else {
                /* need to setup ddc on the bridge */
-               if (radeon_connector_encoder_is_dp_bridge(connector)) {
+               if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) !=
+                       ENCODER_OBJECT_ID_NONE) {
                        if (encoder)
                                radeon_atom_ext_encoder_setup_ddc(encoder);
                }
@@ -1213,13 +1190,12 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
        return ret;
 }
 
-bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector)
+u16 radeon_connector_encoder_get_dp_bridge_encoder_id(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)
@@ -1235,14 +1211,13 @@ bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector)
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_TRAVIS:
                case ENCODER_OBJECT_ID_NUTMEG:
-                       found = true;
-                       break;
+                       return radeon_encoder->encoder_id;
                default:
                        break;
                }
        }
 
-       return found;
+       return ENCODER_OBJECT_ID_NONE;
 }
 
 bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
@@ -1276,7 +1251,7 @@ bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
        struct radeon_device *rdev = dev->dev_private;
 
        if (ASIC_IS_DCE5(rdev) &&
-           (rdev->clock.dp_extclk >= 53900) &&
+           (rdev->clock.default_dispclk >= 53900) &&
            radeon_connector_encoder_is_hbr2(connector)) {
                return true;
        }
@@ -1319,7 +1294,8 @@ 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_is_dp_bridge(connector)) {
+       } 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 */
@@ -1328,8 +1304,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                if (encoder) {
                        /* setup ddc on the bridge */
                        radeon_atom_ext_encoder_setup_ddc(encoder);
-                       if (radeon_ddc_probe(radeon_connector,
-                                            radeon_connector->requires_extended_probe)) /* try DDC */
+                       /* bridge chips are always aux */
+                       if (radeon_ddc_probe(radeon_connector, true)) /* 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;
@@ -1347,8 +1323,8 @@ 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,
-                                                    radeon_connector->requires_extended_probe))
+                               /* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */
+                               if (radeon_ddc_probe(radeon_connector, false))
                                        ret = connector_status_connected;
                        }
                }
@@ -1416,6 +1392,24 @@ struct drm_connector_funcs radeon_dp_connector_funcs = {
        .force = radeon_dvi_force,
 };
 
+static const struct drm_connector_funcs radeon_edp_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = radeon_dp_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = radeon_lvds_set_property,
+       .destroy = radeon_dp_connector_destroy,
+       .force = radeon_dvi_force,
+};
+
+static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = radeon_dp_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = radeon_lvds_set_property,
+       .destroy = radeon_dp_connector_destroy,
+       .force = radeon_dvi_force,
+};
+
 void
 radeon_add_atom_connector(struct drm_device *dev,
                          uint32_t connector_id,
@@ -1493,9 +1487,7 @@ 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);
@@ -1509,8 +1501,6 @@ radeon_add_atom_connector(struct drm_device *dev,
                        goto failed;
                radeon_dig_connector->igp_lane_info = igp_lane_info;
                radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
                if (i2c_bus->valid) {
                        /* add DP i2c bus */
                        if (connector_type == DRM_MODE_CONNECTOR_eDP)
@@ -1527,6 +1517,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                case DRM_MODE_CONNECTOR_VGA:
                case DRM_MODE_CONNECTOR_DVIA:
                default:
+                       drm_connector_init(dev, &radeon_connector->base,
+                                          &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base,
+                                                &radeon_dp_connector_helper_funcs);
                        connector->interlace_allowed = true;
                        connector->doublescan_allowed = true;
                        radeon_connector->dac_load_detect = true;
@@ -1539,6 +1533,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                case DRM_MODE_CONNECTOR_HDMIA:
                case DRM_MODE_CONNECTOR_HDMIB:
                case DRM_MODE_CONNECTOR_DisplayPort:
+                       drm_connector_init(dev, &radeon_connector->base,
+                                          &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base,
+                                                &radeon_dp_connector_helper_funcs);
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_property,
                                                      UNDERSCAN_OFF);
@@ -1563,6 +1561,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        break;
                case DRM_MODE_CONNECTOR_LVDS:
                case DRM_MODE_CONNECTOR_eDP:
+                       drm_connector_init(dev, &radeon_connector->base,
+                                          &radeon_lvds_bridge_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base,
+                                                &radeon_dp_connector_helper_funcs);
                        drm_connector_attach_property(&radeon_connector->base,
                                                      dev->mode_config.scaling_mode_property,
                                                      DRM_MODE_SCALE_FULLSCREEN);
@@ -1587,7 +1589,6 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                      1);
                        /* no HPD on analog connectors */
                        radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
                        connector->interlace_allowed = true;
                        connector->doublescan_allowed = true;
                        break;
@@ -1726,7 +1727,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                goto failed;
                        radeon_dig_connector->igp_lane_info = igp_lane_info;
                        radeon_connector->con_priv = radeon_dig_connector;
-                       drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);
                        drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
                        if (i2c_bus->valid) {
                                /* add DP i2c bus */
@@ -1785,8 +1786,10 @@ radeon_add_atom_connector(struct drm_device *dev,
        }
 
        if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
-               if (i2c_bus->valid)
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+               if (i2c_bus->valid) {
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+                                           DRM_CONNECTOR_POLL_DISCONNECT;
+               }
        } else
                connector->polled = DRM_CONNECTOR_POLL_HPD;
 
@@ -1842,9 +1845,7 @@ 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);
@@ -1860,7 +1861,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
                                              1);
                /* no HPD on analog connectors */
                radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
                connector->interlace_allowed = true;
                connector->doublescan_allowed = true;
                break;
@@ -1945,10 +1945,13 @@ radeon_add_legacy_connector(struct drm_device *dev,
        }
 
        if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
-               if (i2c_bus->valid)
-                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+               if (i2c_bus->valid) {
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+                                           DRM_CONNECTOR_POLL_DISCONNECT;
+               }
        } else
                connector->polled = DRM_CONNECTOR_POLL_HPD;
+
        connector->display_info.subpixel_order = subpixel_order;
        drm_sysfs_connector_add(connector);
        if (connector_type == DRM_MODE_CONNECTOR_LVDS) {