@@ -280,6 +280,21 @@ struct komeda_timing_ctrlr_state {
struct komeda_component_state base;
};
+/* Why define A separated structure but not use plane_state directly ?
+ * 1. Komeda supports layer_split which means a plane_state can be split and
+ * handled by two layers, one layer only handle half of plane image.
+ * 2. Fix up the user properties according to HW's capabilities, like user
+ * set rotation to R180, but HW only supports REFLECT_X+Y. the rot here is
+ * after drm_rotation_simplify()
+ */
+struct komeda_layer_viewport {
+ u16 in_x, in_y, in_w, in_h;
+ u32 out_x, out_y, out_w, out_h;
+ u32 rot;
+ int blending_zorder;
+ u8 pixel_blend_mode, layer_alpha;
+};
+
/** struct komeda_pipeline_funcs */
struct komeda_pipeline_funcs {
/* dump_register: Optional, dump registers to seq_file */
@@ -391,4 +406,13 @@ komeda_component_add(struct komeda_pipeline *pipe,
void komeda_component_destroy(struct komeda_dev *mdev,
struct komeda_component *c);
+struct komeda_plane_state;
+struct komeda_crtc_state;
+
+int komeda_build_layer_data_flow(struct komeda_layer *layer,
+ struct komeda_component_output *dflow,
+ struct komeda_plane_state *kplane_st,
+ struct komeda_crtc_state *kcrtc_st,
+ struct komeda_layer_viewport *vp);
+
#endif /* _KOMEDA_PIPELINE_H_*/
@@ -8,6 +8,7 @@
#include "komeda_dev.h"
#include "komeda_kms.h"
#include "komeda_pipeline.h"
+#include "komeda_framebuffer.h"
static inline bool is_switching_user(void *old, void *new)
{
@@ -89,6 +90,18 @@ komeda_component_get_state(struct komeda_component *c,
&c->obj));
}
+static struct komeda_component_state *
+komeda_component_get_old_state(struct komeda_component *c,
+ struct drm_atomic_state *state)
+{
+ struct drm_private_state *priv_st;
+
+ priv_st = drm_atomic_get_old_private_obj_state(state, &c->obj);
+ if (priv_st)
+ return priv_to_comp_st(priv_st);
+ return NULL;
+}
+
/**
* komeda_component_get_state_and_set_user()
*
@@ -146,3 +159,250 @@ komeda_component_get_state_and_set_user(struct komeda_component *c,
return st;
}
+
+static void
+komeda_component_add_input(struct komeda_component_state *state,
+ struct komeda_component_output *input,
+ int idx)
+{
+ struct komeda_component *c = state->component;
+
+ WARN_ON((idx < 0 || idx >= c->max_active_inputs));
+
+ /* since the inputs[i] is only valid when it is active. So if a input[i]
+ * is a newly enabled input which switches from disable to enable, then
+ * the old inputs[i] is undefined (NOT zeroed), we can not rely on
+ * memcmp, but directly mark it changed
+ */
+ if (!has_bit(idx, state->affected_inputs) ||
+ memcmp(&state->inputs[idx], input, sizeof(*input))) {
+ memcpy(&state->inputs[idx], input, sizeof(*input));
+ state->changed_active_inputs |= BIT(idx);
+ }
+ state->active_inputs |= BIT(idx);
+ state->affected_inputs |= BIT(idx);
+}
+
+static int
+komeda_component_check_input(struct komeda_component_state *state,
+ struct komeda_component_output *input,
+ int idx)
+{
+ struct komeda_component *c = state->component;
+
+ if ((idx < 0) || (idx >= c->max_active_inputs)) {
+ DRM_DEBUG_ATOMIC("%s invalid input id: %d.\n", c->name, idx);
+ return -EINVAL;
+ }
+
+ if (has_bit(idx, state->active_inputs)) {
+ DRM_DEBUG_ATOMIC("%s required input_id: %d has been occupied already.\n",
+ c->name, idx);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+komeda_component_set_output(struct komeda_component_output *output,
+ struct komeda_component *comp,
+ u8 output_port)
+{
+ output->component = comp;
+ output->output_port = output_port;
+}
+
+#define component_validate_private(x, st) \
+({ \
+ struct komeda_component *c = &((x)->base); \
+ int err = 0; \
+ \
+ if (c->funcs->validate) \
+ err = c->funcs->validate(c, &((st)->base)); \
+ err; \
+})
+
+static int
+komeda_layer_check_cfg(struct komeda_layer *layer,
+ struct komeda_plane_state *kplane_st,
+ struct komeda_layer_viewport *view)
+{
+ if (!in_range(&layer->hsize_in, view->in_w)) {
+ DRM_DEBUG_ATOMIC("src_w: %d is out of range.\n", view->in_w);
+ return -EINVAL;
+ }
+
+ if (!in_range(&layer->vsize_in, view->in_h)) {
+ DRM_DEBUG_ATOMIC("src_h: %d is out of range.\n", view->in_h);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int komeda_layer_validate(struct komeda_layer *layer,
+ struct komeda_component_output *input,
+ struct komeda_plane_state *kplane_st,
+ struct komeda_layer_viewport *view)
+{
+ struct drm_plane_state *plane_st = &kplane_st->base;
+ struct drm_framebuffer *fb = plane_st->fb;
+ struct komeda_fb *kfb = to_kfb(fb);
+ struct komeda_component_state *c_st;
+ struct komeda_layer_state *st;
+ int i, err;
+
+ err = komeda_layer_check_cfg(layer, kplane_st, view);
+ if (err)
+ return err;
+
+ c_st = komeda_component_get_state_and_set_user(&layer->base,
+ plane_st->state, plane_st->plane, plane_st->crtc);
+ if (IS_ERR(c_st))
+ return PTR_ERR(c_st);
+
+ st = to_layer_st(c_st);
+
+ st->rot = view->rot;
+ st->hsize = kfb->aligned_w;
+ st->vsize = kfb->aligned_h;
+
+ for (i = 0; i < fb->format->num_planes; i++)
+ st->addr[i] = komeda_fb_get_pixel_addr(kfb, view->in_x,
+ view->in_y, i);
+
+ err = component_validate_private(layer, st);
+ if (err)
+ return err;
+
+ komeda_component_set_output(input, &layer->base, 0);
+
+ return 0;
+}
+
+static void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
+ u16 *hsize, u16 *vsize)
+{
+ struct drm_display_mode *m = &kcrtc_st->base.adjusted_mode;
+
+ if (hsize)
+ *hsize = m->hdisplay;
+ if (vsize)
+ *vsize = m->vdisplay;
+}
+
+int komeda_compiz_set_input(struct komeda_compiz *compiz,
+ struct komeda_component_output *input,
+ struct komeda_crtc_state *kcrtc_st,
+ struct komeda_layer_viewport *vp)
+{
+ struct drm_atomic_state *drm_st = kcrtc_st->base.state;
+ struct komeda_component_state *c_st, *old_st;
+ struct komeda_compiz_input_cfg *cin;
+ u16 compiz_w, compiz_h;
+ int idx = vp->blending_zorder;
+
+ pipeline_composition_size(kcrtc_st, &compiz_w, &compiz_h);
+ /* check display rect */
+ if ((vp->out_x + vp->out_w > compiz_w) ||
+ (vp->out_y + vp->out_h > compiz_h) ||
+ vp->out_w == 0 || vp->out_h == 0) {
+ DRM_DEBUG_ATOMIC("invalid disp rect [x=%d, y=%d, w=%d, h=%d]\n",
+ vp->out_x, vp->out_y, vp->out_w, vp->out_h);
+ return -EINVAL;
+ }
+
+ c_st = komeda_component_get_state_and_set_user(&compiz->base, drm_st,
+ kcrtc_st->base.crtc, kcrtc_st->base.crtc);
+ if (IS_ERR(c_st))
+ return PTR_ERR(c_st);
+
+ if (komeda_component_check_input(c_st, input, idx))
+ return -EINVAL;
+
+ cin = &(to_compiz_st(c_st)->cins[idx]);
+
+ cin->hsize = vp->out_w;
+ cin->vsize = vp->out_h;
+ cin->hoffset = vp->out_x;
+ cin->voffset = vp->out_y;
+ cin->pixel_blend_mode = vp->pixel_blend_mode;
+ cin->layer_alpha = vp->layer_alpha;
+
+ old_st = komeda_component_get_old_state(&compiz->base, drm_st);
+ WARN_ON(!old_st);
+
+ /* compare with old to check if this input has been changed */
+ if (memcmp(&(to_compiz_st(old_st)->cins[idx]), cin, sizeof(*cin)))
+ c_st->changed_active_inputs |= BIT(idx);
+
+ komeda_component_add_input(c_st, input, idx);
+
+ return 0;
+}
+
+int komeda_compiz_validate(struct komeda_compiz *compiz,
+ struct komeda_component_output *input,
+ struct komeda_crtc_state *state,
+ struct komeda_layer_viewport *vp)
+{
+ struct komeda_component_state *c_st;
+ struct komeda_compiz_state *st;
+
+ c_st = komeda_component_get_state_and_set_user(&compiz->base,
+ state->base.state, state->base.crtc, state->base.crtc);
+ if (IS_ERR(c_st))
+ return PTR_ERR(c_st);
+
+ st = to_compiz_st(c_st);
+
+ pipeline_composition_size(state, &st->hsize, &st->vsize);
+
+ komeda_component_set_output(input, &compiz->base, 0);
+
+ /* compiz output dflow will be fed to the next pipeline stage, prepare
+ * the viewport configuration for the next stage
+ */
+ if (vp) {
+ vp->in_w = st->hsize;
+ vp->in_h = st->vsize;
+ vp->out_w = vp->in_w;
+ vp->out_h = vp->in_h;
+ /* the output data of compiz doesn't have alpha, it only can be
+ * used as bottom layer when blend it with master layers
+ */
+ vp->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE;
+ vp->layer_alpha = 0xFF;
+ vp->blending_zorder = 0;
+ }
+
+ return 0;
+}
+
+int komeda_build_layer_data_flow(struct komeda_layer *layer,
+ struct komeda_component_output *dflow,
+ struct komeda_plane_state *kplane_st,
+ struct komeda_crtc_state *kcrtc_st,
+ struct komeda_layer_viewport *vp)
+{
+ struct drm_plane *plane = kplane_st->base.plane;
+ struct komeda_pipeline *pipe = layer->base.pipeline;
+ int err;
+
+ DRM_DEBUG_ATOMIC("%s handling [PLANE:%d:%s]: "
+ "src[x/y:%d/%d, w/h:%d/%d] disp[x/y:%d/%d, w/h:%d/%d]",
+ layer->base.name, plane->base.id, plane->name,
+ vp->in_x, vp->in_y, vp->in_w, vp->in_h,
+ vp->out_x, vp->out_y, vp->out_w, vp->out_h);
+
+ memset(dflow, 0, sizeof(*dflow));
+
+ err = komeda_layer_validate(layer, dflow, kplane_st, vp);
+ if (err)
+ return err;
+
+ err = komeda_compiz_set_input(pipe->compiz, dflow, kcrtc_st, vp);
+
+ return err;
+}
build_layer_data_flow builds a input pipeline according to plane_state. and in this initial stage only added this simplest pipeline usage: Layer -> compiz The scaler and layer_split will be added in the future. Signed-off-by: James (Qian) Wang <james.qian.wang@arm.com> --- .../drm/arm/display/komeda/komeda_pipeline.h | 24 ++ .../display/komeda/komeda_pipeline_state.c | 260 ++++++++++++++++++ 2 files changed, 284 insertions(+)