Commit 1d1547ec authored by Russell King's avatar Russell King

drm/armada: fix plane location and size for interlace

When the CRTC is programmed for interlace, we have to halve the Y
parameters for the plane.  Rather than doing this in the update
function (which would need the calculation repeated for the old
state as well as the new state), arrange to do the calculation in
atomic_check and save it in our private plane state structure.
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
parent 9184ae8d
......@@ -316,19 +316,4 @@ enum {
PWRDN_IRQ_LEVEL = 1 << 0,
};
static inline u32 armada_rect_hw_fp(struct drm_rect *r)
{
return (drm_rect_height(r) & 0xffff0000) | drm_rect_width(r) >> 16;
}
static inline u32 armada_rect_hw(struct drm_rect *r)
{
return drm_rect_height(r) << 16 | (drm_rect_width(r) & 0x0000ffff);
}
static inline u32 armada_rect_yx(struct drm_rect *r)
{
return (r)->y1 << 16 | ((r)->x1 & 0x0000ffff);
}
#endif
......@@ -27,7 +27,7 @@
#define DEFAULT_ENCODING DRM_COLOR_YCBCR_BT601
struct armada_overlay_state {
struct drm_plane_state base;
struct armada_plane_state base;
u32 colorkey_yr;
u32 colorkey_ug;
u32 colorkey_vb;
......@@ -38,7 +38,7 @@ struct armada_overlay_state {
u16 saturation;
};
#define drm_to_overlay_state(s) \
container_of(s, struct armada_overlay_state, base)
container_of(s, struct armada_overlay_state, base.base)
static inline u32 armada_spu_contrast(struct drm_plane_state *state)
{
......@@ -320,9 +320,9 @@ static void armada_overlay_reset(struct drm_plane *plane)
state->brightness = DEFAULT_BRIGHTNESS;
state->contrast = DEFAULT_CONTRAST;
state->saturation = DEFAULT_SATURATION;
__drm_atomic_helper_plane_reset(plane, &state->base);
state->base.color_encoding = DEFAULT_ENCODING;
state->base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
__drm_atomic_helper_plane_reset(plane, &state->base.base);
state->base.base.color_encoding = DEFAULT_ENCODING;
state->base.base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
}
}
......@@ -336,8 +336,9 @@ armada_overlay_duplicate_state(struct drm_plane *plane)
state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
if (state)
__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
return &state->base;
__drm_atomic_helper_plane_duplicate_state(plane,
&state->base.base);
return &state->base.base;
}
static int armada_overlay_set_property(struct drm_plane *plane,
......
......@@ -126,20 +126,47 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
int armada_drm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
{
if (state->fb && !WARN_ON(!state->crtc)) {
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state;
if (state->state)
crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
else
crtc_state = crtc->state;
return drm_atomic_helper_check_plane_state(state, crtc_state,
0, INT_MAX,
true, false);
} else {
struct armada_plane_state *st = to_armada_plane_state(state);
struct drm_crtc *crtc = state->crtc;
struct drm_crtc_state *crtc_state;
bool interlace;
int ret;
if (!state->fb || WARN_ON(!state->crtc)) {
state->visible = false;
return 0;
}
if (state->state)
crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
else
crtc_state = crtc->state;
ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
INT_MAX, true, false);
if (ret)
return ret;
interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
if (interlace) {
if ((state->dst.y1 | state->dst.y2) & 1)
return -EINVAL;
st->src_hw = drm_rect_height(&state->src) >> 17;
st->dst_yx = state->dst.y1 >> 1;
st->dst_hw = drm_rect_height(&state->dst) >> 1;
} else {
st->src_hw = drm_rect_height(&state->src) >> 16;
st->dst_yx = state->dst.y1;
st->dst_hw = drm_rect_height(&state->dst);
}
st->src_hw <<= 16;
st->src_hw |= drm_rect_width(&state->src) >> 16;
st->dst_yx <<= 16;
st->dst_yx |= state->dst.x1 & 0x0000ffff;
st->dst_hw <<= 16;
st->dst_hw |= drm_rect_width(&state->dst) & 0x0000ffff;
return 0;
}
......@@ -262,12 +289,37 @@ static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
.atomic_disable = armada_drm_primary_plane_atomic_disable,
};
void armada_plane_reset(struct drm_plane *plane)
{
struct armada_plane_state *st;
if (plane->state)
__drm_atomic_helper_plane_destroy_state(plane->state);
kfree(plane->state);
st = kzalloc(sizeof(*st), GFP_KERNEL);
if (st)
__drm_atomic_helper_plane_reset(plane, &st->base);
}
struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
{
struct armada_plane_state *st;
if (WARN_ON(!plane->state))
return NULL;
st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
if (st)
__drm_atomic_helper_plane_duplicate_state(plane, &st->base);
return &st->base;
}
static const struct drm_plane_funcs armada_primary_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = drm_primary_helper_destroy,
.reset = drm_atomic_helper_plane_reset,
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.reset = armada_plane_reset,
.atomic_duplicate_state = armada_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
......
#ifndef ARMADA_PLANE_H
#define ARMADA_PLANE_H
#define armada_src_hw(state) armada_rect_hw_fp(&(state)->src)
#define armada_dst_yx(state) armada_rect_yx(&(state)->dst)
#define armada_dst_hw(state) armada_rect_hw(&(state)->dst)
struct armada_plane_state {
struct drm_plane_state base;
u32 src_hw;
u32 dst_yx;
u32 dst_hw;
};
#define to_armada_plane_state(st) \
container_of(st, struct armada_plane_state, base)
#define armada_src_hw(state) to_armada_plane_state(state)->src_hw
#define armada_dst_yx(state) to_armada_plane_state(state)->dst_yx
#define armada_dst_hw(state) to_armada_plane_state(state)->dst_hw
void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
u16 pitches[3], bool interlaced);
......@@ -13,6 +22,11 @@ void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state);
int armada_drm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state);
void armada_plane_reset(struct drm_plane *plane);
struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane);
void armada_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state);
int armada_drm_primary_plane_init(struct drm_device *drm,
struct drm_plane *primary);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment