Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Mario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Mario Kleiner and committed by
Alex Deucher
4366f3b5 8bae4276

+32 -1
+27
drivers/gpu/drm/radeon/atombios_crtc.c
··· 1136 1136 u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 1137 1137 u32 tmp, viewport_w, viewport_h; 1138 1138 int r; 1139 + bool bypass_lut = false; 1139 1140 1140 1141 /* no fb bound */ 1141 1142 if (!atomic && !crtc->primary->fb) { ··· 1226 1225 #ifdef __BIG_ENDIAN 1227 1226 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1228 1227 #endif 1228 + /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 1229 + bypass_lut = true; 1229 1230 break; 1230 1231 case DRM_FORMAT_BGRX1010102: 1231 1232 case DRM_FORMAT_BGRA1010102: ··· 1236 1233 #ifdef __BIG_ENDIAN 1237 1234 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 1238 1235 #endif 1236 + /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 1237 + bypass_lut = true; 1239 1238 break; 1240 1239 default: 1241 1240 DRM_ERROR("Unsupported screen format %s\n", ··· 1370 1365 WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1371 1366 WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1372 1367 1368 + /* 1369 + * The LUT only has 256 slots for indexing by a 8 bpc fb. Bypass the LUT 1370 + * for > 8 bpc scanout to avoid truncation of fb indices to 8 msb's, to 1371 + * retain the full precision throughout the pipeline. 1372 + */ 1373 + WREG32_P(EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL + radeon_crtc->crtc_offset, 1374 + (bypass_lut ? EVERGREEN_LUT_10BIT_BYPASS_EN : 0), 1375 + ~EVERGREEN_LUT_10BIT_BYPASS_EN); 1376 + 1377 + if (bypass_lut) 1378 + DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 1379 + 1373 1380 WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1374 1381 WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); 1375 1382 WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0); ··· 1449 1432 u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; 1450 1433 u32 tmp, viewport_w, viewport_h; 1451 1434 int r; 1435 + bool bypass_lut = false; 1452 1436 1453 1437 /* no fb bound */ 1454 1438 if (!atomic && !crtc->primary->fb) { ··· 1535 1517 #ifdef __BIG_ENDIAN 1536 1518 fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 1537 1519 #endif 1520 + /* Greater 8 bpc fb needs to bypass hw-lut to retain precision */ 1521 + bypass_lut = true; 1538 1522 break; 1539 1523 default: 1540 1524 DRM_ERROR("Unsupported screen format %s\n", ··· 1578 1558 WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); 1579 1559 if (rdev->family >= CHIP_R600) 1580 1560 WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap); 1561 + 1562 + /* LUT only has 256 slots for 8 bpc fb. Bypass for > 8 bpc scanout for precision */ 1563 + WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, 1564 + (bypass_lut ? AVIVO_LUT_10BIT_BYPASS_EN : 0), ~AVIVO_LUT_10BIT_BYPASS_EN); 1565 + 1566 + if (bypass_lut) 1567 + DRM_DEBUG_KMS("Bypassing hardware LUT due to 10 bit fb scanout.\n"); 1581 1568 1582 1569 WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); 1583 1570 WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
+2
drivers/gpu/drm/radeon/evergreen_reg.h
··· 116 116 # define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED 1 117 117 # define EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1 2 118 118 # define EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1 4 119 + #define EVERGREEN_GRPH_LUT_10BIT_BYPASS_CONTROL 0x6808 120 + # define EVERGREEN_LUT_10BIT_BYPASS_EN (1 << 8) 119 121 #define EVERGREEN_GRPH_SWAP_CONTROL 0x680c 120 122 # define EVERGREEN_GRPH_ENDIAN_SWAP(x) (((x) & 0x3) << 0) 121 123 # define EVERGREEN_GRPH_ENDIAN_NONE 0
+1
drivers/gpu/drm/radeon/r500_reg.h
··· 402 402 * block and vice versa. This applies to GRPH, CUR, etc. 403 403 */ 404 404 #define AVIVO_D1GRPH_LUT_SEL 0x6108 405 + # define AVIVO_LUT_10BIT_BYPASS_EN (1 << 8) 405 406 #define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 406 407 #define R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914 407 408 #define R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114
+2 -1
drivers/gpu/drm/radeon/radeon_display.c
··· 66 66 (radeon_crtc->lut_b[i] << 0)); 67 67 } 68 68 69 - WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); 69 + /* Only change bit 0 of LUT_SEL, other bits are set elsewhere */ 70 + WREG32_P(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id, ~1); 70 71 } 71 72 72 73 static void dce4_crtc_load_lut(struct drm_crtc *crtc)