linux/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c

// SPDX-License-Identifier: GPL-2.0
/*
 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
 * Author: James.Qian.Wang <[email protected]>
 *
 */

#include <drm/drm_print.h>
#include <linux/clk.h>
#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)
{}

static struct komeda_pipeline_state *
komeda_pipeline_get_state(struct komeda_pipeline *pipe,
			  struct drm_atomic_state *state)
{}

struct komeda_pipeline_state *
komeda_pipeline_get_old_state(struct komeda_pipeline *pipe,
			      struct drm_atomic_state *state)
{}

static struct komeda_pipeline_state *
komeda_pipeline_get_new_state(struct komeda_pipeline *pipe,
			      struct drm_atomic_state *state)
{}

/* Assign pipeline for crtc */
static struct komeda_pipeline_state *
komeda_pipeline_get_state_and_set_crtc(struct komeda_pipeline *pipe,
				       struct drm_atomic_state *state,
				       struct drm_crtc *crtc)
{}

static struct komeda_component_state *
komeda_component_get_state(struct komeda_component *c,
			   struct drm_atomic_state *state)
{}

static struct komeda_component_state *
komeda_component_get_old_state(struct komeda_component *c,
			       struct drm_atomic_state *state)
{}

/**
 * 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)
{}

static void
komeda_component_add_input(struct komeda_component_state *state,
			   struct komeda_component_output *input,
			   int idx)
{}

static int
komeda_component_check_input(struct komeda_component_state *state,
			     struct komeda_component_output *input,
			     int idx)
{}

static void
komeda_component_set_output(struct komeda_component_output *output,
			    struct komeda_component *comp,
			    u8 output_port)
{}

static int
komeda_component_validate_private(struct komeda_component *c,
				  struct komeda_component_state *st)
{}

/* Get current available scaler from the component->supported_outputs */
static struct komeda_scaler *
komeda_component_get_avail_scaler(struct komeda_component *c,
				  struct drm_atomic_state *state)
{}

static void
komeda_rotate_data_flow(struct komeda_data_flow_cfg *dflow, u32 rot)
{}

static int
komeda_layer_check_cfg(struct komeda_layer *layer,
		       struct komeda_fb *kfb,
		       struct komeda_data_flow_cfg *dflow)
{}

static int
komeda_layer_validate(struct komeda_layer *layer,
		      struct komeda_plane_state *kplane_st,
		      struct komeda_data_flow_cfg *dflow)
{}

static int
komeda_wb_layer_validate(struct komeda_layer *wb_layer,
			 struct drm_connector_state *conn_st,
			 struct komeda_data_flow_cfg *dflow)
{}

static bool scaling_ratio_valid(u32 size_in, u32 size_out,
				u32 max_upscaling, u32 max_downscaling)
{}

static int
komeda_scaler_check_cfg(struct komeda_scaler *scaler,
			struct komeda_crtc_state *kcrtc_st,
			struct komeda_data_flow_cfg *dflow)
{}

static int
komeda_scaler_validate(void *user,
		       struct komeda_crtc_state *kcrtc_st,
		       struct komeda_data_flow_cfg *dflow)
{}

static void komeda_split_data_flow(struct komeda_scaler *scaler,
				   struct komeda_data_flow_cfg *dflow,
				   struct komeda_data_flow_cfg *l_dflow,
				   struct komeda_data_flow_cfg *r_dflow);

static int
komeda_splitter_validate(struct komeda_splitter *splitter,
			 struct drm_connector_state *conn_st,
			 struct komeda_data_flow_cfg *dflow,
			 struct komeda_data_flow_cfg *l_output,
			 struct komeda_data_flow_cfg *r_output)
{}

static int
komeda_merger_validate(struct komeda_merger *merger,
		       void *user,
		       struct komeda_crtc_state *kcrtc_st,
		       struct komeda_data_flow_cfg *left_input,
		       struct komeda_data_flow_cfg *right_input,
		       struct komeda_data_flow_cfg *output)
{}

void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
			       u16 *hsize, u16 *vsize)
{}

static int
komeda_compiz_set_input(struct komeda_compiz *compiz,
			struct komeda_crtc_state *kcrtc_st,
			struct komeda_data_flow_cfg *dflow)
{}

static int
komeda_compiz_validate(struct komeda_compiz *compiz,
		       struct komeda_crtc_state *state,
		       struct komeda_data_flow_cfg *dflow)
{}

static int
komeda_improc_validate(struct komeda_improc *improc,
		       struct komeda_crtc_state *kcrtc_st,
		       struct komeda_data_flow_cfg *dflow)
{}

static int
komeda_timing_ctrlr_validate(struct komeda_timing_ctrlr *ctrlr,
			     struct komeda_crtc_state *kcrtc_st,
			     struct komeda_data_flow_cfg *dflow)
{}

void komeda_complete_data_flow_cfg(struct komeda_layer *layer,
				   struct komeda_data_flow_cfg *dflow,
				   struct drm_framebuffer *fb)
{}

static bool merger_is_available(struct komeda_pipeline *pipe,
				struct komeda_data_flow_cfg *dflow)
{}

int komeda_build_layer_data_flow(struct komeda_layer *layer,
				 struct komeda_plane_state *kplane_st,
				 struct komeda_crtc_state *kcrtc_st,
				 struct komeda_data_flow_cfg *dflow)
{}

/*
 * Split is introduced for workaround scaler's input/output size limitation.
 * The idea is simple, if one scaler can not fit the requirement, use two.
 * So split splits the big source image to two half parts (left/right) and do
 * the scaling by two scaler separately and independently.
 * But split also imports an edge problem in the middle of the image when
 * scaling, to avoid it, split isn't a simple half-and-half, but add an extra
 * pixels (overlap) to both side, after split the left/right will be:
 * - left: [0, src_length/2 + overlap]
 * - right: [src_length/2 - overlap, src_length]
 * The extra overlap do eliminate the edge problem, but which may also generates
 * unnecessary pixels when scaling, we need to crop them before scaler output
 * the result to the next stage. and for the how to crop, it depends on the
 * unneeded pixels, another words the position where overlay has been added.
 * - left: crop the right
 * - right: crop the left
 *
 * The diagram for how to do the split
 *
 *  <---------------------left->out_w ---------------->
 * |--------------------------------|---right_crop-----| <- left after split
 *  \                                \                /
 *   \                                \<--overlap--->/
 *   |-----------------|-------------|(Middle)------|-----------------| <- src
 *                     /<---overlap--->\                               \
 *                    /                 \                               \
 * right after split->|-----left_crop---|--------------------------------|
 *                    ^<------------------- right->out_w --------------->^
 *
 * NOTE: To consistent with HW the output_w always contains the crop size.
 */

static void komeda_split_data_flow(struct komeda_scaler *scaler,
				   struct komeda_data_flow_cfg *dflow,
				   struct komeda_data_flow_cfg *l_dflow,
				   struct komeda_data_flow_cfg *r_dflow)
{}

/* For layer split, a plane state will be split to two data flows and handled
 * by two separated komeda layer input pipelines. komeda supports two types of
 * layer split:
 * - none-scaling split:
 *             / layer-left -> \
 * plane_state                  compiz-> ...
 *             \ layer-right-> /
 *
 * - scaling split:
 *             / layer-left -> scaler->\
 * plane_state                          merger -> compiz-> ...
 *             \ layer-right-> scaler->/
 *
 * Since merger only supports scaler as input, so for none-scaling split, two
 * layer data flows will be output to compiz directly. for scaling_split, two
 * data flow will be merged by merger firstly, then merger outputs one merged
 * data flow to compiz.
 */
int komeda_build_layer_split_data_flow(struct komeda_layer *left,
				       struct komeda_plane_state *kplane_st,
				       struct komeda_crtc_state *kcrtc_st,
				       struct komeda_data_flow_cfg *dflow)
{}

/* writeback data path: compiz -> scaler -> wb_layer -> memory */
int komeda_build_wb_data_flow(struct komeda_layer *wb_layer,
			      struct drm_connector_state *conn_st,
			      struct komeda_crtc_state *kcrtc_st,
			      struct komeda_data_flow_cfg *dflow)
{}

/* writeback scaling split data path:
 *                   /-> scaler ->\
 * compiz -> splitter              merger -> wb_layer -> memory
 *                   \-> scaler ->/
 */
int komeda_build_wb_split_data_flow(struct komeda_layer *wb_layer,
				    struct drm_connector_state *conn_st,
				    struct komeda_crtc_state *kcrtc_st,
				    struct komeda_data_flow_cfg *dflow)
{}

/* build display output data flow, the data path is:
 * compiz -> improc -> timing_ctrlr
 */
int komeda_build_display_data_flow(struct komeda_crtc *kcrtc,
				   struct komeda_crtc_state *kcrtc_st)
{}

static int
komeda_pipeline_unbound_components(struct komeda_pipeline *pipe,
				   struct komeda_pipeline_state *new)
{}

/* release unclaimed pipeline resource */
int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe,
				       struct komeda_crtc_state *kcrtc_st)
{}

/* Since standalone disabled components must be disabled separately and in the
 * last, So a complete disable operation may needs to call pipeline_disable
 * twice (two phase disabling).
 * Phase 1: disable the common components, flush it.
 * Phase 2: disable the standalone disabled components, flush it.
 *
 * RETURNS:
 * true: disable is not complete, needs a phase 2 disable.
 * false: disable is complete.
 */
bool komeda_pipeline_disable(struct komeda_pipeline *pipe,
			     struct drm_atomic_state *old_state)
{}

void komeda_pipeline_update(struct komeda_pipeline *pipe,
			    struct drm_atomic_state *old_state)
{}