Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Michel Dänzer <michel.daenzer@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

+52 -27
+2 -1
drivers/gpu/drm/amd/amdgpu/amdgpu.h
··· 727 727 unsigned shared_count; 728 728 struct fence **shared; 729 729 struct fence_cb cb; 730 + bool async; 730 731 }; 731 732 732 733 ··· 2244 2243 #define amdgpu_display_hpd_set_polarity(adev, h) (adev)->mode_info.funcs->hpd_set_polarity((adev), (h)) 2245 2244 #define amdgpu_display_hpd_get_gpio_reg(adev) (adev)->mode_info.funcs->hpd_get_gpio_reg((adev)) 2246 2245 #define amdgpu_display_bandwidth_update(adev) (adev)->mode_info.funcs->bandwidth_update((adev)) 2247 - #define amdgpu_display_page_flip(adev, crtc, base) (adev)->mode_info.funcs->page_flip((adev), (crtc), (base)) 2246 + #define amdgpu_display_page_flip(adev, crtc, base, async) (adev)->mode_info.funcs->page_flip((adev), (crtc), (base), (async)) 2248 2247 #define amdgpu_display_page_flip_get_scanoutpos(adev, crtc, vbl, pos) (adev)->mode_info.funcs->page_flip_get_scanoutpos((adev), (crtc), (vbl), (pos)) 2249 2248 #define amdgpu_display_add_encoder(adev, e, s, c) (adev)->mode_info.funcs->add_encoder((adev), (e), (s), (c)) 2250 2249 #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))
+2 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
··· 132 132 vblank->linedur_ns / 1000, stat, vpos, hpos); 133 133 134 134 /* Do the flip (mmio) */ 135 - adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base); 135 + adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base, work->async); 136 136 137 137 /* Set the flip status */ 138 138 amdgpuCrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; ··· 197 197 work->event = event; 198 198 work->adev = adev; 199 199 work->crtc_id = amdgpu_crtc->crtc_id; 200 + work->async = (page_flip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0; 200 201 201 202 /* schedule unpin of the old buffer */ 202 203 old_amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb);
+1 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
··· 283 283 u32 (*hpd_get_gpio_reg)(struct amdgpu_device *adev); 284 284 /* pageflipping */ 285 285 void (*page_flip)(struct amdgpu_device *adev, 286 - int crtc_id, u64 crtc_base); 286 + int crtc_id, u64 crtc_base, bool async); 287 287 int (*page_flip_get_scanoutpos)(struct amdgpu_device *adev, int crtc, 288 288 u32 *vbl, u32 *position); 289 289 /* display topology setup */
+17 -8
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
··· 284 284 * surface base address. 285 285 */ 286 286 static void dce_v10_0_page_flip(struct amdgpu_device *adev, 287 - int crtc_id, u64 crtc_base) 287 + int crtc_id, u64 crtc_base, bool async) 288 288 { 289 289 struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; 290 + u32 tmp; 290 291 292 + /* flip at hsync for async, default is vsync */ 293 + tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset); 294 + tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL, 295 + GRPH_SURFACE_UPDATE_H_RETRACE_EN, async ? 1 : 0); 296 + WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp); 291 297 /* update the primary scanout address */ 292 298 WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, 293 299 upper_32_bits(crtc_base)); ··· 2217 2211 2218 2212 dce_v10_0_vga_enable(crtc, false); 2219 2213 2214 + /* Make sure surface address is updated at vertical blank rather than 2215 + * horizontal blank 2216 + */ 2217 + tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset); 2218 + tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL, 2219 + GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0); 2220 + WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp); 2221 + 2220 2222 WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, 2221 2223 upper_32_bits(fb_location)); 2222 2224 WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, ··· 2274 2260 viewport_h = (crtc->mode.vdisplay + 1) & ~1; 2275 2261 WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, 2276 2262 (viewport_w << 16) | viewport_h); 2277 - 2278 - /* pageflip setup */ 2279 - /* make sure flip is at vb rather than hb */ 2280 - tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset); 2281 - tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL, 2282 - GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0); 2283 - WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp); 2284 2263 2285 2264 /* set pageflip to happen only at start of vblank interval (front porch) */ 2286 2265 WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); ··· 2998 2991 return r; 2999 2992 3000 2993 adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; 2994 + 2995 + adev->ddev->mode_config.async_page_flip = true; 3001 2996 3002 2997 adev->ddev->mode_config.max_width = 16384; 3003 2998 adev->ddev->mode_config.max_height = 16384;
+18 -8
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
··· 302 302 * surface base address. 303 303 */ 304 304 static void dce_v11_0_page_flip(struct amdgpu_device *adev, 305 - int crtc_id, u64 crtc_base) 305 + int crtc_id, u64 crtc_base, bool async) 306 306 { 307 307 struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; 308 + u32 tmp; 308 309 310 + /* flip at hsync for async, default is vsync */ 311 + /* use UPDATE_IMMEDIATE_EN instead for async? */ 312 + tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset); 313 + tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL, 314 + GRPH_SURFACE_UPDATE_H_RETRACE_EN, async ? 1 : 0); 315 + WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp); 309 316 /* update the scanout addresses */ 310 317 WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, 311 318 upper_32_bits(crtc_base)); ··· 2192 2185 2193 2186 dce_v11_0_vga_enable(crtc, false); 2194 2187 2188 + /* Make sure surface address is updated at vertical blank rather than 2189 + * horizontal blank 2190 + */ 2191 + tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset); 2192 + tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL, 2193 + GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0); 2194 + WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp); 2195 + 2195 2196 WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, 2196 2197 upper_32_bits(fb_location)); 2197 2198 WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, ··· 2249 2234 viewport_h = (crtc->mode.vdisplay + 1) & ~1; 2250 2235 WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, 2251 2236 (viewport_w << 16) | viewport_h); 2252 - 2253 - /* pageflip setup */ 2254 - /* make sure flip is at vb rather than hb */ 2255 - tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset); 2256 - tmp = REG_SET_FIELD(tmp, GRPH_FLIP_CONTROL, 2257 - GRPH_SURFACE_UPDATE_H_RETRACE_EN, 0); 2258 - WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp); 2259 2237 2260 2238 /* set pageflip to happen only at start of vblank interval (front porch) */ 2261 2239 WREG32(mmCRTC_MASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); ··· 3049 3041 return r; 3050 3042 3051 3043 adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; 3044 + 3045 + adev->ddev->mode_config.async_page_flip = true; 3052 3046 3053 3047 adev->ddev->mode_config.max_width = 16384; 3054 3048 adev->ddev->mode_config.max_height = 16384;
+12 -8
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
··· 233 233 * surface base address. 234 234 */ 235 235 static void dce_v8_0_page_flip(struct amdgpu_device *adev, 236 - int crtc_id, u64 crtc_base) 236 + int crtc_id, u64 crtc_base, bool async) 237 237 { 238 238 struct amdgpu_crtc *amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; 239 239 240 + /* flip at hsync for async, default is vsync */ 241 + WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, async ? 242 + GRPH_FLIP_CONTROL__GRPH_SURFACE_UPDATE_H_RETRACE_EN_MASK : 0); 240 243 /* update the primary scanout addresses */ 241 244 WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, 242 245 upper_32_bits(crtc_base)); ··· 2002 1999 uint32_t fb_format, fb_pitch_pixels; 2003 2000 u32 fb_swap = (GRPH_ENDIAN_NONE << GRPH_SWAP_CNTL__GRPH_ENDIAN_SWAP__SHIFT); 2004 2001 u32 pipe_config; 2005 - u32 tmp, viewport_w, viewport_h; 2002 + u32 viewport_w, viewport_h; 2006 2003 int r; 2007 2004 bool bypass_lut = false; 2008 2005 ··· 2138 2135 2139 2136 dce_v8_0_vga_enable(crtc, false); 2140 2137 2138 + /* Make sure surface address is updated at vertical blank rather than 2139 + * horizontal blank 2140 + */ 2141 + WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, 0); 2142 + 2141 2143 WREG32(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, 2142 2144 upper_32_bits(fb_location)); 2143 2145 WREG32(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH + amdgpu_crtc->crtc_offset, ··· 2189 2181 viewport_h = (crtc->mode.vdisplay + 1) & ~1; 2190 2182 WREG32(mmVIEWPORT_SIZE + amdgpu_crtc->crtc_offset, 2191 2183 (viewport_w << 16) | viewport_h); 2192 - 2193 - /* pageflip setup */ 2194 - /* make sure flip is at vb rather than hb */ 2195 - tmp = RREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset); 2196 - tmp &= ~GRPH_FLIP_CONTROL__GRPH_SURFACE_UPDATE_H_RETRACE_EN_MASK; 2197 - WREG32(mmGRPH_FLIP_CONTROL + amdgpu_crtc->crtc_offset, tmp); 2198 2184 2199 2185 /* set pageflip to happen only at start of vblank interval (front porch) */ 2200 2186 WREG32(mmMASTER_UPDATE_MODE + amdgpu_crtc->crtc_offset, 3); ··· 2903 2901 return r; 2904 2902 2905 2903 adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; 2904 + 2905 + adev->ddev->mode_config.async_page_flip = true; 2906 2906 2907 2907 adev->ddev->mode_config.max_width = 16384; 2908 2908 adev->ddev->mode_config.max_height = 16384;