[PATCH v2] drm/amd/amdgpu: For virtual display, enable multi crtcs.
Emily Deng
Emily.Deng at amd.com
Fri Sep 30 09:27:02 UTC 2016
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;
}
@@ -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
More information about the amd-gfx
mailing list