u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc) { int vpos, hpos, stat; u32 count; struct radeon_device *rdev = dev->dev_private; if (crtc < 0 || crtc >= rdev->num_crtc) { DRM_ERROR("Invalid crtc %d\n", crtc); return -EINVAL; } /* The hw increments its frame counter at start of vsync, not at start * of vblank, as is required by DRM core vblank counter handling. * Cook the hw count here to make it appear to the caller as if it * incremented at start of vblank. We measure distance to start of * vblank in vpos. vpos therefore will be >= 0 between start of vblank * and start of vsync, so vpos >= 0 means to bump the hw frame counter * result by 1 to give the proper appearance to caller. */ if (rdev->mode_info.crtcs[crtc]) { /* Repeat readout if needed to provide stable result if * we cross start of vsync during the queries. */ do { count = radeon_get_vblank_counter(rdev, crtc); /* Ask radeon_get_crtc_scanoutpos to return vpos as * distance to start of vblank, instead of regular * vertical scanout pos. */ stat = radeon_get_crtc_scanoutpos( dev, crtc, GET_DISTANCE_TO_VBLANKSTART, &vpos, &hpos, NULL, NULL, &rdev->mode_info.crtcs[crtc]->base.hwmode); } while (count != radeon_get_vblank_counter(rdev, crtc)); if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) { DRM_DEBUG_VBL("Query failed! stat %d\n", stat); } else { DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n", crtc, vpos); /* Bump counter if we are at >= leading edge of vblank, * but before vsync where vpos would turn negative and * the hw counter really increments. */ if (vpos >= 0) count++; } } else { /* Fallback to use value as is. */ count = radeon_get_vblank_counter(rdev, crtc); DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n"); } return count; }
static irqreturn_t ade_irq_handler(int irq, void *data) { struct ade_crtc *acrtc = data; struct ade_hw_ctx *ctx = acrtc->ctx; struct drm_crtc *crtc = &acrtc->base; void __iomem *base = ctx->base; u32 status; status = readl(base + LDI_MSK_INT); DRM_DEBUG_VBL("LDI IRQ: status=0x%X\n", status); /* vblank irq */ if (status & BIT(FRAME_END_INT_EN_OFST)) { ade_update_bits(base + LDI_INT_CLR, FRAME_END_INT_EN_OFST, MASK(1), 1); drm_crtc_handle_vblank(crtc); } return IRQ_HANDLED; }