diff options
author | Christopher Harvey <charvey@matrox.com> | 2013-05-08 15:10:38 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-05-12 22:17:32 -0400 |
commit | 9f1d036648c1c5ed81b0e98d7a06d55df972701e (patch) | |
tree | 78600dce323c045b93d35d1e3d18799d992df65d | |
parent | 3cdc0e8d6142aaf3eb84a53eab6de1160da290a3 (diff) |
drm/mgag200: Fix framebuffer base address programming
Higher bits of the base address of framebuffers weren't being
programmed properly. This caused framebuffers that didn't happen to be
allocated at a low enough address to not be displayed properly.
Signed-off-by: Christopher Harvey <charvey@matrox.com>
Signed-off-by: Mathieu Larouche <mathieu.larouche@matrox.com>
Acked-by: Julia Lemire <jlemire@matrox.com>
Tested-by: Julia Lemire <jlemire@matrox.com>
Cc: stable@vger.kernel.org
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_mode.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 0326989a6aec..e8e20c653b1d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c | |||
@@ -654,12 +654,26 @@ static void mga_g200wb_commit(struct drm_crtc *crtc) | |||
654 | WREG_DAC(MGA1064_GEN_IO_DATA, tmp); | 654 | WREG_DAC(MGA1064_GEN_IO_DATA, tmp); |
655 | } | 655 | } |
656 | 656 | ||
657 | 657 | /* | |
658 | This is how the framebuffer base address is stored in g200 cards: | ||
659 | * Assume @offset is the gpu_addr variable of the framebuffer object | ||
660 | * Then addr is the number of _pixels_ (not bytes) from the start of | ||
661 | VRAM to the first pixel we want to display. (divided by 2 for 32bit | ||
662 | framebuffers) | ||
663 | * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers | ||
664 | addr<20> -> CRTCEXT0<6> | ||
665 | addr<19-16> -> CRTCEXT0<3-0> | ||
666 | addr<15-8> -> CRTCC<7-0> | ||
667 | addr<7-0> -> CRTCD<7-0> | ||
668 | CRTCEXT0 has to be programmed last to trigger an update and make the | ||
669 | new addr variable take effect. | ||
670 | */ | ||
658 | void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) | 671 | void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) |
659 | { | 672 | { |
660 | struct mga_device *mdev = crtc->dev->dev_private; | 673 | struct mga_device *mdev = crtc->dev->dev_private; |
661 | u32 addr; | 674 | u32 addr; |
662 | int count; | 675 | int count; |
676 | u8 crtcext0; | ||
663 | 677 | ||
664 | while (RREG8(0x1fda) & 0x08); | 678 | while (RREG8(0x1fda) & 0x08); |
665 | while (!(RREG8(0x1fda) & 0x08)); | 679 | while (!(RREG8(0x1fda) & 0x08)); |
@@ -667,10 +681,17 @@ void mga_set_start_address(struct drm_crtc *crtc, unsigned offset) | |||
667 | count = RREG8(MGAREG_VCOUNT) + 2; | 681 | count = RREG8(MGAREG_VCOUNT) + 2; |
668 | while (RREG8(MGAREG_VCOUNT) < count); | 682 | while (RREG8(MGAREG_VCOUNT) < count); |
669 | 683 | ||
670 | addr = offset >> 2; | 684 | WREG8(MGAREG_CRTCEXT_INDEX, 0); |
685 | crtcext0 = RREG8(MGAREG_CRTCEXT_DATA); | ||
686 | crtcext0 &= 0xB0; | ||
687 | addr = offset / 8; | ||
688 | /* Can't store addresses any higher than that... | ||
689 | but we also don't have more than 16MB of memory, so it should be fine. */ | ||
690 | WARN_ON(addr > 0x1fffff); | ||
691 | crtcext0 |= (!!(addr & (1<<20)))<<6; | ||
671 | WREG_CRT(0x0d, (u8)(addr & 0xff)); | 692 | WREG_CRT(0x0d, (u8)(addr & 0xff)); |
672 | WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff); | 693 | WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff); |
673 | WREG_CRT(0xaf, (u8)(addr >> 16) & 0xf); | 694 | WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0); |
674 | } | 695 | } |
675 | 696 | ||
676 | 697 | ||