Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4366f3b5 authored by Mario Kleiner's avatar Mario Kleiner Committed by Alex Deucher
Browse files

drm/radeon: Bypass hw lut's for > 8 bpc framebuffer scanout.



The hardware lut's only have 256 slots for indexing by a
8 bpc framebuffer. In 10 bpc scanout modes, framebuffer
color values would get truncated to their 8 msb's,
thereby losing the extra precision afforded by a 10 bpc
framebuffer.

To retain full precision, bypass the hw lut in 10 bpc
scanout mode.

Signed-off-by: default avatarMario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 8bae4276
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -1136,6 +1136,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
	u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
	u32 tmp, viewport_w, viewport_h;
	int r;
	bool bypass_lut = false;

	/* no fb bound */
	if (!atomic && !crtc->primary->fb) {
@@ -1225,6 +1226,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
#ifdef __BIG_ENDIAN
		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
#endif
		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
		bypass_lut = true;
		break;
	case DRM_FORMAT_BGRX1010102:
	case DRM_FORMAT_BGRA1010102:
@@ -1233,6 +1236,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
#ifdef __BIG_ENDIAN
		fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
#endif
		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
		bypass_lut = true;
		break;
	default:
		DRM_ERROR("Unsupported screen format %s\n",
@@ -1365,6 +1370,18 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
	WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
	WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);

	/*
	 * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT
	 * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to
	 * retain the full precision throughout the pipeline.
	 */
	WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset,
		 (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0),
		 ~EVERGREEN_LUT_10BIT_BYPASS_EN);

	if (bypass_lut)
		DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n");

	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
	WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
@@ -1432,6 +1449,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
	u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE;
	u32 tmp, viewport_w, viewport_h;
	int r;
	bool bypass_lut = false;

	/* no fb bound */
	if (!atomic && !crtc->primary->fb) {
@@ -1517,6 +1535,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
#ifdef __BIG_ENDIAN
		fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
#endif
		/* Greater 8 bpc fb needs to bypass hw-lut to retain precision */
		bypass_lut = true;
		break;
	default:
		DRM_ERROR("Unsupported screen format %s\n",
@@ -1559,6 +1579,13 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
	if (rdev->family >= CHIP_R600)
		WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);

	/* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */
	WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset,
		 (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN);

	if (bypass_lut)
		DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n");

	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
+2 −0
Original line number Diff line number Diff line
@@ -116,6 +116,8 @@
#       define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED      1
#       define EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1      2
#       define EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1      4
#define EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL         0x6808
#       define EVERGREEN_LUT_10BIT_BYPASS_EN            (1 << 8)
#define EVERGREEN_GRPH_SWAP_CONTROL                     0x680c
#       define EVERGREEN_GRPH_ENDIAN_SWAP(x)            (((x) & 0x3) << 0)
#       define EVERGREEN_GRPH_ENDIAN_NONE               0
+1 −0
Original line number Diff line number Diff line
@@ -402,6 +402,7 @@
 * block and vice versa.  This applies to GRPH, CUR, etc.
 */
#define AVIVO_D1GRPH_LUT_SEL                                    0x6108
#       define AVIVO_LUT_10BIT_BYPASS_EN                        (1 << 8)
#define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS                    0x6110
#define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH                0x6914
#define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH                0x6114
+2 −1
Original line number Diff line number Diff line
@@ -66,7 +66,8 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc)
			     (radeon_crtc->lut_b[i] << 0));
	}

	WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id);
	/* Only change bit 0 of LUT_SEL, other bits are set elsewhere */
	WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id, ~1);
}

static void dce4_crtc_load_lut(struct drm_crtc *crtc)