drm/komeda: Add komeda_pipeline/component_get_state_and_set_user
authorjames qian wang (Arm Technology China) <james.qian.wang@arm.com>
Tue, 22 Jan 2019 11:05:51 +0000 (11:05 +0000)
committerLiviu Dudau <Liviu.Dudau@arm.com>
Mon, 29 Apr 2019 11:35:56 +0000 (12:35 +0100)
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.

v2:
- Rebase.
- Applied commit:
  b962a12050a3 ("drm/atomic: integrate modeset lock with private objects")
  And delete our private modeset lock for pipeline.

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
drivers/gpu/drm/arm/display/komeda/Makefile
drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c [new file with mode: 0644]

index d593125236ae74b4f132b200ab23ad0a5f0bbcd8..62bd1bff66a36c47ad619f1932601ff7d55b4eba 100644 (file)
@@ -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_state.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
new file mode 100644 (file)
index 0000000..dd020b0
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <james.qian.wang@arm.com>
+ *
+ */
+
+#include <drm/drm_print.h>
+#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;
+
+       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 pipeline for 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)
+{
+       struct drm_private_state *priv_st;
+
+       WARN_ON(!drm_modeset_is_locked(&c->pipeline->obj.lock));
+
+       priv_st = drm_atomic_get_private_obj_state(state, &c->obj);
+       if (IS_ERR(priv_st))
+               return ERR_CAST(priv_st);
+
+       return priv_to_comp_st(priv_st);
+}
+
+/**
+ * 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.
+ */
+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;
+}