drm/armada: move CBSH properties into overlay plane state

Move the contrast, brightness, and saturation properties to the overlay
plane state structure, and call our overlay commit function to update
the hardware via the planes atomic_update() method.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
This commit is contained in:
Russell King 2018-07-30 11:52:34 +01:00
parent 63b93c0834
commit 61ba252705
2 changed files with 136 additions and 29 deletions

View file

@ -42,7 +42,7 @@ struct armada_plane_work {
struct drm_plane *plane;
struct drm_framebuffer *old_fb;
struct drm_pending_vblank_event *event;
struct armada_regs regs[14];
struct armada_regs regs[24];
};
struct armada_plane {

View file

@ -20,6 +20,10 @@
#include "armada_plane.h"
#include "armada_trace.h"
#define DEFAULT_BRIGHTNESS 0
#define DEFAULT_CONTRAST 0x4000
#define DEFAULT_SATURATION 0x4000
struct armada_ovl_plane_properties {
uint32_t colorkey_yr;
uint32_t colorkey_ug;
@ -27,9 +31,6 @@ struct armada_ovl_plane_properties {
#define K2R(val) (((val) >> 0) & 0xff)
#define K2G(val) (((val) >> 8) & 0xff)
#define K2B(val) (((val) >> 16) & 0xff)
int16_t brightness;
uint16_t contrast;
uint16_t saturation;
uint32_t colorkey_mode;
uint32_t colorkey_enable;
};
@ -44,6 +45,26 @@ struct armada_ovl_plane {
#define drm_to_armada_ovl_plane(p) \
container_of(p, struct armada_ovl_plane, base.base)
struct armada_overlay_state {
struct drm_plane_state base;
s16 brightness;
u16 contrast;
u16 saturation;
};
#define drm_to_overlay_state(s) \
container_of(s, struct armada_overlay_state, base)
static inline u32 armada_spu_contrast(struct drm_plane_state *state)
{
return drm_to_overlay_state(state)->brightness << 16 |
drm_to_overlay_state(state)->contrast;
}
static inline u32 armada_spu_saturation(struct drm_plane_state *state)
{
/* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */
return drm_to_overlay_state(state)->saturation << 16;
}
static void
armada_ovl_update_attr(struct armada_ovl_plane_properties *prop,
@ -53,13 +74,6 @@ armada_ovl_update_attr(struct armada_ovl_plane_properties *prop,
writel_relaxed(prop->colorkey_ug, dcrtc->base + LCD_SPU_COLORKEY_U);
writel_relaxed(prop->colorkey_vb, dcrtc->base + LCD_SPU_COLORKEY_V);
writel_relaxed(prop->brightness << 16 | prop->contrast,
dcrtc->base + LCD_SPU_CONTRAST);
/* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */
writel_relaxed(prop->saturation << 16,
dcrtc->base + LCD_SPU_SATURATION);
writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE);
spin_lock_irq(&dcrtc->irq_lock);
armada_updatel(prop->colorkey_mode,
CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK,
@ -191,6 +205,17 @@ static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
LCD_SPU_DMA_CTRL0);
val = armada_spu_contrast(state);
if ((!old_state->visible && state->visible) ||
armada_spu_contrast(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_CONTRAST);
val = armada_spu_saturation(state);
if ((!old_state->visible && state->visible) ||
armada_spu_saturation(old_state) != val)
armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION);
if (!old_state->visible && state->visible)
armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE);
dcrtc->regs_idx += idx;
}
@ -264,6 +289,10 @@ static int armada_overlay_commit(struct drm_plane *plane,
/* Point of no return */
swap(plane->state, state);
/* No CRTC, can't update */
if (!plane->state->crtc)
goto put_state;
dcrtc->regs_idx = 0;
dcrtc->regs = work->regs;
@ -300,7 +329,7 @@ static int armada_overlay_commit(struct drm_plane *plane,
dplane->next_work = !dplane->next_work;
put_state:
drm_atomic_helper_plane_destroy_state(plane, state);
plane->funcs->atomic_destroy_state(plane, state);
return ret;
}
@ -318,7 +347,7 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
src_x, src_y, src_w, src_h);
/* Construct new state for the overlay plane */
state = drm_atomic_helper_plane_duplicate_state(plane);
state = plane->funcs->atomic_duplicate_state(plane);
if (!state)
return -ENOMEM;
@ -404,15 +433,22 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane,
dplane->prop.colorkey_enable = ADV_GRACOLORKEY;
}
update_attr = true;
} else if (property == priv->brightness_prop) {
dplane->prop.brightness = val - 256;
update_attr = true;
} else if (property == priv->contrast_prop) {
dplane->prop.contrast = val;
update_attr = true;
} else if (property == priv->saturation_prop) {
dplane->prop.saturation = val;
update_attr = true;
} else {
struct drm_plane_state *state;
int ret;
state = plane->funcs->atomic_duplicate_state(plane);
if (!state)
return -ENOMEM;
ret = plane->funcs->atomic_set_property(plane, state, property,
val);
if (ret) {
plane->funcs->atomic_destroy_state(plane, state);
return ret;
}
return armada_overlay_commit(plane, state);
}
if (update_attr && dplane->base.base.crtc)
@ -422,12 +458,85 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane,
return 0;
}
static void armada_overlay_reset(struct drm_plane *plane)
{
struct armada_overlay_state *state;
if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
kfree(plane->state);
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state) {
state->base.plane = plane;
state->base.rotation = DRM_MODE_ROTATE_0;
state->brightness = DEFAULT_BRIGHTNESS;
state->contrast = DEFAULT_CONTRAST;
state->saturation = DEFAULT_SATURATION;
}
plane->state = &state->base;
}
struct drm_plane_state *
armada_overlay_duplicate_state(struct drm_plane *plane)
{
struct armada_overlay_state *state;
if (WARN_ON(!plane->state))
return NULL;
state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
if (state)
__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
return &state->base;
}
static int armada_overlay_set_property(struct drm_plane *plane,
struct drm_plane_state *state, struct drm_property *property,
uint64_t val)
{
struct armada_private *priv = plane->dev->dev_private;
if (property == priv->brightness_prop) {
drm_to_overlay_state(state)->brightness = val - 256;
} else if (property == priv->contrast_prop) {
drm_to_overlay_state(state)->contrast = val;
} else if (property == priv->saturation_prop) {
drm_to_overlay_state(state)->saturation = val;
} else {
return -EINVAL;
}
return 0;
}
static int armada_overlay_get_property(struct drm_plane *plane,
const struct drm_plane_state *state, struct drm_property *property,
uint64_t *val)
{
struct armada_private *priv = plane->dev->dev_private;
if (property == priv->brightness_prop) {
*val = drm_to_overlay_state(state)->brightness + 256;
} else if (property == priv->contrast_prop) {
*val = drm_to_overlay_state(state)->contrast;
} else if (property == priv->saturation_prop) {
*val = drm_to_overlay_state(state)->saturation;
} else {
return -EINVAL;
}
return 0;
}
static const struct drm_plane_funcs armada_ovl_plane_funcs = {
.update_plane = armada_ovl_plane_update,
.disable_plane = drm_plane_helper_disable,
.destroy = armada_ovl_plane_destroy,
.set_property = armada_ovl_plane_set_property,
.reset = drm_atomic_helper_plane_reset,
.reset = armada_overlay_reset,
.atomic_duplicate_state = armada_overlay_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
.atomic_set_property = armada_overlay_set_property,
.atomic_get_property = armada_overlay_get_property,
};
static const uint32_t armada_ovl_formats[] = {
@ -542,9 +651,6 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) |
CFG_ALPHAM_GRA | CFG_ALPHA(0);
dplane->prop.colorkey_enable = ADV_GRACOLORKEY;
dplane->prop.brightness = 0;
dplane->prop.contrast = 0x4000;
dplane->prop.saturation = 0x4000;
mobj = &dplane->base.base.base;
drm_object_attach_property(mobj, priv->colorkey_prop,
@ -559,11 +665,12 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
0x000000);
drm_object_attach_property(mobj, priv->colorkey_mode_prop,
CKMODE_RGB);
drm_object_attach_property(mobj, priv->brightness_prop, 256);
drm_object_attach_property(mobj, priv->brightness_prop,
256 + DEFAULT_BRIGHTNESS);
drm_object_attach_property(mobj, priv->contrast_prop,
dplane->prop.contrast);
DEFAULT_CONTRAST);
drm_object_attach_property(mobj, priv->saturation_prop,
dplane->prop.saturation);
DEFAULT_SATURATION);
return 0;
}