Commit 0f66356d authored by Emily Deng's avatar Emily Deng Committed by Alex Deucher

drm/amd/amdgpu: For virtual display, enable multi crtcs. (v3)

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: default avatarEmily Deng <Emily.Deng@amd.com>
Reviewed-By: default avatarEmily Deng <Emily.Deng@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 483ef985
...@@ -1238,20 +1238,38 @@ static void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev) ...@@ -1238,20 +1238,38 @@ static void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev)
if (amdgpu_virtual_display) { if (amdgpu_virtual_display) {
struct drm_device *ddev = adev->ddev; struct drm_device *ddev = adev->ddev;
const char *pci_address_name = pci_name(ddev->pdev); 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 = kstrdup(amdgpu_virtual_display, GFP_KERNEL);
pciaddstr_tmp = pciaddstr; pciaddstr_tmp = pciaddstr;
while ((pciaddname = strsep(&pciaddstr_tmp, ";"))) { while ((pciaddname_tmp = strsep(&pciaddstr_tmp, ";"))) {
pciaddname = strsep(&pciaddname_tmp, ",");
if (!strcmp(pci_address_name, pciaddname)) { if (!strcmp(pci_address_name, pciaddname)) {
long num_crtc;
int res = -1;
adev->enable_virtual_display = true; 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; break;
} }
} }
DRM_INFO("virtual display string:%s, %s:virtual_display:%d\n", DRM_INFO("virtual display string:%s, %s:virtual_display:%d, num_crtc:%d\n",
amdgpu_virtual_display, pci_address_name, amdgpu_virtual_display, pci_address_name,
adev->enable_virtual_display); adev->enable_virtual_display, adev->mode_info.num_crtc);
kfree(pciaddstr); kfree(pciaddstr);
} }
......
...@@ -201,7 +201,8 @@ module_param_named(pg_mask, amdgpu_pg_mask, uint, 0444); ...@@ -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_PARM_DESC(disable_cu, "Disable CUs (se.sh.cu,...)");
module_param_named(disable_cu, amdgpu_disable_cu, charp, 0444); 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); module_param_named(virtual_display, amdgpu_virtual_display, charp, 0444);
static const struct pci_device_id pciidlist[] = { static const struct pci_device_id pciidlist[] = {
......
...@@ -341,8 +341,6 @@ struct amdgpu_mode_info { ...@@ -341,8 +341,6 @@ struct amdgpu_mode_info {
int num_dig; /* number of dig blocks */ int num_dig; /* number of dig blocks */
int disp_priority; int disp_priority;
const struct amdgpu_display_funcs *funcs; const struct amdgpu_display_funcs *funcs;
struct hrtimer vblank_timer;
enum amdgpu_interrupt_state vsync_timer_enabled;
}; };
#define AMDGPU_MAX_BL_LEVEL 0xFF #define AMDGPU_MAX_BL_LEVEL 0xFF
...@@ -413,6 +411,9 @@ struct amdgpu_crtc { ...@@ -413,6 +411,9 @@ struct amdgpu_crtc {
u32 wm_high; u32 wm_high;
u32 lb_vblank_lead_lines; u32 lb_vblank_lead_lines;
struct drm_display_mode hw_mode; 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 { struct amdgpu_encoder_atom_dig {
......
...@@ -335,6 +335,7 @@ static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index) ...@@ -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->pll_id = ATOM_PPLL_INVALID;
amdgpu_crtc->encoder = NULL; amdgpu_crtc->encoder = NULL;
amdgpu_crtc->connector = 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); drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs);
return 0; return 0;
...@@ -344,11 +345,9 @@ static int dce_virtual_early_init(void *handle) ...@@ -344,11 +345,9 @@ static int dce_virtual_early_init(void *handle)
{ {
struct amdgpu_device *adev = (struct amdgpu_device *)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_display_funcs(adev);
dce_virtual_set_irq_funcs(adev); dce_virtual_set_irq_funcs(adev);
adev->mode_info.num_crtc = 1;
adev->mode_info.num_hpd = 1; adev->mode_info.num_hpd = 1;
adev->mode_info.num_dig = 1; adev->mode_info.num_dig = 1;
return 0; return 0;
...@@ -756,14 +755,13 @@ static int dce_virtual_pageflip(struct amdgpu_device *adev, ...@@ -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) static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer)
{ {
struct amdgpu_mode_info *mode_info = struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer,
container_of(vblank_timer, struct amdgpu_mode_info , vblank_timer); struct amdgpu_crtc, vblank_timer);
struct amdgpu_device *adev = struct drm_device *ddev = amdgpu_crtc->base.dev;
container_of(mode_info, struct amdgpu_device , mode_info); struct amdgpu_device *adev = ddev->dev_private;
unsigned crtc = 0;
drm_handle_vblank(adev->ddev, crtc); drm_handle_vblank(ddev, amdgpu_crtc->crtc_id);
dce_virtual_pageflip(adev, crtc); dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id);
hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD),
HRTIMER_MODE_REL); HRTIMER_MODE_REL);
...@@ -779,18 +777,22 @@ static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *ad ...@@ -779,18 +777,22 @@ static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *ad
return; 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"); DRM_DEBUG("Enable software vsync timer\n");
hrtimer_init(&adev->mode_info.vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer_init(&adev->mode_info.crtcs[crtc]->vblank_timer,
hrtimer_set_expires(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD)); CLOCK_MONOTONIC, HRTIMER_MODE_REL);
adev->mode_info.vblank_timer.function = dce_virtual_vblank_timer_handle; hrtimer_set_expires(&adev->mode_info.crtcs[crtc]->vblank_timer,
hrtimer_start(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL); ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD));
} else if (!state && adev->mode_info.vsync_timer_enabled) { 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"); 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); 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, ...@@ -800,13 +802,11 @@ static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev,
unsigned type, unsigned type,
enum amdgpu_interrupt_state state) enum amdgpu_interrupt_state state)
{ {
switch (type) { if (type > AMDGPU_CRTC_IRQ_VBLANK6)
case AMDGPU_CRTC_IRQ_VBLANK1: return -EINVAL;
dce_virtual_set_crtc_vblank_interrupt_state(adev, 0, state);
break; dce_virtual_set_crtc_vblank_interrupt_state(adev, type, state);
default:
break;
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment