Merge branches 'core-fixes-for-linus' and 'irq-fixes-for-linus' of git://git.kernel...
[pandora-kernel.git] / drivers / gpu / drm / radeon / radeon_encoders.c
index 49fcd60..1b55755 100644 (file)
@@ -229,6 +229,22 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
        return NULL;
 }
 
+static struct drm_connector *
+radeon_get_connector_for_encoder_init(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               if (radeon_encoder->devices & radeon_connector->devices)
+                       return connector;
+       }
+       return NULL;
+}
+
 struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -250,6 +266,25 @@ struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder
        return NULL;
 }
 
+bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder)
+{
+       struct drm_encoder *other_encoder = radeon_atom_get_external_encoder(encoder);
+
+       if (other_encoder) {
+               struct radeon_encoder *radeon_encoder = to_radeon_encoder(other_encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_TRAVIS:
+               case ENCODER_OBJECT_ID_NUTMEG:
+                       return true;
+               default:
+                       return false;
+               }
+       }
+
+       return false;
+}
+
 void radeon_panel_mode_fixup(struct drm_encoder *encoder,
                             struct drm_display_mode *adjusted_mode)
 {
@@ -621,6 +656,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
 
+       /* dp bridges are always DP */
+       if (radeon_encoder_is_dp_bridge(encoder))
+               return ATOM_ENCODER_MODE_DP;
+
        connector = radeon_get_connector_for_encoder(encoder);
        if (!connector) {
                switch (radeon_encoder->encoder_id) {
@@ -748,7 +787,7 @@ union dig_encoder_control {
 };
 
 void
-atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -794,7 +833,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
 
        args.v1.ucAction = action;
        args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
-       args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
+       if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
+               args.v3.ucPanelMode = panel_mode;
+       else
+               args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
 
        if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
            (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST))
@@ -902,7 +944,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct drm_connector *connector;
        union dig_transmitter_control args;
        int index = 0;
        uint8_t frev, crev;
@@ -913,6 +955,11 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        int connector_object_id = 0;
        int igp_lane_info = 0;
 
+       if (action == ATOM_TRANSMITTER_ACTION_INIT)
+               connector = radeon_get_connector_for_encoder_init(encoder);
+       else
+               connector = radeon_get_connector_for_encoder(encoder);
+
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                struct radeon_connector_atom_dig *dig_connector =
@@ -1095,7 +1142,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
-void
+bool
 atombios_set_edp_panel_power(struct drm_connector *connector, int action)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1106,23 +1153,37 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
        uint8_t frev, crev;
 
        if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
-               return;
+               goto done;
 
        if (!ASIC_IS_DCE4(rdev))
-               return;
+               goto done;
 
        if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
            (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
-               return;
+               goto done;
 
        if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
-               return;
+               goto done;
 
        memset(&args, 0, sizeof(args));
 
        args.v1.ucAction = action;
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       /* wait for the panel to power up */
+       if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) {
+               int i;
+
+               for (i = 0; i < 300; i++) {
+                       if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+                               return true;
+                       mdelay(1);
+               }
+               return false;
+       }
+done:
+       return true;
 }
 
 union external_encoder_control {
@@ -1140,7 +1201,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
        union external_encoder_control args;
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct drm_connector *connector;
        int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
        u8 frev, crev;
        int dp_clock = 0;
@@ -1149,6 +1210,11 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
        u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
        int bpc = 8;
 
+       if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+               connector = radeon_get_connector_for_encoder_init(encoder);
+       else
+               connector = radeon_get_connector_for_encoder(encoder);
+
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                struct radeon_connector_atom_dig *dig_connector =
@@ -1377,9 +1443,11 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                                                                     ATOM_TRANSMITTER_ACTION_POWER_ON);
                                        radeon_dig_connector->edp_on = true;
                                }
-                               dp_link_train(encoder, connector);
                                if (ASIC_IS_DCE4(rdev))
-                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
+                               radeon_dp_link_train(encoder, connector);
+                               if (ASIC_IS_DCE4(rdev))
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
                        }
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
                                atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
@@ -1392,7 +1460,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
                                if (ASIC_IS_DCE4(rdev))
-                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
                                if (connector &&
                                    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
                                        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1729,6 +1797,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        return 1;
 }
 
+/* This only needs to be called once at startup */
+void
+radeon_atom_encoder_init(struct radeon_device *rdev)
+{
+       struct drm_device *dev = rdev->ddev;
+       struct drm_encoder *encoder;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+               struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       break;
+               default:
+                       break;
+               }
+
+               if (ext_encoder && ASIC_IS_DCE41(rdev))
+                       atombios_external_encoder_setup(encoder, ext_encoder,
+                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+       }
+}
+
 static void
 radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                             struct drm_display_mode *mode,
@@ -1763,19 +1859,17 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                        /* disable the transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
                        /* setup and enable the encoder */
-                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP);
+                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0);
 
-                       /* init and enable the transmitter */
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       /* enable the transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                } else {
                        /* disable the encoder and transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
-                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
 
                        /* setup and enable the encoder and transmitter */
-                       atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                }
@@ -1800,12 +1894,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        if (ext_encoder) {
-               if (ASIC_IS_DCE41(rdev)) {
-                       atombios_external_encoder_setup(encoder, ext_encoder,
-                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+               if (ASIC_IS_DCE41(rdev))
                        atombios_external_encoder_setup(encoder, ext_encoder,
                                                        EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
-               else
+               else
                        atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
        }
 
@@ -1912,8 +2004,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
-       if (radeon_encoder->active_device &
-           (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
+       if ((radeon_encoder->active_device &
+            (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+           radeon_encoder_is_dp_bridge(encoder)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                if (dig)
                        dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
@@ -1922,11 +2015,17 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
        radeon_atom_output_lock(encoder, true);
        radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
-       /* select the clock/data port if it uses a router */
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+               /* select the clock/data port if it uses a router */
                if (radeon_connector->router.cd_valid)
                        radeon_router_select_cd_port(radeon_connector);
+
+               /* turn eDP panel on for mode set */
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+                       atombios_set_edp_panel_power(connector,
+                                                    ATOM_TRANSMITTER_ACTION_POWER_ON);
        }
 
        /* this is needed for the pll/ss setup to work correctly in some cases */
@@ -1981,7 +2080,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
                else {
                        /* disable the encoder and transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
-                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
                }
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI: