* [PATCH 1/5] drm: Add drm_atomic_get_old/new_private_obj_state
2018-12-24 9:15 [PATCH 0/5] Implement komeda DRM-Plane james qian wang (Arm Technology China)
@ 2018-12-24 9:15 ` james qian wang (Arm Technology China)
2018-12-24 9:15 ` [PATCH 2/5] drm/komeda: Add komeda_pipeline/component_get_state_and_set_user james qian wang (Arm Technology China)
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: james qian wang (Arm Technology China) @ 2018-12-24 9:15 UTC (permalink / raw)
To: Liviu Dudau
Cc: Jonathan Chai (Arm Technology China),
Brian Starkey, Julien Yin (Arm Technology China),
thomas Sun (Arm Technology China),
Alexandru-Cosmin Gheorghe, Lowry Li (Arm Technology China),
Ayan Halder, Tiannan Zhu (Arm Technology China),
Jin Gao (Arm Technology China), Yiqi Kang (Arm Technology China),
nd, malidp, airlied, yamada.masahiro, linux-kernel, dri-devel,
maarten.lankhorst, maxime.ripard, sean,
james qian wang (Arm Technology China)
This pair of functions return the old/new private object state for the
given private_obj, or NULL if the private_obj is not part of the global
atomic state.
Reviewed-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
Signed-off-by: James (Qian) Wang <james.qian.wang@arm.com>
---
drivers/gpu/drm/drm_atomic.c | 45 +++++++++++++++++++++++++++++++++++-
include/drm/drm_atomic.h | 6 +++++
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 9ac26437051b..6ff29f3862fc 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -764,6 +764,50 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
}
EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
+/**
+ * drm_atomic_get_old_private_obj_state
+ * @state: global atomic state object
+ * @obj: private_obj to grab
+ *
+ * This function returns the old private object state for the given private_obj,
+ * or NULL if the private_obj is not part of the global atomic state.
+ */
+struct drm_private_state *
+drm_atomic_get_old_private_obj_state(struct drm_atomic_state *state,
+ struct drm_private_obj *obj)
+{
+ int i;
+
+ for (i = 0; i < state->num_private_objs; i++)
+ if (obj == state->private_objs[i].ptr)
+ return state->private_objs[i].old_state;
+
+ return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_private_obj_state);
+
+/**
+ * drm_atomic_get_new_private_obj_state
+ * @state: global atomic state object
+ * @obj: private_obj to grab
+ *
+ * This function returns the new private object state for the given private_obj,
+ * or NULL if the private_obj is not part of the global atomic state.
+ */
+struct drm_private_state *
+drm_atomic_get_new_private_obj_state(struct drm_atomic_state *state,
+ struct drm_private_obj *obj)
+{
+ int i;
+
+ for (i = 0; i < state->num_private_objs; i++)
+ if (obj == state->private_objs[i].ptr)
+ return state->private_objs[i].new_state;
+
+ return NULL;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_private_obj_state);
+
/**
* drm_atomic_get_connector_state - get connector state
* @state: global atomic state object
@@ -1203,4 +1247,3 @@ int drm_atomic_debugfs_init(struct drm_minor *minor)
minor->debugfs_root, minor);
}
#endif
-
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index f9b35834c45d..beb7b7fb6067 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -408,6 +408,12 @@ void drm_atomic_private_obj_fini(struct drm_private_obj *obj);
struct drm_private_state * __must_check
drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
struct drm_private_obj *obj);
+struct drm_private_state *
+drm_atomic_get_old_private_obj_state(struct drm_atomic_state *state,
+ struct drm_private_obj *obj);
+struct drm_private_state *
+drm_atomic_get_new_private_obj_state(struct drm_atomic_state *state,
+ struct drm_private_obj *obj);
/**
* drm_atomic_get_existing_crtc_state - get crtc state, if it exists
--
2.17.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 2/5] drm/komeda: Add komeda_pipeline/component_get_state_and_set_user
2018-12-24 9:15 [PATCH 0/5] Implement komeda DRM-Plane james qian wang (Arm Technology China)
2018-12-24 9:15 ` [PATCH 1/5] drm: Add drm_atomic_get_old/new_private_obj_state james qian wang (Arm Technology China)
@ 2018-12-24 9:15 ` james qian wang (Arm Technology China)
2018-12-24 9:16 ` [PATCH 3/5] drm/arm/komeda: Initialize komeda component as drm private object james qian wang (Arm Technology China)
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: james qian wang (Arm Technology China) @ 2018-12-24 9:15 UTC (permalink / raw)
To: Liviu Dudau
Cc: Jonathan Chai (Arm Technology China),
Brian Starkey, Julien Yin (Arm Technology China),
thomas Sun (Arm Technology China),
Alexandru-Cosmin Gheorghe, Lowry Li (Arm Technology China),
Ayan Halder, Tiannan Zhu (Arm Technology China),
Jin Gao (Arm Technology China), Yiqi Kang (Arm Technology China),
nd, malidp, airlied, yamada.masahiro, linux-kernel, dri-devel,
maarten.lankhorst, maxime.ripard, sean,
james qian wang (Arm Technology China)
get_state_and_set_user packed get_state and set_user into one function,
which get pipeline/component state for a specific pipeline/component, if
success set the user to it.
Signed-off-by: James (Qian) Wang <james.qian.wang@arm.com>
---
drivers/gpu/drm/arm/display/komeda/Makefile | 1 +
.../drm/arm/display/komeda/komeda_pipeline.c | 2 +
.../drm/arm/display/komeda/komeda_pipeline.h | 7 +
.../display/komeda/komeda_pipeline_state.c | 148 ++++++++++++++++++
4 files changed, 158 insertions(+)
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
index d593125236ae..62bd1bff66a3 100644
--- a/drivers/gpu/drm/arm/display/komeda/Makefile
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -9,6 +9,7 @@ komeda-y := \
komeda_dev.o \
komeda_format_caps.o \
komeda_pipeline.o \
+ komeda_pipeline_state.o \
komeda_framebuffer.o \
komeda_kms.o \
komeda_crtc.o \
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index 611e8c53e248..1c9205d0e61b 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -34,6 +34,8 @@ komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
pipe->id = mdev->n_pipelines;
pipe->funcs = funcs;
+ drm_modeset_lock_init(&pipe->mutex);
+
mdev->pipelines[mdev->n_pipelines] = pipe;
mdev->n_pipelines++;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 4f98fdb21557..201fcf074fa1 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -295,6 +295,13 @@ struct komeda_pipeline_funcs {
struct komeda_pipeline {
/** @obj: link pipeline as private obj of drm_atomic_state */
struct drm_private_obj obj;
+
+ /**
+ * @mutex:
+ *
+ * protects pipeline_state, since pipeline can be shared between crtcs
+ */
+ struct drm_modeset_lock mutex;
/** @mdev: the parent komeda_dev */
struct komeda_dev *mdev;
/** @pxlclk: pixel clock */
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
new file mode 100644
index 000000000000..7ce006b9e5f7
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+#include <linux/clk.h>
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+#include "komeda_pipeline.h"
+
+static inline bool is_switching_user(void *old, void *new)
+{
+ if (!old || !new)
+ return false;
+
+ return old != new;
+}
+
+struct komeda_pipeline_state *
+komeda_pipeline_get_state(struct komeda_pipeline *pipe,
+ struct drm_atomic_state *state)
+{
+ struct drm_private_state *priv_st;
+ int err;
+
+ WARN_ON(!state->acquire_ctx);
+
+ priv_st = drm_atomic_get_new_private_obj_state(state, &pipe->obj);
+ if (priv_st)
+ return priv_to_pipe_st(priv_st);
+
+ err = drm_modeset_lock(&pipe->mutex, state->acquire_ctx);
+ if (err)
+ return ERR_PTR(err);
+
+ priv_st = drm_atomic_get_private_obj_state(state, &pipe->obj);
+ if (IS_ERR(priv_st))
+ return ERR_CAST(priv_st);
+
+ return priv_to_pipe_st(priv_st);
+}
+
+/* Assign a pipeline crtc */
+struct komeda_pipeline_state *
+komeda_pipeline_get_state_and_set_crtc(struct komeda_pipeline *pipe,
+ struct drm_atomic_state *state,
+ struct drm_crtc *crtc)
+{
+ struct komeda_pipeline_state *st;
+
+ st = komeda_pipeline_get_state(pipe, state);
+ if (IS_ERR(st))
+ return st;
+
+ if (is_switching_user(crtc, st->crtc)) {
+ DRM_DEBUG_ATOMIC("CRTC%d required pipeline%d is busy.\n",
+ drm_crtc_index(crtc), pipe->id);
+ return ERR_PTR(-EBUSY);
+ }
+
+ /* pipeline only can be disabled when the it is free or unused */
+ if (!crtc && st->active_comps) {
+ DRM_DEBUG_ATOMIC("Disabling a busy pipeline:%d.\n", pipe->id);
+ return ERR_PTR(-EBUSY);
+ }
+
+ st->crtc = crtc;
+
+ if (crtc) {
+ struct komeda_crtc_state *kcrtc_st;
+
+ kcrtc_st = to_kcrtc_st(drm_atomic_get_new_crtc_state(state,
+ crtc));
+
+ kcrtc_st->active_pipes |= BIT(pipe->id);
+ kcrtc_st->affected_pipes |= BIT(pipe->id);
+ }
+ return st;
+}
+
+static struct komeda_component_state *
+komeda_component_get_state(struct komeda_component *c,
+ struct drm_atomic_state *state)
+{
+ WARN_ON(!drm_modeset_is_locked(&c->pipeline->mutex));
+
+ return priv_to_comp_st(drm_atomic_get_private_obj_state(state,
+ &c->obj));
+}
+
+/**
+ * komeda_component_get_state_and_set_user()
+ *
+ * @c: component to get state and set user
+ * @state: global atomic state
+ * @user: direct user, the binding user
+ * @crtc: the CRTC user, the big boss :)
+ *
+ * This function accepts two users:
+ * - The direct user: can be plane/crtc/wb_connector depends on component
+ * - The big boss (CRTC)
+ * CRTC is the big boss (the final user), because all component resources
+ * eventually will be assigned to CRTC, like the layer will be binding to
+ * kms_plane, but kms plane will be binding to a CRTC eventually.
+ *
+ * The big boss (CRTC) is for pipeline assignment, since &komeda_component isn't
+ * independent and can be assigned to CRTC freely, but belongs to a specific
+ * pipeline, only pipeline can be shared between crtc, and pipeline as a whole
+ * (include all the internal components) assigned to a specific CRTC.
+ *
+ * So when set a user to komeda_component, need first to check the status of
+ * component->pipeline to see if the pipeline is available on this specific
+ * CRTC. if the pipeline is busy (assigned to another CRTC), even the required
+ * component is free, the component still cannot be assigned to the direct user.
+ */
+static struct komeda_component_state *
+komeda_component_get_state_and_set_user(struct komeda_component *c,
+ struct drm_atomic_state *state,
+ void *user,
+ struct drm_crtc *crtc)
+{
+ struct komeda_pipeline_state *pipe_st;
+ struct komeda_component_state *st;
+
+ /* First check if the pipeline is available */
+ pipe_st = komeda_pipeline_get_state_and_set_crtc(c->pipeline,
+ state, crtc);
+ if (IS_ERR(pipe_st))
+ return ERR_CAST(pipe_st);
+
+ st = komeda_component_get_state(c, state);
+ if (IS_ERR(st))
+ return st;
+
+ /* check if the component has been occupied */
+ if (is_switching_user(user, st->binding_user)) {
+ DRM_DEBUG_ATOMIC("required %s is busy.\n", c->name);
+ return ERR_PTR(-EBUSY);
+ }
+
+ st->binding_user = user;
+ /* mark the component as active if user is valid */
+ if (st->binding_user)
+ pipe_st->active_comps |= BIT(c->id);
+
+ return st;
+}
--
2.17.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 3/5] drm/arm/komeda: Initialize komeda component as drm private object
2018-12-24 9:15 [PATCH 0/5] Implement komeda DRM-Plane james qian wang (Arm Technology China)
2018-12-24 9:15 ` [PATCH 1/5] drm: Add drm_atomic_get_old/new_private_obj_state james qian wang (Arm Technology China)
2018-12-24 9:15 ` [PATCH 2/5] drm/komeda: Add komeda_pipeline/component_get_state_and_set_user james qian wang (Arm Technology China)
@ 2018-12-24 9:16 ` james qian wang (Arm Technology China)
2018-12-24 9:16 ` [PATCH 4/5] drm/komeda: Add komeda_build_layer_data_flow james qian wang (Arm Technology China)
2018-12-24 9:16 ` [PATCH 5/5] drm/komeda: Add komeda_plane/plane_helper_funcs james qian wang (Arm Technology China)
4 siblings, 0 replies; 6+ messages in thread
From: james qian wang (Arm Technology China) @ 2018-12-24 9:16 UTC (permalink / raw)
To: Liviu Dudau
Cc: Jonathan Chai (Arm Technology China),
Brian Starkey, Julien Yin (Arm Technology China),
thomas Sun (Arm Technology China),
Alexandru-Cosmin Gheorghe, Lowry Li (Arm Technology China),
Ayan Halder, Tiannan Zhu (Arm Technology China),
Jin Gao (Arm Technology China), Yiqi Kang (Arm Technology China),
nd, malidp, airlied, yamada.masahiro, linux-kernel, dri-devel,
maarten.lankhorst, maxime.ripard, sean,
james qian wang (Arm Technology China)
Initialize koemda_layer, komeda_compiz, komeda_improc and
komeda_timing_ctrlr as drm private object, then track komeda private
component state by drm_atomic_state.
Signed-off-by: James (Qian) Wang <james.qian.wang@arm.com>
---
.../arm/display/komeda/komeda_private_obj.c | 200 +++++++++++++++++-
1 file changed, 198 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
index 9edfd6ab0c12..c5b42fc4f904 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -7,6 +7,184 @@
#include "komeda_dev.h"
#include "komeda_kms.h"
+static void
+komeda_component_state_reset(struct komeda_component_state *st)
+{
+ st->binding_user = NULL;
+ st->affected_inputs = st->active_inputs;
+ st->active_inputs = 0;
+ st->changed_active_inputs = 0;
+}
+
+static struct drm_private_state *
+komeda_layer_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+ struct komeda_layer_state *st;
+
+ st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return NULL;
+
+ komeda_component_state_reset(&st->base);
+ __drm_atomic_helper_private_obj_duplicate_state(obj, &st->base.obj);
+
+ return &st->base.obj;
+}
+
+static void
+komeda_layer_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ struct komeda_layer_state *st = to_layer_st(priv_to_comp_st(state));
+
+ kfree(st);
+}
+
+static const struct drm_private_state_funcs komeda_layer_obj_funcs = {
+ .atomic_duplicate_state = komeda_layer_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_layer_atomic_destroy_state,
+};
+
+static int komeda_layer_obj_add(struct komeda_layer *layer)
+{
+ struct komeda_layer_state *st;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->base.component = &layer->base;
+ drm_atomic_private_obj_init(&layer->base.obj, &st->base.obj,
+ &komeda_layer_obj_funcs);
+ return 0;
+}
+
+static struct drm_private_state *
+komeda_compiz_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+ struct komeda_compiz_state *st;
+
+ st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return NULL;
+
+ komeda_component_state_reset(&st->base);
+ __drm_atomic_helper_private_obj_duplicate_state(obj, &st->base.obj);
+
+ return &st->base.obj;
+}
+
+static void
+komeda_compiz_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ kfree(to_compiz_st(priv_to_comp_st(state)));
+}
+
+static const struct drm_private_state_funcs komeda_compiz_obj_funcs = {
+ .atomic_duplicate_state = komeda_compiz_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_compiz_atomic_destroy_state,
+};
+
+static int komeda_compiz_obj_add(struct komeda_compiz *compiz)
+{
+ struct komeda_compiz_state *st;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->base.component = &compiz->base;
+ drm_atomic_private_obj_init(&compiz->base.obj, &st->base.obj,
+ &komeda_compiz_obj_funcs);
+
+ return 0;
+}
+
+static struct drm_private_state *
+komeda_improc_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+ struct komeda_improc_state *st;
+
+ st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return NULL;
+
+ komeda_component_state_reset(&st->base);
+ __drm_atomic_helper_private_obj_duplicate_state(obj, &st->base.obj);
+
+ return &st->base.obj;
+}
+
+static void
+komeda_improc_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ kfree(to_improc_st(priv_to_comp_st(state)));
+}
+
+static const struct drm_private_state_funcs komeda_improc_obj_funcs = {
+ .atomic_duplicate_state = komeda_improc_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_improc_atomic_destroy_state,
+};
+
+static int komeda_improc_obj_add(struct komeda_improc *improc)
+{
+ struct komeda_improc_state *st;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->base.component = &improc->base;
+ drm_atomic_private_obj_init(&improc->base.obj, &st->base.obj,
+ &komeda_improc_obj_funcs);
+
+ return 0;
+}
+
+static struct drm_private_state *
+komeda_timing_ctrlr_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+ struct komeda_timing_ctrlr_state *st;
+
+ st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return NULL;
+
+ komeda_component_state_reset(&st->base);
+ __drm_atomic_helper_private_obj_duplicate_state(obj, &st->base.obj);
+
+ return &st->base.obj;
+}
+
+static void
+komeda_timing_ctrlr_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ kfree(to_ctrlr_st(priv_to_comp_st(state)));
+}
+
+static const struct drm_private_state_funcs komeda_timing_ctrlr_obj_funcs = {
+ .atomic_duplicate_state = komeda_timing_ctrlr_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_timing_ctrlr_atomic_destroy_state,
+};
+
+static int komeda_timing_ctrlr_obj_add(struct komeda_timing_ctrlr *ctrlr)
+{
+ struct komeda_compiz_state *st;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->base.component = &ctrlr->base;
+ drm_atomic_private_obj_init(&ctrlr->base.obj, &st->base.obj,
+ &komeda_timing_ctrlr_obj_funcs);
+
+ return 0;
+}
+
static struct drm_private_state *
komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
{
@@ -55,7 +233,7 @@ int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
struct komeda_dev *mdev)
{
struct komeda_pipeline *pipe;
- int i, err;
+ int i, j, err;
for (i = 0; i < mdev->n_pipelines; i++) {
pipe = mdev->pipelines[i];
@@ -64,7 +242,23 @@ int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
if (err)
return err;
- /* Add component */
+ for (j = 0; j < pipe->n_layers; j++) {
+ err = komeda_layer_obj_add(pipe->layers[j]);
+ if (err)
+ return err;
+ }
+
+ err = komeda_compiz_obj_add(pipe->compiz);
+ if (err)
+ return err;
+
+ err = komeda_improc_obj_add(pipe->improc);
+ if (err)
+ return err;
+
+ err = komeda_timing_ctrlr_obj_add(pipe->ctrlr);
+ if (err)
+ return err;
}
return 0;
@@ -78,11 +272,13 @@ void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
for (i = 0; i < mdev->n_pipelines; i++) {
pipe = mdev->pipelines[i];
+
dp_for_each_set_bit(id, pipe->avail_comps) {
c = komeda_pipeline_get_component(pipe, id);
drm_atomic_private_obj_fini(&c->obj);
}
+
drm_atomic_private_obj_fini(&pipe->obj);
}
}
--
2.17.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 4/5] drm/komeda: Add komeda_build_layer_data_flow
2018-12-24 9:15 [PATCH 0/5] Implement komeda DRM-Plane james qian wang (Arm Technology China)
` (2 preceding siblings ...)
2018-12-24 9:16 ` [PATCH 3/5] drm/arm/komeda: Initialize komeda component as drm private object james qian wang (Arm Technology China)
@ 2018-12-24 9:16 ` james qian wang (Arm Technology China)
2018-12-24 9:16 ` [PATCH 5/5] drm/komeda: Add komeda_plane/plane_helper_funcs james qian wang (Arm Technology China)
4 siblings, 0 replies; 6+ messages in thread
From: james qian wang (Arm Technology China) @ 2018-12-24 9:16 UTC (permalink / raw)
To: Liviu Dudau
Cc: Jonathan Chai (Arm Technology China),
Brian Starkey, Julien Yin (Arm Technology China),
thomas Sun (Arm Technology China),
Alexandru-Cosmin Gheorghe, Lowry Li (Arm Technology China),
Ayan Halder, Tiannan Zhu (Arm Technology China),
Jin Gao (Arm Technology China), Yiqi Kang (Arm Technology China),
nd, malidp, airlied, yamada.masahiro, linux-kernel, dri-devel,
maarten.lankhorst, maxime.ripard, sean,
james qian wang (Arm Technology China)
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(+)
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 201fcf074fa1..c78edfc6ed5b 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -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_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
index 7ce006b9e5f7..b98163211cfd 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -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;
+}
--
2.17.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 5/5] drm/komeda: Add komeda_plane/plane_helper_funcs
2018-12-24 9:15 [PATCH 0/5] Implement komeda DRM-Plane james qian wang (Arm Technology China)
` (3 preceding siblings ...)
2018-12-24 9:16 ` [PATCH 4/5] drm/komeda: Add komeda_build_layer_data_flow james qian wang (Arm Technology China)
@ 2018-12-24 9:16 ` james qian wang (Arm Technology China)
4 siblings, 0 replies; 6+ messages in thread
From: james qian wang (Arm Technology China) @ 2018-12-24 9:16 UTC (permalink / raw)
To: Liviu Dudau
Cc: Jonathan Chai (Arm Technology China),
Brian Starkey, Julien Yin (Arm Technology China),
thomas Sun (Arm Technology China),
Alexandru-Cosmin Gheorghe, Lowry Li (Arm Technology China),
Ayan Halder, Tiannan Zhu (Arm Technology China),
Jin Gao (Arm Technology China), Yiqi Kang (Arm Technology China),
nd, malidp, airlied, yamada.masahiro, linux-kernel, dri-devel,
maarten.lankhorst, maxime.ripard, sean,
james qian wang (Arm Technology China)
Per komeda design KMS-plane maps to komeda layer input pipeline.
komeda_plane_atomic_check is for building a komeda layer input pipeline.
And KMS-plane is only a user of komeda resources. so there is no real HW
update for plane, but all HW update will be handled in crtc->flush.
Signed-off-by: James (Qian) Wang <james.qian.wang@arm.com>
---
.../gpu/drm/arm/display/komeda/komeda_plane.c | 129 ++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
index 0a4953a9a909..522bdddd0600 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -10,7 +10,83 @@
#include "komeda_dev.h"
#include "komeda_kms.h"
+int komeda_prepare_viewport(struct drm_plane_state *st,
+ struct komeda_layer_viewport *view)
+{
+ struct drm_framebuffer *fb = st->fb;
+
+ memset(view, 0, sizeof(*view));
+
+ view->blending_zorder = st->zpos;
+
+ /* if format doesn't have alpha, fix blend mode to PIXEL_NONE */
+ view->pixel_blend_mode = fb->format->has_alpha ?
+ st->pixel_blend_mode : DRM_MODE_BLEND_PIXEL_NONE;
+ view->layer_alpha = st->alpha >> 8;
+
+ view->out_x = st->crtc_x;
+ view->out_y = st->crtc_y;
+ view->out_w = st->crtc_w;
+ view->out_h = st->crtc_h;
+
+ view->in_x = st->src_x >> 16;
+ view->in_y = st->src_y >> 16;
+ view->in_w = st->src_w >> 16;
+ view->in_h = st->src_h >> 16;
+
+ return 0;
+}
+
+int komeda_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct komeda_plane *kplane = to_kplane(plane);
+ struct komeda_plane_state *kplane_st = to_kplane_st(state);
+ struct komeda_layer *layer = kplane->layer;
+ struct drm_crtc_state *crtc_st;
+ struct komeda_crtc *kcrtc;
+ struct komeda_crtc_state *kcrtc_st;
+ struct komeda_layer_viewport view;
+ struct komeda_component_output dflow;
+ int err;
+
+ if (!state->crtc || !state->fb)
+ return 0;
+
+ crtc_st = drm_atomic_get_crtc_state(state->state, state->crtc);
+ if (!crtc_st->enable) {
+ DRM_DEBUG_ATOMIC("Cannot update plane on a disabled CRTC.\n");
+ return -EINVAL;
+ }
+
+ /* crtc is inactive, skip the resource assignment */
+ if (!crtc_st->active)
+ return 0;
+
+ kcrtc = to_kcrtc(state->crtc);
+ kcrtc_st = to_kcrtc_st(crtc_st);
+
+ err = komeda_prepare_viewport(state, &view);
+ if (err)
+ return err;
+
+ err = komeda_build_layer_data_flow(layer, &dflow,
+ kplane_st, kcrtc_st, &view);
+
+ return err;
+}
+
+/* plane doesn't represent a real HW, so there is no HW update for plane.
+ * komeda handles all the HW update in crtc->atomic_flush
+ */
+void komeda_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+}
+
static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
+ .atomic_check = komeda_plane_atomic_check,
+ .atomic_update = komeda_plane_atomic_update,
};
static void komeda_plane_destroy(struct drm_plane *plane)
@@ -20,7 +96,60 @@ static void komeda_plane_destroy(struct drm_plane *plane)
kfree(to_kplane(plane));
}
+static void komeda_plane_reset(struct drm_plane *plane)
+{
+ struct komeda_plane_state *state;
+ struct komeda_plane *kplane = to_kplane(plane);
+
+ if (plane->state)
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+
+ kfree(plane->state);
+ plane->state = NULL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state) {
+ state->base.rotation = DRM_MODE_ROTATE_0;
+ state->base.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
+ state->base.alpha = DRM_BLEND_ALPHA_OPAQUE;
+ state->base.zpos = kplane->layer->base.id;
+ plane->state = &state->base;
+ plane->state->plane = plane;
+ }
+}
+
+static struct drm_plane_state *
+komeda_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+ struct komeda_plane_state *new;
+
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return NULL;
+
+ __drm_atomic_helper_plane_duplicate_state(plane, &new->base);
+
+ return &new->base;
+}
+
+static void
+komeda_plane_atomic_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(to_kplane_st(state));
+}
+
static const struct drm_plane_funcs komeda_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = komeda_plane_destroy,
+ .reset = komeda_plane_reset,
+ .atomic_duplicate_state = komeda_plane_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_plane_atomic_destroy_state,
};
/* for komeda, which is pipeline can be share between crtcs */
--
2.17.1
^ permalink raw reply [flat|nested] 6+ messages in thread