diff mbox series

[2/2] drm/komeda: add Crossbar support

Message ID 20191211102948.27117-3-tiannan.zhu@arm.com (mailing list archive)
State New, archived
Headers show
Series Add most basic function to support D77 | expand

Commit Message

Tiannan Zhu (Arm Technology China) Dec. 11, 2019, 10:30 a.m. UTC
Active D77's Crossbar

Crossbar(CBU) is a new component added in D77, which is used for zorder
control.
At a time (per display frame) up to 5 inputs of the CBU can be enabled

Signed-off-by: Tiannan Zhu (Arm Technology China) <tiannan.zhu@arm.com>
---
 .../arm/display/komeda/d71/d71_component.c    | 61 +++++++++++++++++++
 .../drm/arm/display/komeda/komeda_pipeline.c  | 10 +++
 .../drm/arm/display/komeda/komeda_pipeline.h  |  7 +++
 .../display/komeda/komeda_pipeline_state.c    | 36 +++++++++++
 .../arm/display/komeda/komeda_private_obj.c   | 49 +++++++++++++++
 5 files changed, 163 insertions(+)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
index ec96b69a5ade..3f2fee43867e 100644
--- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
@@ -44,6 +44,9 @@  static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id)
 	case D71_BLK_TYPE_DOU:
 		id = KOMEDA_COMPONENT_TIMING_CTRLR;
 		break;
+	case D77_BLK_TYPE_CBU:
+		id += KOMEDA_COMPONENT_CROSSBAR0;
+		break;
 	default:
 		id = 0xFFFFFFFF;
 	}
@@ -969,6 +972,63 @@  static int d71_splitter_init(struct d71_dev *d71,
 	return 0;
 }
 
