[PATCH] drm/radeon: cleanup and fix crtc while programming mc
Alex Deucher
alexdeucher at gmail.com
Thu Jul 26 17:35:57 PDT 2012
On Thu, Jul 26, 2012 at 7:24 PM, <j.glisse at gmail.com> wrote:
> From: Jerome Glisse <jglisse at redhat.com>
>
> When we change start address of vram for the GPU memory controller
> we need to make sure that nothing in the GPU still use the old vram
> address. This patch cleanup and fix crtc address.
>
> However there is still someissue somewhere if we reenable the crtc
> after updating the address at which they sancout. So to avoid any
> issue disable crtc. Once we want to do flicker less transition
> btw uefi and radeon we will probably want to revisit how we program
> the GPU memory controller.
>
> This probably fix :
> https://bugs.freedesktop.org/show_bug.cgi?id=52467
> https://bugs.freedesktop.org/show_bug.cgi?id=42373
>
> Cc: <stable at vger.kernel.org>
this should be stable at vger.kernel.org
> Signed-off-by: Jerome Glisse <jglisse at redhat.com>
Also, I think we probably need to poll on bit 16
(CRTC_CURRENT_MASTER_EN_STATE) of CRTC_CONTROL to make sure the crtc
is actually disabled. Something like the following in mc_stop():
WREG32(CRTC_CONTROL, 0);
while (RREG32(CRTC_CONTROL & CRTC_CURRENT_MASTER_EN_STATE))
udelay(1);
Any chance you want to fix the rv515_mc_stop() and rv515_mc_resume()
functions as well?
Alex
> ---
> drivers/gpu/drm/radeon/evergreen.c | 178 ++++++++++++++++------------------
> drivers/gpu/drm/radeon/radeon_asic.h | 18 +++-
> 2 files changed, 99 insertions(+), 97 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
> index e585a3b..c6ede66 100644
> --- a/drivers/gpu/drm/radeon/evergreen.c
> +++ b/drivers/gpu/drm/radeon/evergreen.c
> @@ -1227,70 +1227,94 @@ void evergreen_agp_enable(struct radeon_device *rdev)
> WREG32(VM_CONTEXT1_CNTL, 0);
> }
>
> +static void evergreen_crtc_save(struct radeon_device *rdev, struct evergreen_mc_save *save, unsigned idx)
> +{
> + save->crtc[idx].paddress = 0;
> + save->crtc[idx].saddress = 0;
> + save->crtc[idx].crtc_control = 0;
> +
> + if (idx >= rdev->num_crtc) {
> + /* it seems accessing non existant crtc trigger high latency */
> + return;
> + }
> +
> + save->crtc[idx].paddress = RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + save->crtc[idx].offset);
> + save->crtc[idx].paddress |= ((uint64_t)RREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset)) << 32ULL;
> + save->crtc[idx].saddress = RREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + save->crtc[idx].offset);
> + save->crtc[idx].saddress |= ((uint64_t)RREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset)) << 32ULL;
> + save->crtc[idx].crtc_control = RREG32(EVERGREEN_CRTC_CONTROL + save->crtc[idx].offset);
> + /* We need to disable all crtc as for some reason crtc scanout
> + * base address does not happen properly when changing the
> + * mc vram start address. Don't remove this or you will break
> + * things on uefi system.
> + */
> + save->crtc[idx].crtc_control = 0;
> + save->crtc[idx].vga_control = RREG32(save->crtc[idx].vga_control_offset);
> +
> + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 1);
> + WREG32(EVERGREEN_CRTC_CONTROL + save->crtc[idx].offset, 0);
> + WREG32(save->crtc[idx].vga_control_offset, 0);
> + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 0);
> +}
> +
> void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
> {
> - save->vga_control[0] = RREG32(D1VGA_CONTROL);
> - save->vga_control[1] = RREG32(D2VGA_CONTROL);
> + save->crtc[0].offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
> + save->crtc[1].offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
> + save->crtc[2].offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
> + save->crtc[3].offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
> + save->crtc[4].offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
> + save->crtc[5].offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
> + save->crtc[0].vga_control_offset = D1VGA_CONTROL;
> + save->crtc[1].vga_control_offset = D2VGA_CONTROL;
> + save->crtc[2].vga_control_offset = EVERGREEN_D3VGA_CONTROL;
> + save->crtc[3].vga_control_offset = EVERGREEN_D4VGA_CONTROL;
> + save->crtc[4].vga_control_offset = EVERGREEN_D5VGA_CONTROL;
> + save->crtc[5].vga_control_offset = EVERGREEN_D6VGA_CONTROL;
> +
> + save->fb_address = (uint64_t)(RREG32(MC_VM_FB_LOCATION) & 0xffff) << 24ULL;
> save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
> save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
> - save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
> - save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
> - if (rdev->num_crtc >= 4) {
> - save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
> - save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
> - save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
> - save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
> - }
> - if (rdev->num_crtc >= 6) {
> - save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
> - save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
> - save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
> - save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
> - }
>
> /* Stop all video */
> WREG32(VGA_RENDER_CONTROL, 0);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
> - }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
> - }
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
> - }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
> - }
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
> - }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
> + evergreen_crtc_save(rdev, save, 0);
> + evergreen_crtc_save(rdev, save, 1);
> + evergreen_crtc_save(rdev, save, 2);
> + evergreen_crtc_save(rdev, save, 3);
> + evergreen_crtc_save(rdev, save, 4);
> + evergreen_crtc_save(rdev, save, 5);
> +}
> +
> +static void evergreen_crtc_restore(struct radeon_device *rdev, struct evergreen_mc_save *save, unsigned idx)
> +{
> + if (idx >= rdev->num_crtc) {
> + /* it seems accessing non existant crtc trigger high latency */
> + return;
> }
>
> - WREG32(D1VGA_CONTROL, 0);
> - WREG32(D2VGA_CONTROL, 0);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_D3VGA_CONTROL, 0);
> - WREG32(EVERGREEN_D4VGA_CONTROL, 0);
> + /* update new primary and secondary address */
> + if (save->crtc[idx].paddress) {
> + save->crtc[idx].paddress -= save->fb_address;
> }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_D5VGA_CONTROL, 0);
> - WREG32(EVERGREEN_D6VGA_CONTROL, 0);
> + save->crtc[idx].paddress += rdev->mc.vram_start;
> + if (save->crtc[idx].saddress) {
> + save->crtc[idx].saddress -= save->fb_address;
> }
> + save->crtc[idx].saddress += rdev->mc.vram_start;
> +
> + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 1);
> + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + save->crtc[idx].offset, lower_32_bits(save->crtc[idx].paddress));
> + WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset, upper_32_bits(save->crtc[idx].paddress) & 0xff);
> + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + save->crtc[idx].offset, lower_32_bits(save->crtc[idx].saddress));
> + WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + save->crtc[idx].offset, upper_32_bits(save->crtc[idx].saddress) & 0xff);
> + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 0);
> + WREG32(EVERGREEN_MASTER_UPDATE_MODE + save->crtc[idx].offset, 0);
> +
> + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 1);
> + WREG32(save->crtc[idx].vga_control_offset, save->crtc[idx].vga_control);
> + WREG32(EVERGREEN_CRTC_CONTROL + save->crtc[idx].offset, save->crtc[idx].crtc_control | EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE);
> + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + save->crtc[idx].offset, 0);
> }
>
> void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
> @@ -1357,47 +1381,15 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
> /* Unlock host access */
> WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
> mdelay(1);
> +
> /* Restore video state */
> - WREG32(D1VGA_CONTROL, save->vga_control[0]);
> - WREG32(D2VGA_CONTROL, save->vga_control[1]);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
> - WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
> - }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
> - WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
> - }
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
> - }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
> - }
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
> - }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
> - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
> - }
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
> - if (rdev->num_crtc >= 4) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
> - }
> - if (rdev->num_crtc >= 6) {
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
> - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
> - }
> + evergreen_crtc_restore(rdev, save, 0);
> + evergreen_crtc_restore(rdev, save, 1);
> + evergreen_crtc_restore(rdev, save, 2);
> + evergreen_crtc_restore(rdev, save, 3);
> + evergreen_crtc_restore(rdev, save, 4);
> + evergreen_crtc_restore(rdev, save, 5);
> +
> WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
> }
>
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index f4af243..d450218 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -388,12 +388,22 @@ void r700_cp_fini(struct radeon_device *rdev);
> /*
> * evergreen
> */
> +struct evergreen_crtc_save {
> + uint64_t paddress;
> + uint64_t saddress;
> + uint32_t crtc_control;
> + uint32_t vga_control;
> + uint32_t offset;
> + uint32_t vga_control_offset;
> +};
> +
> struct evergreen_mc_save {
> - u32 vga_control[6];
> - u32 vga_render_control;
> - u32 vga_hdp_control;
> - u32 crtc_control[6];
> + struct evergreen_crtc_save crtc[RADEON_MAX_CRTCS];
> + uint64_t fb_address;
> + uint32_t vga_render_control;
> + uint32_t vga_hdp_control;
> };
> +
> void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev);
> int evergreen_init(struct radeon_device *rdev);
> void evergreen_fini(struct radeon_device *rdev);
> --
> 1.7.10.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list