drm/amd/amdgpu: For virtual display, enable multi crtcs. (v3)
authorEmily Deng <Emily.Deng@amd.com>
Fri, 30 Sep 2016 17:02:18 +0000 (13:02 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 25 Oct 2016 18:38:07 +0000 (14:38 -0400)
Enable multi crtcs for virtual display, user can set the number of crtcs
by amdgpu module parameter  virtual_display.

v2: make timers per crtc
v3: agd: simplify implementation

Signed-off-by: Emily Deng <Emily.Deng@amd.com>
Reviewed-By: Emily Deng <Emily.Deng@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/dce_virtual.c

index 874c33b..22d3319 100644 (file)
@@ -1238,20 +1238,38 @@ static void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev)
        if (amdgpu_virtual_display) {
                struct drm_device *ddev = adev->ddev;
                const char *pci_address_name = pci_name(ddev->pdev);
-               char *pciaddstr, *pciaddstr_tmp, *pciaddname;
+               char *pciaddstr, *pciaddstr_tmp, *pciaddname_tmp, *pciaddname;
 
                pciaddstr = kstrdup(amdgpu_virtual_display, GFP_KERNEL);
                pciaddstr_tmp = pciaddstr;
-               while ((pciaddname = strsep(&pciaddstr_tmp, ";"))) {
+               while ((pciaddname_tmp = strsep(&pciaddstr_tmp, ";"))) {
+                       pciaddname = strsep(&pciaddname_tmp, ",");
                        if (!strcmp(pci_address_name, pciaddname)) {
+                               long num_crtc;
+                               int res = -1;
+
                                adev->enable_virtual_display = true;
+
+                               if (pciaddname_tmp)
+                                       res = kstrtol(pciaddname_tmp, 10,
+                                                     &num_crtc);
+
+                               if (!res) {
+                                       if (num_crtc < 1)
+                                               num_crtc = 1;
+                                       if (num_crtc > 6)
+                                               num_crtc = 6;
+                                       adev->mode_info.num_crtc = num_crtc;
+                               } else {
+                                       adev->mode_info.num_crtc = 1;
+                               }
                                break;
                        }
                }
 
-               DRM_INFO("virtual display string:%s, %s:virtual_display:%d\n",
-                                amdgpu_virtual_display, pci_address_name,
-                                adev->enable_virtual_display);
+               DRM_INFO("virtual display string:%s, %s:virtual_display:%d, num_crtc:%d\n",
+                        amdgpu_virtual_display, pci_address_name,
+                        adev->enable_virtual_display, adev->mode_info.num_crtc);
 
                kfree(pciaddstr);
        }
index 71ed27e..2201f05 100644 (file)
@@ -201,7 +201,8 @@ module_param_named(pg_mask, amdgpu_pg_mask, uint, 0444);
 MODULE_PARM_DESC(disable_cu, "Disable CUs (se.sh.cu,...)");
 module_param_named(disable_cu, amdgpu_disable_cu, charp, 0444);
 
-MODULE_PARM_DESC(virtual_display, "Enable virtual display feature (the virtual_display will be set like xxxx:xx:xx.x;xxxx:xx:xx.x)");
+MODULE_PARM_DESC(virtual_display,
+                "Enable virtual display feature (the virtual_display will be set like xxxx:xx:xx.x,x;xxxx:xx:xx.x,x)");
 module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444);
 
 static const struct pci_device_id pciidlist[] = {
index 7b0eff7..1e23334 100644 (file)
@@ -341,8 +341,6 @@ struct amdgpu_mode_info {
        int                     num_dig; /* number of dig blocks */
        int                     disp_priority;
        const struct amdgpu_display_funcs *funcs;
-       struct hrtimer vblank_timer;
-       enum amdgpu_interrupt_state vsync_timer_enabled;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
@@ -413,6 +411,9 @@ struct amdgpu_crtc {
        u32 wm_high;
        u32 lb_vblank_lead_lines;
        struct drm_display_mode hw_mode;
+       /* for virtual dce */
+       struct hrtimer vblank_timer;
+       enum amdgpu_interrupt_state vsync_timer_enabled;
 };
 
 struct amdgpu_encoder_atom_dig {
index b981e76..226b914 100644 (file)
@@ -335,6 +335,7 @@ static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index)
        amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
        amdgpu_crtc->encoder = NULL;
        amdgpu_crtc->connector = NULL;
+       amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
        drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs);
 
        return 0;
@@ -344,11 +345,9 @@ static int dce_virtual_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       adev->mode_info.vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
        dce_virtual_set_display_funcs(adev);
        dce_virtual_set_irq_funcs(adev);
 
-       adev->mode_info.num_crtc = 1;
        adev->mode_info.num_hpd = 1;
        adev->mode_info.num_dig = 1;
        return 0;
@@ -756,14 +755,13 @@ static int dce_virtual_pageflip(struct amdgpu_device *adev,
 
 static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer)
 {
-       struct amdgpu_mode_info *mode_info =
-               container_of(vblank_timer, struct amdgpu_mode_info , vblank_timer);
-       struct amdgpu_device *adev =
-               container_of(mode_info, struct amdgpu_device , mode_info);
-       unsigned crtc = 0;
+       struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer,
+                                                      struct amdgpu_crtc, vblank_timer);
+       struct drm_device *ddev = amdgpu_crtc->base.dev;
+       struct amdgpu_device *adev = ddev->dev_private;
 
-       drm_handle_vblank(adev->ddev, crtc);
-       dce_virtual_pageflip(adev, crtc);
+       drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
+       dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id);
        hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD),
                      HRTIMER_MODE_REL);
 
@@ -779,18 +777,22 @@ static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *ad
                return;
        }
 
-       if (state && !adev->mode_info.vsync_timer_enabled) {
+       if (state && !adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
                DRM_DEBUG("Enable software vsync timer\n");
-               hrtimer_init(&adev->mode_info.vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-               hrtimer_set_expires(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD));
-               adev->mode_info.vblank_timer.function = dce_virtual_vblank_timer_handle;
-               hrtimer_start(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL);
-       } else if (!state && adev->mode_info.vsync_timer_enabled) {
+               hrtimer_init(&adev->mode_info.crtcs[crtc]->vblank_timer,
+                            CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+               hrtimer_set_expires(&adev->mode_info.crtcs[crtc]->vblank_timer,
+                                   ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD));
+               adev->mode_info.crtcs[crtc]->vblank_timer.function =
+                       dce_virtual_vblank_timer_handle;
+               hrtimer_start(&adev->mode_info.crtcs[crtc]->vblank_timer,
+                             ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL);
+       } else if (!state && adev->mode_info.crtcs[crtc]->vsync_timer_enabled) {
                DRM_DEBUG("Disable software vsync timer\n");
-               hrtimer_cancel(&adev->mode_info.vblank_timer);
+               hrtimer_cancel(&adev->mode_info.crtcs[crtc]->vblank_timer);
        }
 
-       adev->mode_info.vsync_timer_enabled = state;
+       adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state;
        DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state);
 }
 
@@ -800,13 +802,11 @@ static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev,
                                          unsigned type,
                                          enum amdgpu_interrupt_state state)
 {
-       switch (type) {
-       case AMDGPU_CRTC_IRQ_VBLANK1:
-               dce_virtual_set_crtc_vblank_interrupt_state(adev, 0, state);
-               break;
-       default:
-               break;
-       }
+       if (type > AMDGPU_CRTC_IRQ_VBLANK6)
+               return -EINVAL;
+
+       dce_virtual_set_crtc_vblank_interrupt_state(adev, type, state);
+
        return 0;
 }