diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 541ae39..79b60f1 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -39,6 +39,40 @@ static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); +void evergreen_page_flip(struct drm_crtc *crtc, u64 crtc_base) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +#if 0 + radeon_ring_write(rdev, + PACKET0(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, upper_32_bits(crtc_base)); + radeon_ring_write(rdev, + PACKET0(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); +#endif + radeon_ring_write(rdev, + PACKET0(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, upper_32_bits(crtc_base)); + radeon_ring_write(rdev, + PACKET0(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); +#if 1 + radeon_ring_write(rdev, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + radeon_ring_write(rdev, (PACKET3_WAIT_REG_MEM_ENGINE(ENGINE_ME) | + PACKET3_WAIT_REG_MEM_MEM_SPACE(MEM_SPACE_REG) | + PACKET3_WAIT_REG_MEM_FUNCTION(FUNCTION_E))); + radeon_ring_write(rdev, (EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) >> 2); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, EVERGREEN_GRPH_SURFACE_UPDATE_PENDING); + radeon_ring_write(rdev, 10); +#endif + radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0)); + radeon_ring_write(rdev, RB_INT_STAT); +} + /* get temperature in millidegrees */ u32 evergreen_get_temp(struct radeon_device *rdev) { @@ -1593,6 +1627,7 @@ int evergreen_irq_set(struct radeon_device *rdev) hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + cp_int_cntl |= RB_INT_ENABLE; if (rdev->irq.sw_int) { DRM_DEBUG("evergreen_irq_set: sw int\n"); cp_int_cntl |= RB_INT_ENABLE; @@ -1992,7 +2027,8 @@ restart_ih: case 8: /* D1 pflip */ switch (src_data) { case 0: /* D1 pflip */ - DRM_DEBUG("IH: D1 pflip\n"); + DRM_INFO("IH: D1 pflip\n"); + radeon_crtc_handle_flip(rdev, 0); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -2002,7 +2038,8 @@ restart_ih: case 10: /* D2 pflip */ switch (src_data) { case 0: /* D2 pflip */ - DRM_DEBUG("IH: D2 pflip\n"); + DRM_INFO("IH: D2 pflip\n"); + radeon_crtc_handle_flip(rdev, 1); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -2012,7 +2049,8 @@ restart_ih: case 12: /* D3 pflip */ switch (src_data) { case 0: /* D3 pflip */ - DRM_DEBUG("IH: D3 pflip\n"); + DRM_INFO("IH: D3 pflip\n"); + radeon_crtc_handle_flip(rdev, 2); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -2022,7 +2060,8 @@ restart_ih: case 14: /* D4 pflip */ switch (src_data) { case 0: /* D4 pflip */ - DRM_DEBUG("IH: D4 pflip\n"); + DRM_INFO("IH: D4 pflip\n"); + radeon_crtc_handle_flip(rdev, 3); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -2032,7 +2071,8 @@ restart_ih: case 16: /* D5 pflip */ switch (src_data) { case 0: /* D5 pflip */ - DRM_DEBUG("IH: D5 pflip\n"); + DRM_INFO("IH: D5 pflip\n"); + radeon_crtc_handle_flip(rdev, 4); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -2042,7 +2082,8 @@ restart_ih: case 18: /* D6 pflip */ switch (src_data) { case 0: /* D6 pflip */ - DRM_DEBUG("IH: D6 pflip\n"); + DRM_INFO("IH: D6 pflip\n"); + radeon_crtc_handle_flip(rdev, 5); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -2101,8 +2142,9 @@ restart_ih: case 176: /* CP_INT in ring buffer */ case 177: /* CP_INT in IB1 */ case 178: /* CP_INT in IB2 */ - DRM_DEBUG("IH: CP int: 0x%08x\n", src_data); - radeon_fence_process(rdev); + DRM_INFO("IH: CP int: 0x%08x\n", src_data); + //radeon_fence_process(rdev); + radeon_crtc_handle_flip(rdev, 0); break; case 181: /* CP EOP event */ DRM_DEBUG("IH: CP EOP\n"); diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 2330f3a..e8c625b 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -105,6 +105,9 @@ #define EVERGREEN_GRPH_Y_START 0x6830 #define EVERGREEN_GRPH_X_END 0x6834 #define EVERGREEN_GRPH_Y_END 0x6838 +#define EVERGREEN_GRPH_UPDATE 0x6844 +# define EVERGREEN_GRPH_SURFACE_UPDATE_PENDING (1 << 2) +# define EVERGREEN_GRPH_UPDATE_LOCK (1 << 16) /* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */ #define EVERGREEN_CUR_CONTROL 0x6998 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 319aa97..ac89775 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -615,6 +615,20 @@ #define PACKET3_MEM_SEMAPHORE 0x39 #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_WAIT_REG_MEM 0x3C +# define PACKET3_WAIT_REG_MEM_ENGINE(x) ((x) << 8) +# define ENGINE_ME 0 +# define ENGINE_PFP 1 +# define PACKET3_WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) +# define MEM_SPACE_REG 0 +# define MEM_SPACE_MEM 1 +# define PACKET3_WAIT_REG_MEM_FUNCTION(x) ((x) << 0) +# define FUNCTION_ALWAYS 0 +# define FUNCTION_LT 1 +# define FUNCTION_LTE 2 +# define FUNCTION_E 3 +# define FUNCTION_NE 4 +# define FUNCTION_GTE 5 +# define FUNCTION_GT 6 #define PACKET3_MEM_WRITE 0x3D #define PACKET3_INDIRECT_BUFFER 0x32 #define PACKET3_SURFACE_SYNC 0x43 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 6112ac9..914f37b 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -68,6 +68,23 @@ MODULE_FIRMWARE(FIRMWARE_R520); * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +void r100_page_flip(struct drm_crtc *crtc, u64 crtc_base) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + /* crtc offset is from display base addr not FB location */ + crtc_base -= radeon_crtc->legacy_display_base_addr; + + radeon_ring_write(rdev, + PACKET0(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, RADEON_WAIT_CRTC_PFLIP | (radeon_crtc->crtc_id << 31)); + +} + void r100_pm_get_dynpm_state(struct radeon_device *rdev) { int i; diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 6ac1f60..bc1eea1 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -409,6 +409,7 @@ #define AVIVO_D1GRPH_X_END 0x6134 #define AVIVO_D1GRPH_Y_END 0x6138 #define AVIVO_D1GRPH_UPDATE 0x6144 +# define AVIVO_D1GRPH_SURFACE_UPDATE_PENDING (1 << 2) # define AVIVO_D1GRPH_UPDATE_LOCK (1 << 16) #define AVIVO_D1GRPH_FLIP_CONTROL 0x6148 diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 6b083db..207d5a4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,6 +92,22 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +void r600_page_flip(struct drm_crtc *crtc, u64 crtc_base) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +#if 0 + radeon_ring_write(rdev, + PACKET0(D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); +#endif + radeon_ring_write(rdev, + PACKET0(D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); + +} + /* get temperature in millidegrees */ u32 rv6xx_get_temp(struct radeon_device *rdev) { @@ -3348,7 +3364,8 @@ restart_ih: case 9: /* D1 pflip */ switch (src_data) { case 0: /* D1 pflip */ - DRM_DEBUG("IH: D1 pflip\n"); + DRM_INFO("IH: D1 pflip\n"); + radeon_crtc_handle_flip(rdev, 0); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -3358,7 +3375,8 @@ restart_ih: case 11: /* D2 pflip */ switch (src_data) { case 0: /* D2 pflip */ - DRM_DEBUG("IH: D2 pflip\n"); + DRM_INFO("IH: D2 pflip\n"); + radeon_crtc_handle_flip(rdev, 1); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 45995b4..0e5b428 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -731,6 +731,12 @@ # define DxGRPH_PFLIP_INT_MASK (1 << 0) # define DxGRPH_PFLIP_INT_TYPE (1 << 8) +#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 +#define D1GRPH_UPDATE 0x6144 +# define D1GRPH_SURFACE_UPDATE_PENDING (1 << 2) +# define D1GRPH_UPDATE_LOCK (1 << 16) + /* * PM4 */ @@ -771,6 +777,20 @@ #define PACKET3_MEM_SEMAPHORE 0x39 #define PACKET3_MPEG_INDEX 0x3A #define PACKET3_WAIT_REG_MEM 0x3C +# define PACKET3_WAIT_REG_MEM_ENGINE(x) ((x) << 8) +# define ENGINE_ME 0 +# define ENGINE_PFP 1 +# define PACKET3_WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) +# define MEM_SPACE_REG 0 +# define MEM_SPACE_MEM 1 +# define PACKET3_WAIT_REG_MEM_FUNCTION(x) ((x) << 0) +# define FUNCTION_ALWAYS 0 +# define FUNCTION_LT 1 +# define FUNCTION_LTE 2 +# define FUNCTION_E 3 +# define FUNCTION_NE 4 +# define FUNCTION_GTE 5 +# define FUNCTION_GT 6 #define PACKET3_MEM_WRITE 0x3D #define PACKET3_INDIRECT_BUFFER 0x32 #define PACKET3_SURFACE_SYNC 0x43 diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3a01e83..c5e8dd9 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -882,6 +882,7 @@ struct radeon_asic { void (*pm_finish)(struct radeon_device *rdev); void (*pm_init_profile)(struct radeon_device *rdev); void (*pm_get_dynpm_state)(struct radeon_device *rdev); + void (*page_flip)(struct drm_crtc *crtc, u64 crtc_base); }; /* @@ -1341,6 +1342,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) #define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev)) #define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev)) #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev)) +#define radeon_page_flip(crtc, base) rdev->asic->page_flip((crtc), (base)) /* Common functions */ /* AGP */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 64fb89e..0da113d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -171,6 +171,7 @@ static struct radeon_asic r100_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &r100_page_flip, }; static struct radeon_asic r200_asic = { @@ -215,6 +216,7 @@ static struct radeon_asic r200_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &r100_page_flip, }; static struct radeon_asic r300_asic = { @@ -260,6 +262,7 @@ static struct radeon_asic r300_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &r100_page_flip, }; static struct radeon_asic r300_asic_pcie = { @@ -304,6 +307,7 @@ static struct radeon_asic r300_asic_pcie = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &r100_page_flip, }; static struct radeon_asic r420_asic = { @@ -349,6 +353,7 @@ static struct radeon_asic r420_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &r100_page_flip, }; static struct radeon_asic rs400_asic = { @@ -394,6 +399,7 @@ static struct radeon_asic rs400_asic = { .pm_finish = &r100_pm_finish, .pm_init_profile = &r100_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &r100_page_flip, }; static struct radeon_asic rs600_asic = { @@ -439,6 +445,7 @@ static struct radeon_asic rs600_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &rs600_page_flip, }; static struct radeon_asic rs690_asic = { @@ -484,6 +491,7 @@ static struct radeon_asic rs690_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &rs600_page_flip, }; static struct radeon_asic rv515_asic = { @@ -529,6 +537,7 @@ static struct radeon_asic rv515_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &rs600_page_flip, }; static struct radeon_asic r520_asic = { @@ -574,6 +583,7 @@ static struct radeon_asic r520_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r420_pm_init_profile, .pm_get_dynpm_state = &r100_pm_get_dynpm_state, + .page_flip = &rs600_page_flip, }; static struct radeon_asic r600_asic = { @@ -618,6 +628,7 @@ static struct radeon_asic r600_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r600_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .page_flip = &r600_page_flip, }; static struct radeon_asic rs780_asic = { @@ -662,6 +673,7 @@ static struct radeon_asic rs780_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &rs780_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .page_flip = &r600_page_flip, }; static struct radeon_asic rv770_asic = { @@ -706,6 +718,7 @@ static struct radeon_asic rv770_asic = { .pm_finish = &rs600_pm_finish, .pm_init_profile = &r600_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .page_flip = &rv770_page_flip, }; static struct radeon_asic evergreen_asic = { @@ -749,6 +762,7 @@ static struct radeon_asic evergreen_asic = { .pm_finish = &evergreen_pm_finish, .pm_init_profile = &r600_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, + .page_flip = &evergreen_page_flip, }; int radeon_asic_init(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 7409882..3678f23 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -130,6 +130,7 @@ extern void r100_pm_prepare(struct radeon_device *rdev); extern void r100_pm_finish(struct radeon_device *rdev); extern void r100_pm_init_profile(struct radeon_device *rdev); extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); +extern void r100_page_flip(struct drm_crtc *crtc, u64 crtc_base); /* * r200,rv250,rs300,rv280 @@ -205,6 +206,7 @@ void rs600_hpd_set_polarity(struct radeon_device *rdev, extern void rs600_pm_misc(struct radeon_device *rdev); extern void rs600_pm_prepare(struct radeon_device *rdev); extern void rs600_pm_finish(struct radeon_device *rdev); +extern void rs600_page_flip(struct drm_crtc *crtc, u64 crtc_base); /* * rs690,rs740 @@ -278,6 +280,7 @@ extern void r600_pm_misc(struct radeon_device *rdev); extern void r600_pm_init_profile(struct radeon_device *rdev); extern void rs780_pm_init_profile(struct radeon_device *rdev); extern void r600_pm_get_dynpm_state(struct radeon_device *rdev); +extern void r600_page_flip(struct drm_crtc *crtc, u64 crtc_base); /* * rv770,rv730,rv710,rv740 @@ -287,6 +290,7 @@ void rv770_fini(struct radeon_device *rdev); int rv770_suspend(struct radeon_device *rdev); int rv770_resume(struct radeon_device *rdev); extern void rv770_pm_misc(struct radeon_device *rdev); +extern void rv770_page_flip(struct drm_crtc *crtc, u64 crtc_base); /* * evergreen @@ -314,5 +318,6 @@ extern int evergreen_cs_parse(struct radeon_cs_parser *p); extern void evergreen_pm_misc(struct radeon_device *rdev); extern void evergreen_pm_prepare(struct radeon_device *rdev); extern void evergreen_pm_finish(struct radeon_device *rdev); +extern void evergreen_page_flip(struct drm_crtc *crtc, u64 crtc_base); #endif diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 0383631..124d192 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -183,12 +183,150 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc) kfree(radeon_crtc); } +void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) +{ + struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; + struct drm_pending_vblank_event *e = radeon_crtc->event; + struct timeval now; + unsigned long flags; + int r; + + spin_lock_irqsave(&rdev->ddev->event_lock, flags); + if (radeon_crtc->flip_old_bo == NULL) { + /* no flip scheduled */ + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); + return; + } + + /* unpin of the old buffer */ + r = radeon_bo_reserve(radeon_crtc->flip_old_bo, false); + if (likely(r == 0)) { + r = radeon_bo_unpin(radeon_crtc->flip_old_bo); + if (unlikely(r != 0)) { + DRM_ERROR("failed to unpin buffer after flip\n"); + } + radeon_bo_unreserve(radeon_crtc->flip_old_bo); + radeon_crtc->flip_old_bo = NULL; + } + + drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id); + + /* wakeup userspace */ + e = radeon_crtc->event; + radeon_crtc->event = NULL; + if (e) { + do_gettimeofday(&now); + e->event.sequence = drm_vblank_count(rdev->ddev, crtc_id); + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + list_add_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + } + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); +} + +static int radeon_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_framebuffer *old_radeon_fb; + struct radeon_framebuffer *new_radeon_fb; + struct drm_gem_object *obj; + struct radeon_bo *rbo; + struct radeon_fence *fence; + unsigned long flags; + u64 base; + int r; + + spin_lock_irqsave(&dev->event_lock, flags); + if (radeon_crtc->flip_old_bo) { + spin_unlock_irqrestore(&dev->event_lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&dev->event_lock, flags); + + old_radeon_fb = to_radeon_framebuffer(crtc->fb); + new_radeon_fb = to_radeon_framebuffer(fb); + + /* pin the new buffer */ + obj = new_radeon_fb->obj; + rbo = obj->driver_private; + r = radeon_bo_reserve(rbo, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &base); + if (unlikely(r != 0)) { + radeon_bo_unreserve(rbo); + return -EINVAL; + } + radeon_bo_unreserve(rbo); + + /* update crtc fb */ + crtc->fb = fb; + + r = drm_vblank_get(dev, radeon_crtc->crtc_id); + if (r) + return r; + + /* 64 ought to cover us */ + r = radeon_ring_lock(rdev, 64); + if (r) + return r; + + /* enable pflip irq */ + DRM_INFO("enable pflip irq\n"); + rdev->irq.pflip[radeon_crtc->crtc_id] = true; + if (rdev->irq.installed) + radeon_irq_set(rdev); + /* put the flip on the ring */ + DRM_INFO("emit pflip\n"); + radeon_page_flip(crtc, base); + /* make sure the flip took place before unpinning */ + DRM_INFO("emit fence\n"); + radeon_fence_create(rdev, &fence); + radeon_fence_emit(rdev, fence); + radeon_ring_unlock_commit(rdev); + //radeon_fence_wait(fence, false); + radeon_fence_unref(&fence); + + DRM_INFO("schedule unpin\n"); + /* schedule unpin of the old buffer */ + obj = old_radeon_fb->obj; + rbo = obj->driver_private; + spin_lock_irqsave(&dev->event_lock, flags); + radeon_crtc->flip_old_bo = rbo; + radeon_crtc->event = event; + spin_unlock_irqrestore(&dev->event_lock, flags); + //radeon_crtc_handle_flip(rdev, radeon_crtc->crtc_id); + +#if 0 + /* unpin the old buffer */ + obj = old_radeon_fb->obj; + rbo = obj->driver_private; + r = radeon_bo_reserve(rbo, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_unpin(rbo); + if (unlikely(r != 0)) { + radeon_bo_unreserve(rbo); + return -EINVAL; + } + radeon_bo_unreserve(rbo); +#endif + DRM_INFO("done radeon_crtc_page_flip\n"); + return 0; +} + static const struct drm_crtc_funcs radeon_crtc_funcs = { .cursor_set = radeon_crtc_cursor_set, .cursor_move = radeon_crtc_cursor_move, .gamma_set = radeon_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, .destroy = radeon_crtc_destroy, + .page_flip = radeon_crtc_page_flip, }; static void radeon_crtc_init(struct drm_device *dev, int index) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 61b9243..d5ab484 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -278,6 +278,8 @@ struct radeon_crtc { fixed20_12 hsc; struct drm_display_mode native_mode; int pll_id; + struct radeon_bo *flip_old_bo; + struct drm_pending_vblank_event *event; }; struct radeon_encoder_primary_dac { @@ -653,4 +655,7 @@ int radeon_fbdev_total_size(struct radeon_device *rdev); bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); void radeon_fb_output_poll_changed(struct radeon_device *rdev); + +void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id); + #endif diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index b091a1f..2b989fe 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -46,6 +46,24 @@ void rs600_gpu_init(struct radeon_device *rdev); int rs600_mc_wait_for_idle(struct radeon_device *rdev); +void rs600_page_flip(struct drm_crtc *crtc, u64 crtc_base) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + /* secondary? */ + radeon_ring_write(rdev, + PACKET0(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); + radeon_ring_write(rdev, + PACKET0(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, RADEON_WAIT_CRTC_PFLIP | (radeon_crtc->crtc_id << 31)); + +} + void rs600_pm_misc(struct radeon_device *rdev) { int requested_index = rdev->pm.requested_power_state_index; diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h index a27c13a..ebe478b 100644 --- a/drivers/gpu/drm/radeon/rs600d.h +++ b/drivers/gpu/drm/radeon/rs600d.h @@ -28,6 +28,19 @@ #ifndef __RS600D_H__ #define __RS600D_H__ +/* PM4 */ +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \ + (((reg) >> 2) & 0xFFFF) | \ + ((n) & 0x3FFF) << 16) +#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) + /* Registers */ #define R_000040_GEN_INT_CNTL 0x000040 #define S_000040_SCRATCH_INT_MASK(x) (((x) & 0x1) << 18) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 245374e..09fa5cd 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -42,6 +42,40 @@ static void rv770_gpu_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); +void rv770_page_flip(struct drm_crtc *crtc, u64 crtc_base) +{ + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); +#if 0 + if (radeon_crtc->crtc_id) { + radeon_ring_write(rdev, + PACKET0(D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0)); + radeon_ring_write(rdev, upper_32_bits(crtc_base)); + } else { + radeon_ring_write(rdev, + PACKET0(D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0)); + radeon_ring_write(rdev, upper_32_bits(crtc_base)); + } + radeon_ring_write(rdev, + PACKET0(D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); +#endif + if (radeon_crtc->crtc_id) { + radeon_ring_write(rdev, + PACKET0(D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0)); + radeon_ring_write(rdev, upper_32_bits(crtc_base)); + } else { + radeon_ring_write(rdev, + PACKET0(D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0)); + radeon_ring_write(rdev, upper_32_bits(crtc_base)); + } + radeon_ring_write(rdev, + PACKET0(D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, 0)); + radeon_ring_write(rdev, (u32)crtc_base); + +} + /* get temperature in millidegrees */ u32 rv770_get_temp(struct radeon_device *rdev) { diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index b7a5a20..aa832cb 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -351,4 +351,43 @@ #define SRBM_STATUS 0x0E50 +#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914 +#define D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114 +#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 +#define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c +#define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c +#define D1GRPH_UPDATE 0x6144 +# define D1GRPH_SURFACE_UPDATE_PENDING (1 << 2) +# define D1GRPH_UPDATE_LOCK (1 << 16) + +/* PM4 */ +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \ + (((reg) >> 2) & 0xFFFF) | \ + ((n) & 0x3FFF) << 16) +#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) + +#define PACKET3_WAIT_REG_MEM 0x3C +# define PACKET3_WAIT_REG_MEM_ENGINE(x) ((x) << 8) +# define ENGINE_ME 0 +# define ENGINE_PFP 1 +# define PACKET3_WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) +# define MEM_SPACE_REG 0 +# define MEM_SPACE_MEM 1 +# define PACKET3_WAIT_REG_MEM_FUNCTION(x) ((x) << 0) +# define FUNCTION_ALWAYS 0 +# define FUNCTION_LT 1 +# define FUNCTION_LTE 2 +# define FUNCTION_E 3 +# define FUNCTION_NE 4 +# define FUNCTION_GTE 5 +# define FUNCTION_GT 6 + #endif