Merge tag 'drm-for-v4.15-part2' of git://people.freedesktop.org/~airlied/linux
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_device.c
index 2c85e0a98608d0a8fb4a1ae5991f6d6eece3b1ec..2c574374d9b6884e6c4473f2dd3ede86b7a612df 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/debugfs.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/amdgpu_drm.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
@@ -2049,6 +2050,52 @@ static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
        }
 }
 
+bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
+{
+       switch (asic_type) {
+#if defined(CONFIG_DRM_AMD_DC)
+       case CHIP_BONAIRE:
+       case CHIP_HAWAII:
+       case CHIP_KAVERI:
+       case CHIP_CARRIZO:
+       case CHIP_STONEY:
+       case CHIP_POLARIS11:
+       case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
+       case CHIP_TONGA:
+       case CHIP_FIJI:
+#if defined(CONFIG_DRM_AMD_DC_PRE_VEGA)
+               return amdgpu_dc != 0;
+#endif
+       case CHIP_KABINI:
+       case CHIP_MULLINS:
+               return amdgpu_dc > 0;
+       case CHIP_VEGA10:
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+       case CHIP_RAVEN:
+#endif
+               return amdgpu_dc != 0;
+#endif
+       default:
+               return false;
+       }
+}
+
+/**
+ * amdgpu_device_has_dc_support - check if dc is supported
+ *
+ * @adev: amdgpu_device_pointer
+ *
+ * Returns true for supported, false for not supported
+ */
+bool amdgpu_device_has_dc_support(struct amdgpu_device *adev)
+{
+       if (amdgpu_sriov_vf(adev))
+               return false;
+
+       return amdgpu_device_asic_has_dc_support(adev->asic_type);
+}
+
 /**
  * amdgpu_device_init - initialize the driver
  *
@@ -2103,7 +2150,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        adev->audio_endpt_rreg = &amdgpu_block_invalid_rreg;
        adev->audio_endpt_wreg = &amdgpu_block_invalid_wreg;
 
-
        DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n",
                 amdgpu_asic_name[adev->asic_type], pdev->vendor, pdev->device,
                 pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision);
@@ -2245,7 +2291,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
                        goto failed;
                }
                /* init i2c buses */
-               amdgpu_atombios_i2c_init(adev);
+               if (!amdgpu_device_has_dc_support(adev))
+                       amdgpu_atombios_i2c_init(adev);
        }
 
        /* Fence driver */
@@ -2381,7 +2428,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
        adev->accel_working = false;
        cancel_delayed_work_sync(&adev->late_init_work);
        /* free i2c buses */
-       amdgpu_i2c_fini(adev);
+       if (!amdgpu_device_has_dc_support(adev))
+               amdgpu_i2c_fini(adev);
        amdgpu_atombios_fini(adev);
        kfree(adev->bios);
        adev->bios = NULL;
@@ -2432,12 +2480,14 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
 
        drm_kms_helper_poll_disable(dev);
 
-       /* turn off display hw */
-       drm_modeset_lock_all(dev);
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       if (!amdgpu_device_has_dc_support(adev)) {
+               /* turn off display hw */
+               drm_modeset_lock_all(dev);
+               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+               }
+               drm_modeset_unlock_all(dev);
        }
-       drm_modeset_unlock_all(dev);
 
        amdgpu_amdkfd_suspend(adev);
 
@@ -2580,13 +2630,25 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
 
        /* blat the mode back in */
        if (fbcon) {
-               drm_helper_resume_force_mode(dev);
-               /* turn on display hw */
-               drm_modeset_lock_all(dev);
-               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+               if (!amdgpu_device_has_dc_support(adev)) {
+                       /* pre DCE11 */
+                       drm_helper_resume_force_mode(dev);
+
+                       /* turn on display hw */
+                       drm_modeset_lock_all(dev);
+                       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+                       }
+                       drm_modeset_unlock_all(dev);
+               } else {
+                       /*
+                        * There is no equivalent atomic helper to turn on
+                        * display, so we defined our own function for this,
+                        * once suspend resume is supported by the atomic
+                        * framework this will be reworked
+                        */
+                       amdgpu_dm_display_resume(adev);
                }
-               drm_modeset_unlock_all(dev);
        }
 
        drm_kms_helper_poll_enable(dev);
@@ -2603,7 +2665,10 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
 #ifdef CONFIG_PM
        dev->dev->power.disable_depth++;
 #endif
-       drm_helper_hpd_irq_event(dev);
+       if (!amdgpu_device_has_dc_support(adev))
+               drm_helper_hpd_irq_event(dev);
+       else
+               drm_kms_helper_hotplug_event(dev);
 #ifdef CONFIG_PM
        dev->dev->power.disable_depth--;
 #endif
@@ -2903,6 +2968,7 @@ give_up_reset:
  */
 int amdgpu_gpu_reset(struct amdgpu_device *adev)
 {
+       struct drm_atomic_state *state = NULL;
        int i, r;
        int resched;
        bool need_full_reset, vram_lost = false;
@@ -2916,6 +2982,9 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev)
 
        /* block TTM */
        resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
+       /* store modesetting */
+       if (amdgpu_device_has_dc_support(adev))
+               state = drm_atomic_helper_suspend(adev->ddev);
 
        /* block scheduler */
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
@@ -3032,7 +3101,11 @@ out:
                }
        }
 
-       drm_helper_resume_force_mode(adev->ddev);
+       if (amdgpu_device_has_dc_support(adev)) {
+               r = drm_atomic_helper_resume(adev->ddev, state);
+               amdgpu_dm_display_resume(adev);
+       } else
+               drm_helper_resume_force_mode(adev->ddev);
 
        ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
        if (r) {