diff options
Diffstat (limited to 'drivers/gpu/drm/arm/display')
7 files changed, 211 insertions, 18 deletions
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 c3d29c0b051b..f0ba26e282c3 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c @@ -106,6 +106,23 @@ static void dump_block_header(struct seq_file *sf, void __iomem *reg)  			   i, hdr.output_ids[i]);  } +/* On D71, we are using the global line size. From D32, every component have + * a line size register to indicate the fifo size. + */ +static u32 __get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg, +			       u32 max_default) +{ +	if (!d71->periph_addr) +		max_default = malidp_read32(reg, BLK_MAX_LINE_SIZE); + +	return max_default; +} + +static u32 get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg) +{ +	return __get_blk_line_size(d71, reg, d71->max_line_size); +} +  static u32 to_rot_ctrl(u32 rot)  {  	u32 lr_ctrl = 0; @@ -332,7 +349,56 @@ static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)  	seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);  } +static int d71_layer_validate(struct komeda_component *c, +			      struct komeda_component_state *state) +{ +	struct komeda_layer_state *st = to_layer_st(state); +	struct komeda_layer *layer = to_layer(c); +	struct drm_plane_state *plane_st; +	struct drm_framebuffer *fb; +	u32 fourcc, line_sz, max_line_sz; + +	plane_st = drm_atomic_get_new_plane_state(state->obj.state, +						  state->plane); +	fb = plane_st->fb; +	fourcc = fb->format->format; + +	if (drm_rotation_90_or_270(st->rot)) +		line_sz = st->vsize - st->afbc_crop_t - st->afbc_crop_b; +	else +		line_sz = st->hsize - st->afbc_crop_l - st->afbc_crop_r; + +	if (fb->modifier) { +		if ((fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == +			AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) +			max_line_sz = layer->line_sz; +		else +			max_line_sz = layer->line_sz / 2; + +		if (line_sz > max_line_sz) { +			DRM_DEBUG_ATOMIC("afbc request line_sz: %d exceed the max afbc line_sz: %d.\n", +					 line_sz, max_line_sz); +			return -EINVAL; +		} +	} + +	if (fourcc == DRM_FORMAT_YUV420_10BIT && line_sz > 2046 && (st->afbc_crop_l % 4)) { +		DRM_DEBUG_ATOMIC("YUV420_10BIT input_hsize: %d exceed the max size 2046.\n", +				 line_sz); +		return -EINVAL; +	} + +	if (fourcc == DRM_FORMAT_X0L2 && line_sz > 2046 && (st->addr[0] % 16)) { +		DRM_DEBUG_ATOMIC("X0L2 input_hsize: %d exceed the max size 2046.\n", +				 line_sz); +		return -EINVAL; +	} + +	return 0; +} +  static const struct komeda_component_funcs d71_layer_funcs = { +	.validate	= d71_layer_validate,  	.update		= d71_layer_update,  	.disable	= d71_layer_disable,  	.dump_register	= d71_layer_dump, @@ -365,7 +431,28 @@ static int d71_layer_init(struct d71_dev *d71,  	else  		layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER; -	set_range(&layer->hsize_in, 4, d71->max_line_size); +	if (!d71->periph_addr) { +		/* D32 or newer product */ +		layer->line_sz = malidp_read32(reg, BLK_MAX_LINE_SIZE); +		layer->yuv_line_sz = L_INFO_YUV_MAX_LINESZ(layer_info); +	} else if (d71->max_line_size > 2048) { +		/* D71 4K */ +		layer->line_sz = d71->max_line_size; +		layer->yuv_line_sz = layer->line_sz / 2; +	} else	{ +		/* D71 2K */ +		if (layer->layer_type == KOMEDA_FMT_RICH_LAYER) { +			/* rich layer is 4K configuration */ +			layer->line_sz = d71->max_line_size * 2; +			layer->yuv_line_sz = layer->line_sz / 2; +		} else { +			layer->line_sz = d71->max_line_size; +			layer->yuv_line_sz = 0; +		} +	} + +	set_range(&layer->hsize_in, 4, layer->line_sz); +  	set_range(&layer->vsize_in, 4, d71->max_vsize);  	malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP); @@ -456,9 +543,11 @@ static int d71_wb_layer_init(struct d71_dev *d71,  	wb_layer = to_layer(c);  	wb_layer->layer_type = KOMEDA_FMT_WB_LAYER; +	wb_layer->line_sz = get_blk_line_size(d71, reg); +	wb_layer->yuv_line_sz = wb_layer->line_sz; -	set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size); -	set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize); +	set_range(&wb_layer->hsize_in, 64, wb_layer->line_sz); +	set_range(&wb_layer->vsize_in, 64, d71->max_vsize);  	return 0;  } @@ -595,8 +684,8 @@ static int d71_compiz_init(struct d71_dev *d71,  	compiz = to_compiz(c); -	set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size); -	set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize); +	set_range(&compiz->hsize, 64, get_blk_line_size(d71, reg)); +	set_range(&compiz->vsize, 64, d71->max_vsize);  	return 0;  } @@ -703,7 +792,7 @@ static void d71_scaler_update(struct komeda_component *c,  static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)  { -	u32 v[9]; +	u32 v[10];  	dump_block_header(sf, c->reg); @@ -723,6 +812,18 @@ static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)  	seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);  	seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);  	seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]); + +	get_values_from_reg(c->reg, 0x130, 10, v); +	seq_printf(sf, "SC_ENH_LIMITS:\t\t0x%X\n", v[0]); +	seq_printf(sf, "SC_ENH_COEFF0:\t\t0x%X\n", v[1]); +	seq_printf(sf, "SC_ENH_COEFF1:\t\t0x%X\n", v[2]); +	seq_printf(sf, "SC_ENH_COEFF2:\t\t0x%X\n", v[3]); +	seq_printf(sf, "SC_ENH_COEFF3:\t\t0x%X\n", v[4]); +	seq_printf(sf, "SC_ENH_COEFF4:\t\t0x%X\n", v[5]); +	seq_printf(sf, "SC_ENH_COEFF5:\t\t0x%X\n", v[6]); +	seq_printf(sf, "SC_ENH_COEFF6:\t\t0x%X\n", v[7]); +	seq_printf(sf, "SC_ENH_COEFF7:\t\t0x%X\n", v[8]); +	seq_printf(sf, "SC_ENH_COEFF8:\t\t0x%X\n", v[9]);  }  static const struct komeda_component_funcs d71_scaler_funcs = { @@ -753,7 +854,7 @@ static int d71_scaler_init(struct d71_dev *d71,  	}  	scaler = to_scaler(c); -	set_range(&scaler->hsize, 4, 2048); +	set_range(&scaler->hsize, 4, __get_blk_line_size(d71, reg, 2048));  	set_range(&scaler->vsize, 4, 4096);  	scaler->max_downscaling = 6;  	scaler->max_upscaling = 64; @@ -862,7 +963,7 @@ static int d71_splitter_init(struct d71_dev *d71,  	splitter = to_splitter(c); -	set_range(&splitter->hsize, 4, d71->max_line_size); +	set_range(&splitter->hsize, 4, get_blk_line_size(d71, reg));  	set_range(&splitter->vsize, 4, d71->max_vsize);  	return 0; @@ -933,7 +1034,8 @@ static int d71_merger_init(struct d71_dev *d71,  	merger = to_merger(c); -	set_range(&merger->hsize_merged, 4, 4032); +	set_range(&merger->hsize_merged, 4, +		  __get_blk_line_size(d71, reg, 4032));  	set_range(&merger->vsize_merged, 4, 4096);  	return 0; @@ -944,13 +1046,26 @@ static void d71_improc_update(struct komeda_component *c,  {  	struct komeda_improc_state *st = to_improc_st(state);  	u32 __iomem *reg = c->reg; -	u32 index; +	u32 index, mask = 0, ctrl = 0;  	for_each_changed_input(state, index)  		malidp_write32(reg, BLK_INPUT_ID0 + index * 4,  			       to_d71_input_id(state, index));  	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); +	malidp_write32(reg, IPS_DEPTH, st->color_depth); + +	mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; + +	/* config color format */ +	if (st->color_format == DRM_COLOR_FORMAT_YCRCB420) +		ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; +	else if (st->color_format == DRM_COLOR_FORMAT_YCRCB422) +		ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422; +	else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444) +		ctrl |= IPS_CTRL_YUV; + +	malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);  }  static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf) diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h index 2d5e6d00b42c..1727dc993909 100644 --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_regs.h @@ -10,6 +10,7 @@  /* Common block registers offset */  #define BLK_BLOCK_INFO		0x000  #define BLK_PIPELINE_INFO	0x004 +#define BLK_MAX_LINE_SIZE	0x008  #define BLK_VALID_INPUT_ID0	0x020  #define BLK_OUTPUT_ID0		0x060  #define BLK_INPUT_ID0		0x080 @@ -321,6 +322,7 @@  #define L_INFO_RF		BIT(0)  #define L_INFO_CM		BIT(1)  #define L_INFO_ABUF_SIZE(x)	(((x) >> 4) & 0x7) +#define L_INFO_YUV_MAX_LINESZ(x)	(((x) >> 16) & 0xFFFF)  /* Scaler registers */  #define SC_COEFFTAB		0x0DC @@ -494,13 +496,6 @@ enum d71_blk_type {  #define D71_DEFAULT_PREPRETCH_LINE	5  #define D71_BUS_WIDTH_16_BYTES		16 -#define D71_MIN_LINE_SIZE		64 -#define D71_MIN_VERTICAL_SIZE		64 -#define D71_SC_MIN_LIN_SIZE		4 -#define D71_SC_MIN_VERTICAL_SIZE	4 -#define D71_SC_MAX_LIN_SIZE		2048 -#define D71_SC_MAX_VERTICAL_SIZE	4096 -  #define D71_SC_MAX_UPSCALING		64  #define D71_SC_MAX_DOWNSCALING		6  #define D71_SC_SPLIT_OVERLAP		8 diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c index 75263d8cd0bd..252015210fbc 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c @@ -17,6 +17,33 @@  #include "komeda_dev.h"  #include "komeda_kms.h" +void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st, +				  u32 *color_depths, u32 *color_formats) +{ +	struct drm_connector *conn; +	struct drm_connector_state *conn_st; +	u32 conn_color_formats = ~0u; +	int i, min_bpc = 31, conn_bpc = 0; + +	for_each_new_connector_in_state(crtc_st->state, conn, conn_st, i) { +		if (conn_st->crtc != crtc_st->crtc) +			continue; + +		conn_bpc = conn->display_info.bpc ? conn->display_info.bpc : 8; +		conn_color_formats &= conn->display_info.color_formats; + +		if (conn_bpc < min_bpc) +			min_bpc = conn_bpc; +	} + +	/* connector doesn't config any color_format, use RGB444 as default */ +	if (!conn_color_formats) +		conn_color_formats = DRM_COLOR_FORMAT_RGB444; + +	*color_depths = GENMASK(min_bpc, 0); +	*color_formats = conn_color_formats; +} +  static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st)  {  	u64 pxlclk, aclk; @@ -296,7 +323,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc,  	struct komeda_crtc_state *old_st = to_kcrtc_st(old);  	struct komeda_pipeline *master = kcrtc->master;  	struct komeda_pipeline *slave  = kcrtc->slave; -	struct completion *disable_done = &crtc->state->commit->flip_done; +	struct completion *disable_done;  	bool needs_phase2 = false;  	DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x\n", diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h index 45c498e15e7a..456f3c435719 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h @@ -166,6 +166,8 @@ static inline bool has_flip_h(u32 rot)  		return !!(rotation & DRM_MODE_REFLECT_X);  } +void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st, +				  u32 *color_depths, u32 *color_formats);  unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st);  int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h index b322f52ba8f2..bd6ca7c87037 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h @@ -227,6 +227,8 @@ struct komeda_layer {  	/* accepted h/v input range before rotation */  	struct malidp_range hsize_in, vsize_in;  	u32 layer_type; /* RICH, SIMPLE or WB */ +	u32 line_sz; +	u32 yuv_line_sz; /* maximum line size for YUV422 and YUV420 */  	u32 supported_rots;  	/* komeda supports layer split which splits a whole image to two parts  	 * left and right and handle them by two individual layer processors @@ -323,6 +325,7 @@ struct komeda_improc {  struct komeda_improc_state {  	struct komeda_component_state base; +	u8 color_format, color_depth;  	u16 hsize, vsize;  }; 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 0ba9c6aa3708..42bdc63dcffa 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline_state.c @@ -285,6 +285,7 @@ komeda_layer_check_cfg(struct komeda_layer *layer,  		       struct komeda_data_flow_cfg *dflow)  {  	u32 src_x, src_y, src_w, src_h; +	u32 line_sz, max_line_sz;  	if (!komeda_fb_is_layer_supported(kfb, layer->layer_type, dflow->rot))  		return -EINVAL; @@ -314,6 +315,22 @@ komeda_layer_check_cfg(struct komeda_layer *layer,  		return -EINVAL;  	} +	if (drm_rotation_90_or_270(dflow->rot)) +		line_sz = dflow->in_h; +	else +		line_sz = dflow->in_w; + +	if (kfb->base.format->hsub > 1) +		max_line_sz = layer->yuv_line_sz; +	else +		max_line_sz = layer->line_sz; + +	if (line_sz > max_line_sz) { +		DRM_DEBUG_ATOMIC("Required line_sz: %d exceeds the max size %d\n", +				 line_sz, max_line_sz); +		return -EINVAL; +	} +  	return 0;  } @@ -743,6 +760,7 @@ komeda_improc_validate(struct komeda_improc *improc,  		       struct komeda_data_flow_cfg *dflow)  {  	struct drm_crtc *crtc = kcrtc_st->base.crtc; +	struct drm_crtc_state *crtc_st = &kcrtc_st->base;  	struct komeda_component_state *c_st;  	struct komeda_improc_state *st; @@ -756,6 +774,34 @@ komeda_improc_validate(struct komeda_improc *improc,  	st->hsize = dflow->in_w;  	st->vsize = dflow->in_h; +	if (drm_atomic_crtc_needs_modeset(crtc_st)) { +		u32 output_depths, output_formats; +		u32 avail_depths, avail_formats; + +		komeda_crtc_get_color_config(crtc_st, &output_depths, +					     &output_formats); + +		avail_depths = output_depths & improc->supported_color_depths; +		if (avail_depths == 0) { +			DRM_DEBUG_ATOMIC("No available color depths, conn depths: 0x%x & display: 0x%x\n", +					 output_depths, +					 improc->supported_color_depths); +			return -EINVAL; +		} + +		avail_formats = output_formats & +				improc->supported_color_formats; +		if (!avail_formats) { +			DRM_DEBUG_ATOMIC("No available color_formats, conn formats 0x%x & display: 0x%x\n", +					 output_formats, +					 improc->supported_color_formats); +			return -EINVAL; +		} + +		st->color_depth = __fls(avail_depths); +		st->color_format = BIT(__ffs(avail_formats)); +	} +  	komeda_component_add_input(&st->base, &dflow->input, 0);  	komeda_component_set_output(&dflow->input, &improc->base, 0); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c index b72840c06ab7..e465cc4879c9 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c @@ -141,6 +141,7 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms,  	struct komeda_dev *mdev = kms->base.dev_private;  	struct komeda_wb_connector *kwb_conn;  	struct drm_writeback_connector *wb_conn; +	struct drm_display_info *info;  	u32 *formats, n_formats = 0;  	int err; @@ -172,6 +173,10 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms,  	drm_connector_helper_add(&wb_conn->base, &komeda_wb_conn_helper_funcs); +	info = &kwb_conn->base.base.display_info; +	info->bpc = __fls(kcrtc->master->improc->supported_color_depths); +	info->color_formats = kcrtc->master->improc->supported_color_formats; +  	kcrtc->wb_conn = kwb_conn;  	return 0;  | 
