Provide helpers that program hardware gamma LUTs. Tha gamma ramp is either provided by the driver or generated by the helper.
The DRM driver exports the GAMMA_LUT property with a fixed number of entries per color component, such as 256 on 8-bit-wide components. The entries describe the gamma ramp of each individual component. The new helper drm_crtc_load_gamma_888() loads such gamma ramp to hardware. The hardware uses each displayed pixel's individial components as indeces into the hardware gamma table. For color modes with less than 8 bits per color component, the helpers drm_crtc_load_gamma_565_from() and drm_crtc_load_gamma_555_from_888() interpolate the provided gamma ramp to reduce it to the correct number of entries; 5/6/5 for RGB565-like formats and 5/5/5 for RGB1555-like formats. If no gamma ramp has been provided, drivers can use the new helper drm_crtc_fill_gamma_888() to load a default gamma ramp with 256 entries per color component. For color modes with less bits, the new helpers drm_crtc_fill_gamma_565() and drm_crtc_fill_gamma_555() are available. The default gamma ramp uses a gamma factor of 1. Later patches can change this. For PCs, a gamma factor of 2.2 is common. For color modes with palette, drm_crtc_load_palette_8() load an 8-bit palette into the hardware. If no palette has been specified, drm_crtc_fill_palette_8() load a system-specific default palette. This is currently only a grey-scale palette with increasing luminance, but later patches can change this. For PCs, a VGA default palette could be used. Signed-off-by: Thomas Zimmermann <tzimmerm...@suse.de> --- drivers/gpu/drm/drm_color_mgmt.c | 206 +++++++++++++++++++++++++++++++ include/drm/drm_color_mgmt.h | 27 ++++ 2 files changed, 233 insertions(+) diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index 3969dc548cff..dd3e06605180 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -630,3 +630,209 @@ int drm_color_lut_check(const struct drm_property_blob *lut, u32 tests) return 0; } EXPORT_SYMBOL(drm_color_lut_check); + +/* + * Gamma-LUT programming + */ + +/** + * drm_crtc_load_gamma_888 - Programs gamma ramp for RGB888-like formats + * @crtc: The displaying CRTC + * @lut: The gamma ramp to program + * @set_gamma: Callback for programming the hardware gamma LUT + * + * Programs the gamma ramp specified in @lut to hardware. The input gamma + * ramp must have 256 entries per color component. + */ +void drm_crtc_load_gamma_888(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_gamma) +{ + unsigned int i; + + for (i = 0; i < 256; ++i) + set_gamma(crtc, i, lut[i].red, lut[i].green, lut[i].blue); +} +EXPORT_SYMBOL(drm_crtc_load_gamma_888); + +/** + * drm_crtc_load_gamma_565_from_888 - Programs gamma ramp for RGB565-like formats + * @crtc: The displaying CRTC + * @lut: The gamma ramp to program + * @set_gamma: Callback for programming the hardware gamma LUT + * + * Programs the gamma ramp specified in @lut to hardware. The input gamma + * ramp must have 256 entries per color component. The helper interpolates + * the individual color components to reduce the number of entries to 5/6/5. + */ +void drm_crtc_load_gamma_565_from_888(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_gamma) +{ + unsigned int i; + u16 r, g, b; + + for (i = 0; i < 32; ++i) { + r = lut[i * 8 + i / 4].red; + g = lut[i * 4 + i / 16].green; + b = lut[i * 8 + i / 4].blue; + set_gamma(crtc, i, r, g, b); + } + /* Green has one more bit, so add padding with 0 for red and blue. */ + for (i = 32; i < 64; ++i) { + g = lut[i * 4 + i / 16].green; + set_gamma(crtc, i, 0, g, 0); + } +} +EXPORT_SYMBOL(drm_crtc_load_gamma_565_from_888); + +/** + * drm_crtc_load_gamma_555_from_888 - Programs gamma ramp for RGB555-like formats + * @crtc: The displaying CRTC + * @lut: The gamma ramp to program + * @set_gamma: Callback for programming the hardware gamma LUT + * + * Programs the gamma ramp specified in @lut to hardware. The input gamma + * ramp must have 256 entries per color component. The helper interpolates + * the individual color components to reduce the number of entries to 5/5/5. + */ +void drm_crtc_load_gamma_555_from_888(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_gamma) +{ + unsigned int i; + u16 r, g, b; + + for (i = 0; i < 32; ++i) { + r = lut[i * 8 + i / 4].red; + g = lut[i * 8 + i / 4].green; + b = lut[i * 8 + i / 4].blue; + set_gamma(crtc, i, r, g, b); + } +} +EXPORT_SYMBOL(drm_crtc_load_gamma_555_from_888); + +static void fill_gamma_888(struct drm_crtc *crtc, unsigned int i, u16 r, u16 g, u16 b, + drm_crtc_set_lut_func set_gamma) +{ + r = (r << 8) | r; + g = (g << 8) | g; + b = (b << 8) | b; + + set_gamma(crtc, i, r, g, b); +} + +/** + * drm_crtc_fill_gamma_888 - Programs a default gamma ramp for RGB888-like formats + * @crtc: The displaying CRTC + * @set_gamma: Callback for programming the hardware gamma LUT + * + * Programs a default gamma ramp to hardware. + */ +void drm_crtc_fill_gamma_888(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma) +{ + unsigned int i; + + for (i = 0; i < 256; ++i) + fill_gamma_888(crtc, i, i, i, i, set_gamma); +} +EXPORT_SYMBOL(drm_crtc_fill_gamma_888); + +static void fill_gamma_565(struct drm_crtc *crtc, unsigned int i, u16 r, u16 g, u16 b, + drm_crtc_set_lut_func set_gamma) +{ + r = (r << 11) | (r << 6) | (r << 1) | (r >> 4); + g = (g << 10) | (g << 4) | (g >> 2); + b = (b << 11) | (b << 6) | (b << 1) | (b >> 4); + + set_gamma(crtc, i, r, g, b); +} + +/** + * drm_crtc_fill_gamma_565 - Programs a default gamma ramp for RGB565-like formats + * @crtc: The displaying CRTC + * @set_gamma: Callback for programming the hardware gamma LUT + * + * Programs a default gamma ramp to hardware. + */ +void drm_crtc_fill_gamma_565(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma) +{ + unsigned int i; + + for (i = 0; i < 32; ++i) + fill_gamma_565(crtc, i, i, i, i, set_gamma); + /* Green has one more bit, so add padding with 0 for red and blue. */ + for (i = 32; i < 64; ++i) + fill_gamma_565(crtc, i, 0, i, 0, set_gamma); +} +EXPORT_SYMBOL(drm_crtc_fill_gamma_565); + +static void fill_gamma_555(struct drm_crtc *crtc, unsigned int i, u16 r, u16 g, u16 b, + drm_crtc_set_lut_func set_gamma) +{ + r = (r << 11) | (r << 6) | (r << 1) | (r >> 4); + g = (g << 11) | (g << 6) | (g << 1) | (g >> 4); + b = (b << 11) | (b << 6) | (b << 1) | (r >> 4); + + set_gamma(crtc, i, r, g, b); +} + +/** + * drm_crtc_fill_gamma_555 - Programs a default gamma ramp for RGB555-like formats + * @crtc: The displaying CRTC + * @set_gamma: Callback for programming the hardware gamma LUT + * + * Programs a default gamma ramp to hardware. + */ +void drm_crtc_fill_gamma_555(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma) +{ + unsigned int i; + + for (i = 0; i < 32; ++i) + fill_gamma_555(crtc, i, i, i, i, set_gamma); +} +EXPORT_SYMBOL(drm_crtc_fill_gamma_555); + +/* + * Color-LUT programming + */ + +/** + * drm_crtc_load_palette_8 - Programs palette for C8-like formats + * @crtc: The displaying CRTC + * @lut: The palette to program + * @set_palette: Callback for programming the hardware palette + * + * Programs the palette specified in @lut to hardware. The input palette + * must have 256 entries per color component. + */ +void drm_crtc_load_palette_8(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_palette) +{ + unsigned int i; + + for (i = 0; i < 256; ++i) + set_palette(crtc, i, lut[i].red, lut[i].green, lut[i].blue); +} +EXPORT_SYMBOL(drm_crtc_load_palette_8); + +static void fill_palette_8(struct drm_crtc *crtc, unsigned int i, + drm_crtc_set_lut_func set_palette) +{ + u16 Y = (i << 8) | i; // relative luminance + + set_palette(crtc, i, Y, Y, Y); +} + +/** + * drm_crtc_fill_palette_8 - Programs a default palette for C8-like formats + * @crtc: The displaying CRTC + * @set_palette: Callback for programming the hardware gamma LUT + * + * Programs a default palette to hardware. + */ +void drm_crtc_fill_palette_8(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette) +{ + unsigned int i; + + for (i = 0; i < 256; ++i) + fill_palette_8(crtc, i, set_palette); +} +EXPORT_SYMBOL(drm_crtc_fill_palette_8); diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h index ed81741036d7..6cb577f6dba6 100644 --- a/include/drm/drm_color_mgmt.h +++ b/include/drm/drm_color_mgmt.h @@ -118,4 +118,31 @@ enum drm_color_lut_tests { }; int drm_color_lut_check(const struct drm_property_blob *lut, u32 tests); + +/* + * Gamma-LUT programming + */ + +typedef void (*drm_crtc_set_lut_func)(struct drm_crtc *, unsigned int, u16, u16, u16); + +void drm_crtc_load_gamma_888(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_gamma); +void drm_crtc_load_gamma_565_from_888(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_gamma); +void drm_crtc_load_gamma_555_from_888(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_gamma); + +void drm_crtc_fill_gamma_888(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma); +void drm_crtc_fill_gamma_565(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma); +void drm_crtc_fill_gamma_555(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma); + +/* + * Color-LUT programming + */ + +void drm_crtc_load_palette_8(struct drm_crtc *crtc, const struct drm_color_lut *lut, + drm_crtc_set_lut_func set_palette); + +void drm_crtc_fill_palette_8(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette); + #endif -- 2.49.0