diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 3a153648b369..22c64a4366c6 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -98,6 +98,20 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, drm_crtc_send_vblank_event(crtc, event); spin_unlock_irq(&crtc->dev->event_lock); } + + if (crtc->state->color_mgmt_changed) { + if (crtc->state->gamma_lut) { + /* LUT can be only updated when gamma correction is + * disabled + */ + sun4i_tcon_enable_gamma(scrtc->tcon, false); + sun4i_tcon_load_gamma_lut(scrtc->tcon, + crtc->state->gamma_lut->data); + sun4i_tcon_enable_gamma(scrtc->tcon, true); + } else + sun4i_tcon_enable_gamma(scrtc->tcon, false); + } + } static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc, @@ -181,6 +195,7 @@ static const struct drm_crtc_funcs sun4i_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .enable_vblank = sun4i_crtc_enable_vblank, .disable_vblank = sun4i_crtc_disable_vblank, + .gamma_set = drm_atomic_helper_legacy_gamma_set, }; struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index c81cdce6ed55..25ff0106f4f5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -214,6 +214,34 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable) } EXPORT_SYMBOL(sun4i_tcon_enable_vblank); +void sun4i_tcon_load_gamma_lut(struct sun4i_tcon *tcon, + struct drm_color_lut *lut) +{ + int i; + + for (i = 0; i < SUN4I_TCON_GAMMA_LUT_SIZE; i++) { + u32 r, g, b; + + r = drm_color_lut_extract(lut[i].red, 8); + g = drm_color_lut_extract(lut[i].green, 8); + b = drm_color_lut_extract(lut[i].blue, 8); + + regmap_write(tcon->regs, SUN4I_TCON_GAMMA_TABLE_REG + 4 * i, + SUN4I_TCON_GAMMA_TABLE_R(r) | + SUN4I_TCON_GAMMA_TABLE_G(g) | + SUN4I_TCON_GAMMA_TABLE_B(b)); + } +} +EXPORT_SYMBOL(sun4i_tcon_load_gamma_lut); + +void sun4i_tcon_enable_gamma(struct sun4i_tcon *tcon, bool enable) +{ + regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG, + SUN4I_TCON_GCTL_GAMMA_ENABLE, + enable ? SUN4I_TCON_GCTL_GAMMA_ENABLE : 0); +} +EXPORT_SYMBOL(sun4i_tcon_enable_gamma); + /* * This function is a helper for TCON output muxing. The TCON output * muxing control register in earlier SoCs (without the TCON TOP block) @@ -1261,6 +1289,11 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, list_add_tail(&tcon->list, &drv->tcon_list); + drm_mode_crtc_set_gamma_size(&tcon->crtc->crtc, + SUN4I_TCON_GAMMA_LUT_SIZE); + drm_crtc_enable_color_mgmt(&tcon->crtc->crtc, 0, false, + tcon->crtc->crtc.gamma_size); + return 0; err_free_dotclock: diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index a62ec826ae71..a1f4cd6b5711 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -18,6 +18,7 @@ #define SUN4I_TCON_GCTL_REG 0x0 #define SUN4I_TCON_GCTL_TCON_ENABLE BIT(31) +#define SUN4I_TCON_GCTL_GAMMA_ENABLE BIT(30) #define SUN4I_TCON_GCTL_IOMAP_MASK BIT(0) #define SUN4I_TCON_GCTL_IOMAP_TCON1 (1 << 0) #define SUN4I_TCON_GCTL_IOMAP_TCON0 (0 << 0) @@ -211,7 +212,13 @@ #define SUN4I_TCON1_FILL_BEG2_REG 0x31c #define SUN4I_TCON1_FILL_END2_REG 0x320 #define SUN4I_TCON1_FILL_DATA2_REG 0x324 -#define SUN4I_TCON1_GAMMA_TABLE_REG 0x400 + +#define SUN4I_TCON_GAMMA_TABLE_REG 0x400 +#define SUN4I_TCON_GAMMA_TABLE_B(x) ((x) & 0xff) +#define SUN4I_TCON_GAMMA_TABLE_G(x) (((x) & 0xff) << 8) +#define SUN4I_TCON_GAMMA_TABLE_R(x) (((x) & 0xff) << 16) + +#define SUN4I_TCON_GAMMA_LUT_SIZE 256 #define SUN4I_TCON_MAX_CHANNELS 2 @@ -275,6 +282,9 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, const struct drm_display_mode *mode); void sun4i_tcon_set_status(struct sun4i_tcon *crtc, const struct drm_encoder *encoder, bool enable); +void sun4i_tcon_load_gamma_lut(struct sun4i_tcon *tcon, + struct drm_color_lut *lut); +void sun4i_tcon_enable_gamma(struct sun4i_tcon *tcon, bool enable); extern const struct of_device_id sun4i_tcon_of_table[];