+static void d77_crossbar_update(struct komeda_component *c,
+				struct komeda_component_state *state)
+{
+	u32 __iomem *reg;
+	u32 index, input_hw_id;
+
+	for_each_changed_input(state, index) {
+		reg = c->reg + index;
+		input_hw_id = to_d71_input_id(state, index);
+		if (state->active_inputs & BIT(index)) {
+			malidp_write32(reg, BLK_INPUT_ID0, input_hw_id);
+			malidp_write32(reg, BLK_CONTROL, CBU_INPUT_CTRL_EN);
+		} else {
+			malidp_write32(reg, BLK_INPUT_ID0, 0);
+			malidp_write32(reg, BLK_CONTROL, 0);
+		}
+	}
+}
+
+static void d77_crossbar_disable(struct komeda_component *c)
+{
+	u32 __iomem *reg = c->reg;
+	u32 i;
+
+	for (i = 0; i < c->max_active_inputs; i++) {
+		malidp_write32(reg, BLK_CONTROL + (i << 2), 0);
+		malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
+	}
+}
+
+static struct komeda_component_funcs d77_crossbar_funcs = {
+	.update		= d77_crossbar_update,
+	.disable	= d77_crossbar_disable,
+};
+
+static int d77_crossbar_init(struct d71_dev *d71,
+			     struct block_header *blk, u32 __iomem *reg)
+{
+	struct komeda_component *c;
+	u32 pipe_id, comp_id;
+
+	get_resources_id(blk->block_info, &pipe_id, &comp_id);
+	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*c),
+				 comp_id,
+				 BLOCK_INFO_INPUT_ID(blk->block_info),
+				 &d77_crossbar_funcs,
+				 CBU_NUM_INPUT_IDS, get_valid_inputs(blk),
+				 CBU_NUM_OUTPUT_IDS, reg,
+				 "CBU%d", pipe_id);
+	if (IS_ERR(c)) {
+		DRM_ERROR("Failed to add crossbar component\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static void d71_merger_update(struct komeda_component *c,
 			      struct komeda_component_state *state)
 {
@@ -1351,6 +1411,7 @@  int d71_probe_block(struct d71_dev *d71,
 		break;
 
 	case D77_BLK_TYPE_CBU:
+		err = d77_crossbar_init(d71, blk, reg);
 		break;
 
 	case D77_BLK_TYPE_ATU:
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index 104e27cc1dc3..fdb17a7c6fb6 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -76,6 +76,16 @@  komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
 	case KOMEDA_COMPONENT_LAYER3:
 		pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
 		break;
+	case KOMEDA_COMPONENT_CROSSBAR0:
+	case KOMEDA_COMPONENT_CROSSBAR1:
+		temp = mdev->pipelines[id - KOMEDA_COMPONENT_CROSSBAR0];
+		if (!temp) {
+			DRM_ERROR("crossbar-%d's pipeline doesn't exist.\n",
+				  id);
+			return NULL;
+		}
+		pos = to_cpos(temp->cbar);
+		break;
 	case KOMEDA_COMPONENT_WB_LAYER:
 		pos = to_cpos(pipe->wb_layer);
 		break;
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 76621a972803..b15649d08c3a 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -34,6 +34,8 @@  enum {
 	KOMEDA_COMPONENT_IPS0		= 20, /* post image processor */
 	KOMEDA_COMPONENT_IPS1		= 21,
 	KOMEDA_COMPONENT_TIMING_CTRLR	= 22, /* timing controller */
+	KOMEDA_COMPONENT_CROSSBAR0	= 24,
+	KOMEDA_COMPONENT_CROSSBAR1	= 25,
 };
 
 #define KOMEDA_PIPELINE_LAYERS		(BIT(KOMEDA_COMPONENT_LAYER0) |\
@@ -41,6 +43,9 @@  enum {
 					 BIT(KOMEDA_COMPONENT_LAYER2) |\
 					 BIT(KOMEDA_COMPONENT_LAYER3))
 
+#define KOMEDA_PIPELINE_CROSSBARS	(BIT(KOMEDA_COMPONENT_CROSSBAR0) |\
+					 BIT(KOMEDA_COMPONENT_CROSSBAR1))
+
 #define KOMEDA_PIPELINE_SCALERS		(BIT(KOMEDA_COMPONENT_SCALER0) |\
 					 BIT(KOMEDA_COMPONENT_SCALER1))
 
@@ -412,6 +417,8 @@  struct komeda_pipeline {
 	int n_layers;
 	/** @layers: the pipeline layers */
 	struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
+	/** @cbar: the pipeline crossbar */
+	struct komeda_component *cbar;
 	/** @n_scalers: the number of scaler on @scalers */
 	int n_scalers;
 	/** @scalers: the pipeline scalers */
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 79f7e7b6526f..82f21e9b5c73 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c
@@ -665,6 +665,32 @@  void pipeline_composition_size(struct komeda_crtc_state *kcrtc_st,
 		*vsize = m->vdisplay;
 }
 
+static int
+komeda_crossbar_set_input(struct komeda_component *cbar,
+			  struct komeda_crtc_state *kcrtc_st,
+			  struct komeda_data_flow_cfg *dflow)
+{
+	struct drm_atomic_state *drm_st = kcrtc_st->base.state;
+	struct drm_crtc *crtc = kcrtc_st->base.crtc;
+	struct komeda_component_state *st;
+	u32 idx = dflow->blending_zorder;
+
+	if (!cbar)
+		return 0;
+
+	st = komeda_component_get_state_and_set_user(cbar, drm_st, crtc, crtc);
+	if (IS_ERR(st))
+		return PTR_ERR(st);
+
+	if (komeda_component_check_input(st, &dflow->input, idx))
+		return -EINVAL;
+
+	komeda_component_add_input(st, &dflow->input, idx);
+	komeda_component_set_output(&dflow->input, cbar, idx);
+
+	return 0;
+}
+
 static int
 komeda_compiz_set_input(struct komeda_compiz *compiz,
 			struct komeda_crtc_state *kcrtc_st,
@@ -905,6 +931,10 @@  int komeda_build_layer_data_flow(struct komeda_layer *layer,
 	if (err)
 		return err;
 
+	err = komeda_crossbar_set_input(pipe->cbar, kcrtc_st, dflow);
+	if (err)
+		return err;
+
 	err = komeda_scaler_validate(plane, kcrtc_st, dflow);
 	if (err)
 		return err;
@@ -1452,6 +1482,12 @@  int komeda_build_display_data_flow(struct komeda_crtc *kcrtc,
 		if (err)
 			return err;
 
+		/* if master has crossbar, connect s_dflow to crossbar */
+		err = komeda_crossbar_set_input(master->cbar, kcrtc_st,
+						&s_dflow);
+		if (err)
+			return err;
+
 		/* merge the slave dflow into master pipeline */
 		err = komeda_compiz_set_input(master->compiz, kcrtc_st,
 					      &s_dflow);
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 914400c4af73..4cc8ccf224f1 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -103,6 +103,49 @@  static int komeda_scaler_obj_add(struct komeda_kms_dev *kms,
 	return 0;
 }
 
+static struct drm_private_state *
+komeda_crossbar_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+	struct komeda_component_state *st;
+
+	st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return NULL;
+
+	komeda_component_state_reset(st);
+	__drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
+
+	return &st->obj;
+}
+
+static void
+komeda_crossbar_atomic_destroy_state(struct drm_private_obj *obj,
+				     struct drm_private_state *state)
+{
+	kfree(priv_to_comp_st(state));
+}
+
+static const struct drm_private_state_funcs komeda_crossbar_obj_funcs = {
+	.atomic_duplicate_state = komeda_crossbar_atomic_duplicate_state,
+	.atomic_destroy_state	= komeda_crossbar_atomic_destroy_state,
+};
+
+static int komeda_crossbar_obj_add(struct komeda_kms_dev *kms,
+				   struct komeda_component *cbar)
+{
+	struct komeda_component_state *st;
+	struct drm_device *dev = &kms->base;
+
+	st = kzalloc(sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+	st->component = cbar;
+
+	drm_atomic_private_obj_init(dev, &cbar->obj, &st->obj,
+				    &komeda_crossbar_obj_funcs);
+	return 0;
+}
+
 static struct drm_private_state *
 komeda_compiz_atomic_duplicate_state(struct drm_private_obj *obj)
 {
@@ -388,6 +431,12 @@  int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
 				return err;
 		}
 
+		if (pipe->cbar) {
+			err = komeda_crossbar_obj_add(kms, pipe->cbar);
+			if (err)
+				return err;
+		}
+
 		for (j = 0; j < pipe->n_scalers; j++) {
 			err = komeda_scaler_obj_add(kms, pipe->scalers[j]);
 			if (err)