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.w...@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.w...@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

Reply via email to