[PATCH v2] drm/amd/amdgpu: For virtual display, enable multi crtcs.

Alex Deucher alexdeucher at gmail.com
Fri Sep 30 15:16:57 UTC 2016


On Fri, Sep 30, 2016 at 5:27 AM, Emily Deng <Emily.Deng at amd.com> wrote:
> Enable multi crtcs for virtual display, user can set the number of crtcs
> by amdgpu module parameter  virtual_display.
>
> Signed-off-by: Emily Deng <Emily.Deng at amd.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/ObjectID.h      |  25 ++++-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_device.c |  27 +++++-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c    |   2 +-
>  drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h   |   4 +-
>  drivers/gpu/drm/amd/amdgpu/dce_virtual.c   | 142 ++++++++++++++++++++++-------
>  5 files changed, 155 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/ObjectID.h b/drivers/gpu/drm/amd/amdgpu/ObjectID.h
> index b8d6667..3002836 100644
> --- a/drivers/gpu/drm/amd/amdgpu/ObjectID.h
> +++ b/drivers/gpu/drm/amd/amdgpu/ObjectID.h
> @@ -149,7 +149,6 @@
>  #define GRAPH_OBJECT_ENUM_ID5                     0x05
>  #define GRAPH_OBJECT_ENUM_ID6                     0x06
>  #define GRAPH_OBJECT_ENUM_ID7                     0x07
> -#define GRAPH_OBJECT_ENUM_VIRTUAL                 0x08
>
>  /****************************************************/
>  /* Graphics Object ID Bit definition                */
> @@ -411,8 +410,28 @@
>                                                    GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
>                                                    ENCODER_OBJECT_ID_HDMI_ANX9805 << OBJECT_ID_SHIFT)
>
> -#define ENCODER_VIRTUAL_ENUM_VIRTUAL            ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
> -                                                  GRAPH_OBJECT_ENUM_VIRTUAL << ENUM_ID_SHIFT |\
> +#define ENCODER_VIRTUAL_ENUM_ID1                 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
> +                                                  GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
> +                                                  ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT)
> +
> +#define ENCODER_VIRTUAL_ENUM_ID2                 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
> +                                                  GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
> +                                                  ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT)
> +
> +#define ENCODER_VIRTUAL_ENUM_ID3                 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
> +                                                  GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
> +                                                  ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT)
> +
> +#define ENCODER_VIRTUAL_ENUM_ID4                 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
> +                                                  GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
> +                                                  ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT)
> +
> +#define ENCODER_VIRTUAL_ENUM_ID5                 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
> +                                                  GRAPH_OBJECT_ENUM_ID5 << ENUM_ID_SHIFT |\
> +                                                  ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT)
> +
> +#define ENCODER_VIRTUAL_ENUM_ID6                 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
> +                                                  GRAPH_OBJECT_ENUM_ID6 << ENUM_ID_SHIFT |\
>                                                    ENCODER_OBJECT_ID_VIRTUAL << OBJECT_ID_SHIFT)
>
>  /****************************************************/
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> index c626434..1f008a0 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
> @@ -1239,20 +1239,37 @@ static void amdgpu_whether_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);
>         }
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 80d8c93..d9b7cbc 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -207,7 +207,7 @@ 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[] = {
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> index 50aeccf..ada9f7e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
> @@ -369,8 +369,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
> @@ -446,6 +444,8 @@ struct amdgpu_crtc {
>         uint32_t flip_flags;
>         /* After Set Mode target will be non-NULL */
>         struct dc_target *target;
> +       struct hrtimer vblank_timer;
> +       enum amdgpu_interrupt_state vsync_timer_enabled;
>  };
>
>  struct amdgpu_encoder_atom_dig {
> diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
> index f3debe8..378f5af 100644
> --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
> +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c
> @@ -339,6 +339,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;
> @@ -348,11 +349,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;
> @@ -363,6 +362,9 @@ static bool dce_virtual_get_connector_info(struct amdgpu_device *adev)
>         struct amdgpu_i2c_bus_rec ddc_bus;
>         struct amdgpu_router router;
>         struct amdgpu_hpd hpd;
> +       int i = 0;
> +       uint32_t encoder_enum = ENCODER_VIRTUAL_ENUM_ID1;
> +       uint32_t supported_device = ATOM_DEVICE_DFP1_SUPPORT;
>
>         /* look up gpio for ddc, hpd */
>         ddc_bus.valid = false;
> @@ -373,17 +375,41 @@ static bool dce_virtual_get_connector_info(struct amdgpu_device *adev)
>         memset(&router, 0, sizeof(router));
>         router.ddc_valid = false;
>         router.cd_valid = false;
> -       amdgpu_display_add_connector(adev,
> -                                     0,
> -                                     ATOM_DEVICE_CRT1_SUPPORT,
> -                                     DRM_MODE_CONNECTOR_VIRTUAL, &ddc_bus,
> -                                     CONNECTOR_OBJECT_ID_VIRTUAL,
> -                                     &hpd,
> -                                     &router);
> -
> -       amdgpu_display_add_encoder(adev, ENCODER_VIRTUAL_ENUM_VIRTUAL,
> -                                                       ATOM_DEVICE_CRT1_SUPPORT,
> -                                                       0);
> +
> +       for (i = 0; i < adev->mode_info.num_crtc; i++) {
> +               switch (i) {
> +               case 0:
> +                       encoder_enum = ENCODER_VIRTUAL_ENUM_ID1;
> +                       supported_device = ATOM_DEVICE_DFP1_SUPPORT;
> +                       break;
> +               case 1:
> +                       encoder_enum = ENCODER_VIRTUAL_ENUM_ID2;
> +                       supported_device = ATOM_DEVICE_DFP2_SUPPORT;
> +                       break;
> +               case 2:
> +                       encoder_enum = ENCODER_VIRTUAL_ENUM_ID3;
> +                       supported_device = ATOM_DEVICE_DFP3_SUPPORT;
> +                       break;
> +               case 3:
> +                       encoder_enum = ENCODER_VIRTUAL_ENUM_ID4;
> +                       supported_device = ATOM_DEVICE_DFP4_SUPPORT;
> +                       break;
> +               case 4:
> +                       encoder_enum = ENCODER_VIRTUAL_ENUM_ID5;
> +                       supported_device = ATOM_DEVICE_DFP5_SUPPORT;
> +                       break;
> +               case 5:
> +                       encoder_enum = ENCODER_VIRTUAL_ENUM_ID6;
> +                       supported_device = ATOM_DEVICE_DFP6_SUPPORT;
> +                       break;
> +               }
> +
> +               amdgpu_display_add_connector(adev, i, supported_device,
> +                               DRM_MODE_CONNECTOR_VIRTUAL, &ddc_bus,
> +                               CONNECTOR_OBJECT_ID_VIRTUAL, &hpd, &router);
> +               amdgpu_display_add_encoder(adev, encoder_enum,
> +                               supported_device, 0);
> +       }
>
>         amdgpu_link_encoder_connector(adev->ddev);
>
> @@ -603,7 +629,28 @@ static void dce_virtual_encoder_add(struct amdgpu_device *adev,
>                 return;
>
>         encoder = &amdgpu_encoder->base;
> -       encoder->possible_crtcs = 0x1;
> +
> +       switch (adev->mode_info.num_crtc) {
> +       case 1:
> +               encoder->possible_crtcs = 0x1;
> +               break;
> +       case 2:
> +               encoder->possible_crtcs = 0x3;
> +               break;
> +       case 3:
> +               encoder->possible_crtcs = 0x7;
> +               break;
> +       case 4:
> +               encoder->possible_crtcs = 0xf;
> +               break;
> +       case 5:
> +               encoder->possible_crtcs = 0x1f;
> +               break;
> +       case 6:
> +               encoder->possible_crtcs = 0x3f;
> +               break;
> +       }
> +
>         amdgpu_encoder->enc_priv = NULL;
>         amdgpu_encoder->encoder_enum = encoder_enum;
>         amdgpu_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
> @@ -646,11 +693,15 @@ static void dce_virtual_set_display_funcs(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;
> -       drm_handle_vblank(adev->ddev, crtc);
> -       dce_virtual_pageflip_irq(adev, NULL, NULL);
> +       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;
> +       struct amdgpu_iv_entry entry;
> +
> +       entry.src_id = amdgpu_crtc->crtc_id;
> +       drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
> +       dce_virtual_pageflip_irq(adev, NULL, &entry);
>         hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL);
>         return HRTIMER_NORESTART;
>  }
> @@ -664,18 +715,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);
>  }
>
> @@ -689,6 +744,21 @@ static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev,
>         case AMDGPU_CRTC_IRQ_VBLANK1:
>                 dce_virtual_set_crtc_vblank_interrupt_state(adev, 0, state);
>                 break;
> +       case AMDGPU_CRTC_IRQ_VBLANK2:
> +               dce_virtual_set_crtc_vblank_interrupt_state(adev, 1, state);
> +               break;
> +       case AMDGPU_CRTC_IRQ_VBLANK3:
> +               dce_virtual_set_crtc_vblank_interrupt_state(adev, 2, state);
> +               break;
> +       case AMDGPU_CRTC_IRQ_VBLANK4:
> +               dce_virtual_set_crtc_vblank_interrupt_state(adev, 3, state);
> +               break;
> +       case AMDGPU_CRTC_IRQ_VBLANK5:
> +               dce_virtual_set_crtc_vblank_interrupt_state(adev, 4, state);
> +               break;
> +       case AMDGPU_CRTC_IRQ_VBLANK6:
> +               dce_virtual_set_crtc_vblank_interrupt_state(adev, 5, state);
> +               break;
>         default:
>                 break;
>         }
> @@ -708,16 +778,20 @@ static int dce_virtual_crtc_irq(struct amdgpu_device *adev,
>                               struct amdgpu_irq_src *source,
>                               struct amdgpu_iv_entry *entry)
>  {
> -       unsigned crtc = 0;
> +       int i;
>         unsigned irq_type = AMDGPU_CRTC_IRQ_VBLANK1;
>
> -       dce_virtual_crtc_vblank_int_ack(adev, crtc);
> +       for (i = 0; i < adev->mode_info.num_crtc; i++) {
> +               irq_type = amdgpu_crtc_idx_to_irq_type(adev, i);
> +               entry->src_id = i;
> +
> +               dce_virtual_crtc_vblank_int_ack(adev, i);
> +               if (amdgpu_irq_enabled(adev, source, irq_type))
> +                       drm_handle_vblank(adev->ddev, i);
>
> -       if (amdgpu_irq_enabled(adev, source, irq_type)) {
> -               drm_handle_vblank(adev->ddev, crtc);
> +               dce_virtual_pageflip_irq(adev, NULL, entry);
> +               DRM_DEBUG("IH: D%d vblank\n", i + 1);
>         }
> -       dce_virtual_pageflip_irq(adev, NULL, NULL);
> -       DRM_DEBUG("IH: D%d vblank\n", crtc + 1);
>         return 0;
>  }

I think dce_virtual_crtc_irq can be dropped altogether.  It's never
used.  In fact, you can set both of the amdgpu_irq_src_funcs.process
callbacks to NULL because they will never be called because the
interrupt vector will never show up in the IV ring.  Just handle all
of the vblank and pageflip updates directly in your timer handler.


>
> @@ -744,7 +818,7 @@ static int dce_virtual_pageflip_irq(struct amdgpu_device *adev,
>         struct amdgpu_crtc *amdgpu_crtc;
>         struct amdgpu_flip_work *works;
>
> -       crtc_id = 0;
> +       crtc_id = entry->src_id;
>         amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
>
>         if (crtc_id >= adev->mode_info.num_crtc) {
> --
> 1.9.1
>
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx


More information about the amd-gfx mailing list