Commit cb9e59d7 authored by Alex Deucher's avatar Alex Deucher

drm/amdgpu: Support DRM_MODE_PAGE_FLIP_ASYNC (v2)

When this flag is set, we program the hardware to execute the flip
during horizontal blank (i.e. for the next scanline) instead of during
vertical blank (i.e. for the next frame).

Ported from radeon commit:
drm/radeon: Support DRM_MODE_PAGE_FLIP_ASYNC

v2: drop DAL change for upstream
Reviewed-by: default avatarMichel Dänzer <michel.daenzer@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent a71dd897
...@@ -727,6 +727,7 @@ struct amdgpu_flip_work { ...@@ -727,6 +727,7 @@ struct amdgpu_flip_work {
unsigned shared_count; unsigned shared_count;
struct fence **shared; struct fence **shared;
struct fence_cb cb; struct fence_cb cb;
bool async;
}; };
...@@ -2243,7 +2244,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring) ...@@ -2243,7 +2244,7 @@ amdgpu_get_sdma_instance(struct amdgpu_ring *ring)
#define amdgpu_display_hpd_set_polarity(adev, h) (adev)->mode_info.funcs->hpd_set_polarity((adev), (h)) #define amdgpu_display_hpd_set_polarity(adev, h) (adev)->mode_info.funcs->hpd_set_polarity((adev), (h))
#define amdgpu_display_hpd_get_gpio_reg(adev) (adev)->mode_info.funcs->hpd_get_gpio_reg((adev)) #define amdgpu_display_hpd_get_gpio_reg(adev) (adev)->mode_info.funcs->hpd_get_gpio_reg((adev))
#define amdgpu_display_bandwidth_update(adev) (adev)->mode_info.funcs->bandwidth_update((adev)) #define amdgpu_display_bandwidth_update(adev) (adev)->mode_info.funcs->bandwidth_update((adev))
#define amdgpu_display_page_flip(adev, crtc, base) (adev)->mode_info.funcs->page_flip((adev), (crtc), (base)) #define amdgpu_display_page_flip(adev, crtc, base, async) (adev)->mode_info.funcs->page_flip((adev), (crtc), (base), (async))
#define amdgpu_display_page_flip_get_scanoutpos(adev, crtc, vbl, pos) (adev)->mode_info.funcs->page_flip_get_scanoutpos((adev), (crtc), (vbl), (pos)) #define amdgpu_display_page_flip_get_scanoutpos(adev, crtc, vbl, pos) (adev)->mode_info.funcs->page_flip_get_scanoutpos((adev), (crtc), (vbl), (pos))
#define amdgpu_display_add_encoder(adev, e, s, c) (adev)->mode_info.funcs->add_encoder((adev), (e), (s), (c)) #define amdgpu_display_add_encoder(adev, e, s, c) (adev)->mode_info.funcs->add_encoder((adev), (e), (s), (c))
#define amdgpu_display_add_connector(adev, ci, sd, ct, ib, coi, h, r) (adev)->mode_info.funcs->add_connector((adev), (ci), (sd), (ct), (ib), (coi), (h), (r)) #define amdgpu_display_add_connector(adev, ci, sd, ct, ib, coi, h, r) (adev)->mode_info.funcs->add_connector((adev), (ci), (sd), (ct), (ib), (coi), (h), (r))
......
...@@ -132,7 +132,7 @@ static void amdgpu_flip_work_func(struct work_struct *__work) ...@@ -132,7 +132,7 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
vblank->linedur_ns / 1000, stat, vpos, hpos); vblank->linedur_ns / 1000, stat, vpos, hpos);
/* Do the flip (mmio) */ /* Do the flip (mmio) */
adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base); adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base, work->async);
/* Set the flip status */ /* Set the flip status */
amdgpuCrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; amdgpuCrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
...@@ -197,6 +197,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc, ...@@ -197,6 +197,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
work->event = event; work->event = event;
work->adev = adev; work->adev = adev;
work->crtc_id = amdgpu_crtc->crtc_id; work->crtc_id = amdgpu_crtc->crtc_id;
work->async = (page_flip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0;
/* schedule unpin of the old buffer */ /* schedule unpin of the old buffer */
old_amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb); old_amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
......
...@@ -283,7 +283,7 @@ struct amdgpu_display_funcs { ...@@ -283,7 +283,7 @@ struct amdgpu_display_funcs {
u32 (*hpd_get_gpio_reg)(struct amdgpu_device *adev); u32 (*hpd_get_gpio_reg)(struct amdgpu_device *adev);
/* pageflipping */ /* pageflipping */
void (*page_flip)(struct amdgpu_device *adev, void (*page_flip)(struct amdgpu_device *adev,
int crtc_id, u64 crtc_base); int crtc_id, u64 crtc_base, bool async);
int (*page_flip_get_scanoutpos)(struct amdgpu_device *adev, int crtc, int (*page_flip_get_scanoutpos)(struct amdgpu_device *adev, int crtc,
u32 *vbl, u32 *position); u32 *vbl, u32 *position);
/* display topology setup */ /* display topology setup */
......
...@@ -284,10 +284,16 @@ static void dce_v10_0_pageflip_interrupt_fini(struct amdgpu_device *adev) ...@@ -284,10 +284,16 @@ static void dce_v10_0_pageflip_interrupt_fini(struct amdgpu_device *adev)
* surface base address. * surface base address.
*/ */
static void dce_v10_0_page_flip(struct amdgpu_device *adev, static void dce_v10_0_page_flip(struct amdgpu_device *adev,
int crtc_id, u64 crtc_base) int crtc_id, u64 crtc_base, bool async)
{ {
struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
u32 tmp;
/* flip at hsync for async, default is vsync */
tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, async ? 1 : 0);
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
/* update the primary scanout address */ /* update the primary scanout address */
WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
upper_32_bits(crtc_base)); upper_32_bits(crtc_base));
...@@ -2211,6 +2217,14 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, ...@@ -2211,6 +2217,14 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
dce_v10_0_vga_enable(crtc, false); dce_v10_0_vga_enable(crtc, false);
/* Make sure surface address is updated at vertical blank rather than
* horizontal blank
*/
tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
upper_32_bits(fb_location)); upper_32_bits(fb_location));
WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
...@@ -2261,13 +2275,6 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, ...@@ -2261,13 +2275,6 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc,
WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
(viewport_w << 16) | viewport_h); (viewport_w << 16) | viewport_h);
/* pageflip setup */
/* make sure flip is at vb rather than hb */
tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
/* set pageflip to happen only at start of vblank interval (front porch) */ /* set pageflip to happen only at start of vblank interval (front porch) */
WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3);
...@@ -2992,6 +2999,8 @@ static int dce_v10_0_sw_init(void *handle) ...@@ -2992,6 +2999,8 @@ static int dce_v10_0_sw_init(void *handle)
adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
adev->ddev->mode_config.async_page_flip = true;
adev->ddev->mode_config.max_width = 16384; adev->ddev->mode_config.max_width = 16384;
adev->ddev->mode_config.max_height = 16384; adev->ddev->mode_config.max_height = 16384;
......
...@@ -302,10 +302,17 @@ static void dce_v11_0_pageflip_interrupt_fini(struct amdgpu_device *adev) ...@@ -302,10 +302,17 @@ static void dce_v11_0_pageflip_interrupt_fini(struct amdgpu_device *adev)
* surface base address. * surface base address.
*/ */
static void dce_v11_0_page_flip(struct amdgpu_device *adev, static void dce_v11_0_page_flip(struct amdgpu_device *adev,
int crtc_id, u64 crtc_base) int crtc_id, u64 crtc_base, bool async)
{ {
struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
u32 tmp;
/* flip at hsync for async, default is vsync */
/* use UPDATE_IMMEDIATE_EN instead for async? */
tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, async ? 1 : 0);
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
/* update the scanout addresses */ /* update the scanout addresses */
WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
upper_32_bits(crtc_base)); upper_32_bits(crtc_base));
...@@ -2185,6 +2192,14 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, ...@@ -2185,6 +2192,14 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
dce_v11_0_vga_enable(crtc, false); dce_v11_0_vga_enable(crtc, false);
/* Make sure surface address is updated at vertical blank rather than
* horizontal blank
*/
tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
upper_32_bits(fb_location)); upper_32_bits(fb_location));
WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
...@@ -2235,13 +2250,6 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, ...@@ -2235,13 +2250,6 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc,
WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
(viewport_w << 16) | viewport_h); (viewport_w << 16) | viewport_h);
/* pageflip setup */
/* make sure flip is at vb rather than hb */
tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL,
GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0);
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
/* set pageflip to happen only at start of vblank interval (front porch) */ /* set pageflip to happen only at start of vblank interval (front porch) */
WREG32(mmCRTC_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); WREG32(mmCRTC_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3);
...@@ -3042,6 +3050,8 @@ static int dce_v11_0_sw_init(void *handle) ...@@ -3042,6 +3050,8 @@ static int dce_v11_0_sw_init(void *handle)
adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
adev->ddev->mode_config.async_page_flip = true;
adev->ddev->mode_config.max_width = 16384; adev->ddev->mode_config.max_width = 16384;
adev->ddev->mode_config.max_height = 16384; adev->ddev->mode_config.max_height = 16384;
......
...@@ -233,10 +233,13 @@ static void dce_v8_0_pageflip_interrupt_fini(struct amdgpu_device *adev) ...@@ -233,10 +233,13 @@ static void dce_v8_0_pageflip_interrupt_fini(struct amdgpu_device *adev)
* surface base address. * surface base address.
*/ */
static void dce_v8_0_page_flip(struct amdgpu_device *adev, static void dce_v8_0_page_flip(struct amdgpu_device *adev,
int crtc_id, u64 crtc_base) int crtc_id, u64 crtc_base, bool async)
{ {
struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id];
/* flip at hsync for async, default is vsync */
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, async ?
GRPH_FLIP_CONTROL__GRPH_SURFACE_UPDATE_H_RETRACE_EN_MASK : 0);
/* update the primary scanout addresses */ /* update the primary scanout addresses */
WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
upper_32_bits(crtc_base)); upper_32_bits(crtc_base));
...@@ -1999,7 +2002,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, ...@@ -1999,7 +2002,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
uint32_t fb_format, fb_pitch_pixels; uint32_t fb_format, fb_pitch_pixels;
u32 fb_swap = (GRPH_ENDIAN_NONE << GRPH_SWAP_CNTL__GRPH_ENDIAN_SWAP__SHIFT); u32 fb_swap = (GRPH_ENDIAN_NONE << GRPH_SWAP_CNTL__GRPH_ENDIAN_SWAP__SHIFT);
u32 pipe_config; u32 pipe_config;
u32 tmp, viewport_w, viewport_h; u32 viewport_w, viewport_h;
int r; int r;
bool bypass_lut = false; bool bypass_lut = false;
...@@ -2135,6 +2138,11 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, ...@@ -2135,6 +2138,11 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
dce_v8_0_vga_enable(crtc, false); dce_v8_0_vga_enable(crtc, false);
/* Make sure surface address is updated at vertical blank rather than
* horizontal blank
*/
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, 0);
WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
upper_32_bits(fb_location)); upper_32_bits(fb_location));
WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset,
...@@ -2182,12 +2190,6 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, ...@@ -2182,12 +2190,6 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc,
WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset,
(viewport_w << 16) | viewport_h); (viewport_w << 16) | viewport_h);
/* pageflip setup */
/* make sure flip is at vb rather than hb */
tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset);
tmp &= ~GRPH_FLIP_CONTROL__GRPH_SURFACE_UPDATE_H_RETRACE_EN_MASK;
WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp);
/* set pageflip to happen only at start of vblank interval (front porch) */ /* set pageflip to happen only at start of vblank interval (front porch) */
WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3);
...@@ -2902,6 +2904,8 @@ static int dce_v8_0_sw_init(void *handle) ...@@ -2902,6 +2904,8 @@ static int dce_v8_0_sw_init(void *handle)
adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; adev->ddev->mode_config.funcs = &amdgpu_mode_funcs;
adev->ddev->mode_config.async_page_flip = true;
adev->ddev->mode_config.max_width = 16384; adev->ddev->mode_config.max_width = 16384;
adev->ddev->mode_config.max_height = 16384; adev->ddev->mode_config.max_height = 16384;
......
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