[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