File Index
Files and directories
Sign in
FILE

d71_component.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
   4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
   5 *
   6 */
   7
   8#include <linux/seq_file.h>
   9#include "d71_dev.h"
  10#include "komeda_kms.h"
  11#include "malidp_io.h"
  12#include "komeda_framebuffer.h"
  13#include "komeda_color_mgmt.h"
  14
  15static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id)
  16{
  17	u32 id = BLOCK_INFO_BLK_ID(hw_id);
  18	u32 pipe = id;
  19
  20	switch (BLOCK_INFO_BLK_TYPE(hw_id)) {
  21	case D71_BLK_TYPE_LPU_WB_LAYER:
  22		id = KOMEDA_COMPONENT_WB_LAYER;
  23		break;
  24	case D71_BLK_TYPE_CU_SPLITTER:
  25		id = KOMEDA_COMPONENT_SPLITTER;
  26		break;
  27	case D71_BLK_TYPE_CU_SCALER:
  28		pipe = id / D71_PIPELINE_MAX_SCALERS;
  29		id %= D71_PIPELINE_MAX_SCALERS;
  30		id += KOMEDA_COMPONENT_SCALER0;
  31		break;
  32	case D71_BLK_TYPE_CU:
  33		id += KOMEDA_COMPONENT_COMPIZ0;
  34		break;
  35	case D71_BLK_TYPE_LPU_LAYER:
  36		pipe = id / D71_PIPELINE_MAX_LAYERS;
  37		id %= D71_PIPELINE_MAX_LAYERS;
  38		id += KOMEDA_COMPONENT_LAYER0;
  39		break;
  40	case D71_BLK_TYPE_DOU_IPS:
  41		id += KOMEDA_COMPONENT_IPS0;
  42		break;
  43	case D71_BLK_TYPE_CU_MERGER:
  44		id = KOMEDA_COMPONENT_MERGER;
  45		break;
  46	case D71_BLK_TYPE_DOU:
  47		id = KOMEDA_COMPONENT_TIMING_CTRLR;
  48		break;
  49	default:
  50		id = 0xFFFFFFFF;
  51	}
  52
  53	if (comp_id)
  54		*comp_id = id;
  55
  56	if (pipe_id)
  57		*pipe_id = pipe;
  58}
  59
  60static u32 get_valid_inputs(struct block_header *blk)
  61{
  62	u32 valid_inputs = 0, comp_id;
  63	int i;
  64
  65	for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++) {
  66		get_resources_id(blk->input_ids[i], NULL, &comp_id);
  67		if (comp_id == 0xFFFFFFFF)
  68			continue;
  69		valid_inputs |= BIT(comp_id);
  70	}
  71
  72	return valid_inputs;
  73}
  74
  75static void get_values_from_reg(void __iomem *reg, u32 offset,
  76				u32 count, u32 *val)
  77{
  78	u32 i, addr;
  79
  80	for (i = 0; i < count; i++) {
  81		addr = offset + (i << 2);
  82		/* 0xA4 is WO register */
  83		if (addr != 0xA4)
  84			val[i] = malidp_read32(reg, addr);
  85		else
  86			val[i] = 0xDEADDEAD;
  87	}
  88}
  89
  90static void dump_block_header(struct seq_file *sf, void __iomem *reg)
  91{
  92	struct block_header hdr;
  93	u32 i, n_input, n_output;
  94
  95	d71_read_block_header(reg, &hdr);
  96	seq_printf(sf, "BLOCK_INFO:\t\t0x%X\n", hdr.block_info);
  97	seq_printf(sf, "PIPELINE_INFO:\t\t0x%X\n", hdr.pipeline_info);
  98
  99	n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info);
 100	n_input  = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info);
 101
 102	for (i = 0; i < n_input; i++)
 103		seq_printf(sf, "VALID_INPUT_ID%u:\t0x%X\n",
 104			   i, hdr.input_ids[i]);
 105
 106	for (i = 0; i < n_output; i++)
 107		seq_printf(sf, "OUTPUT_ID%u:\t\t0x%X\n",
 108			   i, hdr.output_ids[i]);
 109}
 110
 111/* On D71, we are using the global line size. From D32, every component have
 112 * a line size register to indicate the fifo size.
 113 */
 114static u32 __get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg,
 115			       u32 max_default)
 116{
 117	if (!d71->periph_addr)
 118		max_default = malidp_read32(reg, BLK_MAX_LINE_SIZE);
 119
 120	return max_default;
 121}
 122
 123static u32 get_blk_line_size(struct d71_dev *d71, u32 __iomem *reg)
 124{
 125	return __get_blk_line_size(d71, reg, d71->max_line_size);
 126}
 127
 128static u32 to_rot_ctrl(u32 rot)
 129{
 130	u32 lr_ctrl = 0;
 131
 132	switch (rot & DRM_MODE_ROTATE_MASK) {
 133	case DRM_MODE_ROTATE_0:
 134		lr_ctrl |= L_ROT(L_ROT_R0);
 135		break;
 136	case DRM_MODE_ROTATE_90:
 137		lr_ctrl |= L_ROT(L_ROT_R90);
 138		break;
 139	case DRM_MODE_ROTATE_180:
 140		lr_ctrl |= L_ROT(L_ROT_R180);
 141		break;
 142	case DRM_MODE_ROTATE_270:
 143		lr_ctrl |= L_ROT(L_ROT_R270);
 144		break;
 145	}
 146
 147	if (rot & DRM_MODE_REFLECT_X)
 148		lr_ctrl |= L_HFLIP;
 149	if (rot & DRM_MODE_REFLECT_Y)
 150		lr_ctrl |= L_VFLIP;
 151
 152	return lr_ctrl;
 153}
 154
 155static u32 to_ad_ctrl(u64 modifier)
 156{
 157	u32 afbc_ctrl = AD_AEN;
 158
 159	if (!modifier)
 160		return 0;
 161
 162	if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
 163	    AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
 164		afbc_ctrl |= AD_WB;
 165
 166	if (modifier & AFBC_FORMAT_MOD_YTR)
 167		afbc_ctrl |= AD_YT;
 168	if (modifier & AFBC_FORMAT_MOD_SPLIT)
 169		afbc_ctrl |= AD_BS;
 170	if (modifier & AFBC_FORMAT_MOD_TILED)
 171		afbc_ctrl |= AD_TH;
 172
 173	return afbc_ctrl;
 174}
 175
 176static inline u32 to_d71_input_id(struct komeda_component_state *st, int idx)
 177{
 178	struct komeda_component_output *input = &st->inputs[idx];
 179
 180	/* if input is not active, set hw input_id(0) to disable it */
 181	if (has_bit(idx, st->active_inputs))
 182		return input->component->hw_id + input->output_port;
 183	else
 184		return 0;
 185}
 186
 187static void d71_layer_update_fb(struct komeda_component *c,
 188				struct komeda_fb *kfb,
 189				dma_addr_t *addr)
 190{
 191	struct drm_framebuffer *fb = &kfb->base;
 192	const struct drm_format_info *info = fb->format;
 193	u32 __iomem *reg = c->reg;
 194	int block_h;
 195
 196	if (info->num_planes > 2)
 197		malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);
 198
 199	if (info->num_planes > 1) {
 200		block_h = drm_format_info_block_height(info, 1);
 201		malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);
 202		malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);
 203	}
 204
 205	block_h = drm_format_info_block_height(info, 0);
 206	malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);
 207	malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);
 208	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
 209}
 210
 211static void d71_layer_disable(struct komeda_component *c)
 212{
 213	malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
 214}
 215
 216static void d71_layer_update(struct komeda_component *c,
 217			     struct komeda_component_state *state)
 218{
 219	struct komeda_layer_state *st = to_layer_st(state);
 220	struct drm_plane_state *plane_st = state->plane->state;
 221	struct drm_framebuffer *fb = plane_st->fb;
 222	struct komeda_fb *kfb = to_kfb(fb);
 223	u32 __iomem *reg = c->reg;
 224	u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
 225	u32 ctrl = L_EN | to_rot_ctrl(st->rot);
 226
 227	d71_layer_update_fb(c, kfb, st->addr);
 228
 229	malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
 230	if (fb->modifier) {
 231		u64 addr;
 232
 233		malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
 234							     st->afbc_crop_r));
 235		malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
 236							     st->afbc_crop_b));
 237		/* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
 238		if (fb->modifier & AFBC_FORMAT_MOD_TILED)
 239			addr = st->addr[0] + kfb->offset_payload;
 240		else
 241			addr = st->addr[0] + kfb->afbc_size - 1;
 242
 243		malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
 244		malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
 245	}
 246
 247	if (fb->format->is_yuv) {
 248		u32 upsampling = 0;
 249
 250		switch (kfb->format_caps->fourcc) {
 251		case DRM_FORMAT_YUYV:
 252			upsampling = fb->modifier ? LR_CHI422_BILINEAR :
 253				     LR_CHI422_REPLICATION;
 254			break;
 255		case DRM_FORMAT_UYVY:
 256			upsampling = LR_CHI422_REPLICATION;
 257			break;
 258		case DRM_FORMAT_NV12:
 259		case DRM_FORMAT_YUV420_8BIT:
 260		case DRM_FORMAT_YUV420_10BIT:
 261		case DRM_FORMAT_YUV420:
 262		case DRM_FORMAT_P010:
 263		/* these fmt support MPGE/JPEG both, here perfer JPEG*/
 264			upsampling = LR_CHI420_JPEG;
 265			break;
 266		case DRM_FORMAT_X0L2:
 267			upsampling = LR_CHI420_JPEG;
 268			break;
 269		default:
 270			break;
 271		}
 272
 273		malidp_write32(reg, LAYER_R_CONTROL, upsampling);
 274		malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,
 275				   KOMEDA_N_YUV2RGB_COEFFS,
 276				   komeda_select_yuv2rgb_coeffs(
 277					plane_st->color_encoding,
 278					plane_st->color_range));
 279	}
 280
 281	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
 282
 283	if (kfb->is_va)
 284		ctrl |= L_TBU_EN;
 285	malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
 286}
 287
 288static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
 289{
 290	u32 v[15], i;
 291	bool rich, rgb2rgb;
 292	char *prefix;
 293
 294	get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
 295	if (v[14] & 0x1) {
 296		rich = true;
 297		prefix = "LR_";
 298	} else {
 299		rich = false;
 300		prefix = "LS_";
 301	}
 302
 303	rgb2rgb = !!(v[14] & L_INFO_CM);
 304
 305	dump_block_header(sf, c->reg);
 306
 307	seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
 308
 309	get_values_from_reg(c->reg, 0xD0, 1, v);
 310	seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
 311	if (rich) {
 312		get_values_from_reg(c->reg, 0xD4, 1, v);
 313		seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
 314	}
 315	get_values_from_reg(c->reg, 0xD8, 4, v);
 316	seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
 317	seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
 318	seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
 319	seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
 320
 321	get_values_from_reg(c->reg, 0x100, 3, v);
 322	seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
 323	seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
 324	seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
 325
 326	get_values_from_reg(c->reg, 0x110, 2, v);
 327	seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
 328	seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
 329	if (rich) {
 330		get_values_from_reg(c->reg, 0x118, 1, v);
 331		seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
 332
 333		get_values_from_reg(c->reg, 0x120, 2, v);
 334		seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
 335		seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
 336
 337		get_values_from_reg(c->reg, 0x130, 12, v);
 338		for (i = 0; i < 12; i++)
 339			seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
 340	}
 341
 342	if (rgb2rgb) {
 343		get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
 344		for (i = 0; i < 12; i++)
 345			seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
 346	}
 347
 348	get_values_from_reg(c->reg, 0x160, 3, v);
 349	seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
 350	seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
 351	seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
 352}
 353
 354static int d71_layer_validate(struct komeda_component *c,
 355			      struct komeda_component_state *state)
 356{
 357	struct komeda_layer_state *st = to_layer_st(state);
 358	struct komeda_layer *layer = to_layer(c);
 359	struct drm_plane_state *plane_st;
 360	struct drm_framebuffer *fb;
 361	u32 fourcc, line_sz, max_line_sz;
 362
 363	plane_st = drm_atomic_get_new_plane_state(state->obj.state,
 364						  state->plane);
 365	fb = plane_st->fb;
 366	fourcc = fb->format->format;
 367
 368	if (drm_rotation_90_or_270(st->rot))
 369		line_sz = st->vsize - st->afbc_crop_t - st->afbc_crop_b;
 370	else
 371		line_sz = st->hsize - st->afbc_crop_l - st->afbc_crop_r;
 372
 373	if (fb->modifier) {
 374		if ((fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
 375			AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
 376			max_line_sz = layer->line_sz;
 377		else
 378			max_line_sz = layer->line_sz / 2;
 379
 380		if (line_sz > max_line_sz) {
 381			DRM_DEBUG_ATOMIC("afbc request line_sz: %d exceed the max afbc line_sz: %d.\n",
 382					 line_sz, max_line_sz);
 383			return -EINVAL;
 384		}
 385	}
 386
 387	if (fourcc == DRM_FORMAT_YUV420_10BIT && line_sz > 2046 && (st->afbc_crop_l % 4)) {
 388		DRM_DEBUG_ATOMIC("YUV420_10BIT input_hsize: %d exceed the max size 2046.\n",
 389				 line_sz);
 390		return -EINVAL;
 391	}
 392
 393	if (fourcc == DRM_FORMAT_X0L2 && line_sz > 2046 && (st->addr[0] % 16)) {
 394		DRM_DEBUG_ATOMIC("X0L2 input_hsize: %d exceed the max size 2046.\n",
 395				 line_sz);
 396		return -EINVAL;
 397	}
 398
 399	return 0;
 400}
 401
 402static const struct komeda_component_funcs d71_layer_funcs = {
 403	.validate	= d71_layer_validate,
 404	.update		= d71_layer_update,
 405	.disable	= d71_layer_disable,
 406	.dump_register	= d71_layer_dump,
 407};
 408
 409static int d71_layer_init(struct d71_dev *d71,
 410			  struct block_header *blk, u32 __iomem *reg)
 411{
 412	struct komeda_component *c;
 413	struct komeda_layer *layer;
 414	u32 pipe_id, layer_id, layer_info;
 415
 416	get_resources_id(blk->block_info, &pipe_id, &layer_id);
 417	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
 418				 layer_id,
 419				 BLOCK_INFO_INPUT_ID(blk->block_info),
 420				 &d71_layer_funcs, 0,
 421				 get_valid_inputs(blk),
 422				 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
 423	if (IS_ERR(c)) {
 424		DRM_ERROR("Failed to add layer component\n");
 425		return PTR_ERR(c);
 426	}
 427
 428	layer = to_layer(c);
 429	layer_info = malidp_read32(reg, LAYER_INFO);
 430
 431	if (layer_info & L_INFO_RF)
 432		layer->layer_type = KOMEDA_FMT_RICH_LAYER;
 433	else
 434		layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
 435
 436	if (!d71->periph_addr) {
 437		/* D32 or newer product */
 438		layer->line_sz = malidp_read32(reg, BLK_MAX_LINE_SIZE);
 439		layer->yuv_line_sz = L_INFO_YUV_MAX_LINESZ(layer_info);
 440	} else if (d71->max_line_size > 2048) {
 441		/* D71 4K */
 442		layer->line_sz = d71->max_line_size;
 443		layer->yuv_line_sz = layer->line_sz / 2;
 444	} else	{
 445		/* D71 2K */
 446		if (layer->layer_type == KOMEDA_FMT_RICH_LAYER) {
 447			/* rich layer is 4K configuration */
 448			layer->line_sz = d71->max_line_size * 2;
 449			layer->yuv_line_sz = layer->line_sz / 2;
 450		} else {
 451			layer->line_sz = d71->max_line_size;
 452			layer->yuv_line_sz = 0;
 453		}
 454	}
 455
 456	set_range(&layer->hsize_in, 4, layer->line_sz);
 457
 458	set_range(&layer->vsize_in, 4, d71->max_vsize);
 459
 460	malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
 461
 462	layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
 463
 464	return 0;
 465}
 466
 467static void d71_wb_layer_update(struct komeda_component *c,
 468				struct komeda_component_state *state)
 469{
 470	struct komeda_layer_state *st = to_layer_st(state);
 471	struct drm_connector_state *conn_st = state->wb_conn->state;
 472	struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
 473	u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
 474	u32 __iomem *reg = c->reg;
 475
 476	d71_layer_update_fb(c, kfb, st->addr);
 477
 478	if (kfb->is_va)
 479		ctrl |= LW_TBU_EN;
 480
 481	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
 482	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 483	malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
 484}
 485
 486static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
 487{
 488	u32 v[12], i;
 489
 490	dump_block_header(sf, c->reg);
 491
 492	get_values_from_reg(c->reg, 0x80, 1, v);
 493	seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
 494
 495	get_values_from_reg(c->reg, 0xD0, 3, v);
 496	seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
 497	seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
 498	seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
 499
 500	get_values_from_reg(c->reg, 0xE0, 1, v);
 501	seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
 502
 503	for (i = 0; i < 2; i++) {
 504		get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
 505		seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
 506		seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
 507		seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
 508	}
 509
 510	get_values_from_reg(c->reg, 0x130, 12, v);
 511	for (i = 0; i < 12; i++)
 512		seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
 513}
 514
 515static void d71_wb_layer_disable(struct komeda_component *c)
 516{
 517	malidp_write32(c->reg, BLK_INPUT_ID0, 0);
 518	malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
 519}
 520
 521static const struct komeda_component_funcs d71_wb_layer_funcs = {
 522	.update		= d71_wb_layer_update,
 523	.disable	= d71_wb_layer_disable,
 524	.dump_register	= d71_wb_layer_dump,
 525};
 526
 527static int d71_wb_layer_init(struct d71_dev *d71,
 528			     struct block_header *blk, u32 __iomem *reg)
 529{
 530	struct komeda_component *c;
 531	struct komeda_layer *wb_layer;
 532	u32 pipe_id, layer_id;
 533
 534	get_resources_id(blk->block_info, &pipe_id, &layer_id);
 535
 536	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
 537				 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
 538				 &d71_wb_layer_funcs,
 539				 1, get_valid_inputs(blk), 0, reg,
 540				 "LPU%d_LAYER_WR", pipe_id);
 541	if (IS_ERR(c)) {
 542		DRM_ERROR("Failed to add wb_layer component\n");
 543		return PTR_ERR(c);
 544	}
 545
 546	wb_layer = to_layer(c);
 547	wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
 548	wb_layer->line_sz = get_blk_line_size(d71, reg);
 549	wb_layer->yuv_line_sz = wb_layer->line_sz;
 550
 551	set_range(&wb_layer->hsize_in, 64, wb_layer->line_sz);
 552	set_range(&wb_layer->vsize_in, 64, d71->max_vsize);
 553
 554	return 0;
 555}
 556
 557static void d71_component_disable(struct komeda_component *c)
 558{
 559	u32 __iomem *reg = c->reg;
 560	u32 i;
 561
 562	malidp_write32(reg, BLK_CONTROL, 0);
 563
 564	for (i = 0; i < c->max_active_inputs; i++) {
 565		malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
 566
 567		/* Besides clearing the input ID to zero, D71 compiz also has
 568		 * input enable bit in CU_INPUTx_CONTROL which need to be
 569		 * cleared.
 570		 */
 571		if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))
 572			malidp_write32(reg, CU_INPUT0_CONTROL +
 573				       i * CU_PER_INPUT_REGS * 4,
 574				       CU_INPUT_CTRL_ALPHA(0xFF));
 575	}
 576}
 577
 578static void compiz_enable_input(u32 __iomem *id_reg,
 579				u32 __iomem *cfg_reg,
 580				u32 input_hw_id,
 581				struct komeda_compiz_input_cfg *cin)
 582{
 583	u32 ctrl = CU_INPUT_CTRL_EN;
 584	u8 blend = cin->pixel_blend_mode;
 585
 586	if (blend == DRM_MODE_BLEND_PIXEL_NONE)
 587		ctrl |= CU_INPUT_CTRL_PAD;
 588	else if (blend == DRM_MODE_BLEND_PREMULTI)
 589		ctrl |= CU_INPUT_CTRL_PMUL;
 590
 591	ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
 592
 593	malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
 594
 595	malidp_write32(cfg_reg, CU_INPUT0_SIZE,
 596		       HV_SIZE(cin->hsize, cin->vsize));
 597	malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
 598		       HV_OFFSET(cin->hoffset, cin->voffset));
 599	malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
 600}
 601
 602static void d71_compiz_update(struct komeda_component *c,
 603			      struct komeda_component_state *state)
 604{
 605	struct komeda_compiz_state *st = to_compiz_st(state);
 606	u32 __iomem *reg = c->reg;
 607	u32 __iomem *id_reg, *cfg_reg;
 608	u32 index;
 609
 610	for_each_changed_input(state, index) {
 611		id_reg = reg + index;
 612		cfg_reg = reg + index * CU_PER_INPUT_REGS;
 613		if (state->active_inputs & BIT(index)) {
 614			compiz_enable_input(id_reg, cfg_reg,
 615					    to_d71_input_id(state, index),
 616					    &st->cins[index]);
 617		} else {
 618			malidp_write32(id_reg, BLK_INPUT_ID0, 0);
 619			malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
 620		}
 621	}
 622
 623	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 624}
 625
 626static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
 627{
 628	u32 v[8], i;
 629
 630	dump_block_header(sf, c->reg);
 631
 632	get_values_from_reg(c->reg, 0x80, 5, v);
 633	for (i = 0; i < 5; i++)
 634		seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
 635
 636	get_values_from_reg(c->reg, 0xA0, 5, v);
 637	seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
 638	seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
 639	seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
 640	seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
 641	seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
 642
 643	get_values_from_reg(c->reg, 0xD0, 2, v);
 644	seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
 645	seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
 646
 647	get_values_from_reg(c->reg, 0xDC, 1, v);
 648	seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
 649
 650	for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
 651		get_values_from_reg(c->reg, v[4], 3, v);
 652		seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
 653		seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
 654		seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
 655	}
 656
 657	get_values_from_reg(c->reg, 0x130, 2, v);
 658	seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
 659	seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
 660}
 661
 662static const struct komeda_component_funcs d71_compiz_funcs = {
 663	.update		= d71_compiz_update,
 664	.disable	= d71_component_disable,
 665	.dump_register	= d71_compiz_dump,
 666};
 667
 668static int d71_compiz_init(struct d71_dev *d71,
 669			   struct block_header *blk, u32 __iomem *reg)
 670{
 671	struct komeda_component *c;
 672	struct komeda_compiz *compiz;
 673	u32 pipe_id, comp_id;
 674
 675	get_resources_id(blk->block_info, &pipe_id, &comp_id);
 676
 677	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
 678				 comp_id,
 679				 BLOCK_INFO_INPUT_ID(blk->block_info),
 680				 &d71_compiz_funcs,
 681				 CU_NUM_INPUT_IDS, get_valid_inputs(blk),
 682				 CU_NUM_OUTPUT_IDS, reg,
 683				 "CU%d", pipe_id);
 684	if (IS_ERR(c))
 685		return PTR_ERR(c);
 686
 687	compiz = to_compiz(c);
 688
 689	set_range(&compiz->hsize, 64, get_blk_line_size(d71, reg));
 690	set_range(&compiz->vsize, 64, d71->max_vsize);
 691
 692	return 0;
 693}
 694
 695static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
 696					 u32 vsize_in, u32 hsize_out,
 697					 u32 vsize_out)
 698{
 699	u32 val = 0;
 700
 701	if (hsize_in <= hsize_out)
 702		val  |= 0x62;
 703	else if (hsize_in <= (hsize_out + hsize_out / 2))
 704		val |= 0x63;
 705	else if (hsize_in <= hsize_out * 2)
 706		val |= 0x64;
 707	else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
 708		val |= 0x65;
 709	else
 710		val |= 0x66;
 711
 712	if (vsize_in <= vsize_out)
 713		val  |= SC_VTSEL(0x6A);
 714	else if (vsize_in <= (vsize_out + vsize_out / 2))
 715		val |= SC_VTSEL(0x6B);
 716	else if (vsize_in <= vsize_out * 2)
 717		val |= SC_VTSEL(0x6C);
 718	else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
 719		val |= SC_VTSEL(0x6D);
 720	else
 721		val |= SC_VTSEL(0x6E);
 722
 723	malidp_write32(reg, SC_COEFFTAB, val);
 724}
 725
 726static void d71_scaler_update(struct komeda_component *c,
 727			      struct komeda_component_state *state)
 728{
 729	struct komeda_scaler_state *st = to_scaler_st(state);
 730	u32 __iomem *reg = c->reg;
 731	u32 init_ph, delta_ph, ctrl;
 732
 733	d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
 734				     st->hsize_out, st->vsize_out);
 735
 736	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
 737	malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
 738	malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));
 739
 740	/* for right part, HW only sample the valid pixel which means the pixels
 741	 * in left_crop will be jumpped, and the first sample pixel is:
 742	 *
 743	 * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;
 744	 *
 745	 * Then the corresponding texel in src is:
 746	 *
 747	 * h_delta_phase = st->total_hsize_in / st->total_hsize_out;
 748	 * src_a = dst_A * h_delta_phase;
 749	 *
 750	 * and h_init_phase is src_a deduct the real source start src_S;
 751	 *
 752	 * src_S = st->total_hsize_in - st->hsize_in;
 753	 * h_init_phase = src_a - src_S;
 754	 *
 755	 * And HW precision for the initial/delta_phase is 16:16 fixed point,
 756	 * the following is the simplified formula
 757	 */
 758	if (st->right_part) {
 759		u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;
 760
 761		if (st->en_img_enhancement)
 762			dst_a -= 1;
 763
 764		init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -
 765			    2 * st->total_hsize_out * (st->total_hsize_in -
 766			    st->hsize_in)) << 15) / st->total_hsize_out;
 767	} else {
 768		init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;
 769	}
 770
 771	malidp_write32(reg, SC_H_INIT_PH, init_ph);
 772
 773	delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;
 774	malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
 775
 776	init_ph = (st->total_vsize_in << 15) / st->vsize_out;
 777	malidp_write32(reg, SC_V_INIT_PH, init_ph);
 778
 779	delta_ph = (st->total_vsize_in << 16) / st->vsize_out;
 780	malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
 781
 782	ctrl = 0;
 783	ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
 784	ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
 785	ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
 786	/* If we use the hardware splitter we shouldn't set SC_CTRL_LS */
 787	if (st->en_split &&
 788	    state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)
 789		ctrl |= SC_CTRL_LS;
 790
 791	malidp_write32(reg, BLK_CONTROL, ctrl);
 792	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 793}
 794
 795static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
 796{
 797	u32 v[10];
 798
 799	dump_block_header(sf, c->reg);
 800
 801	get_values_from_reg(c->reg, 0x80, 1, v);
 802	seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
 803
 804	get_values_from_reg(c->reg, 0xD0, 1, v);
 805	seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
 806
 807	get_values_from_reg(c->reg, 0xDC, 9, v);
 808	seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
 809	seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
 810	seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
 811	seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
 812	seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
 813	seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
 814	seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
 815	seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
 816	seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
 817
 818	get_values_from_reg(c->reg, 0x130, 10, v);
 819	seq_printf(sf, "SC_ENH_LIMITS:\t\t0x%X\n", v[0]);
 820	seq_printf(sf, "SC_ENH_COEFF0:\t\t0x%X\n", v[1]);
 821	seq_printf(sf, "SC_ENH_COEFF1:\t\t0x%X\n", v[2]);
 822	seq_printf(sf, "SC_ENH_COEFF2:\t\t0x%X\n", v[3]);
 823	seq_printf(sf, "SC_ENH_COEFF3:\t\t0x%X\n", v[4]);
 824	seq_printf(sf, "SC_ENH_COEFF4:\t\t0x%X\n", v[5]);
 825	seq_printf(sf, "SC_ENH_COEFF5:\t\t0x%X\n", v[6]);
 826	seq_printf(sf, "SC_ENH_COEFF6:\t\t0x%X\n", v[7]);
 827	seq_printf(sf, "SC_ENH_COEFF7:\t\t0x%X\n", v[8]);
 828	seq_printf(sf, "SC_ENH_COEFF8:\t\t0x%X\n", v[9]);
 829}
 830
 831static const struct komeda_component_funcs d71_scaler_funcs = {
 832	.update		= d71_scaler_update,
 833	.disable	= d71_component_disable,
 834	.dump_register	= d71_scaler_dump,
 835};
 836
 837static int d71_scaler_init(struct d71_dev *d71,
 838			   struct block_header *blk, u32 __iomem *reg)
 839{
 840	struct komeda_component *c;
 841	struct komeda_scaler *scaler;
 842	u32 pipe_id, comp_id;
 843
 844	get_resources_id(blk->block_info, &pipe_id, &comp_id);
 845
 846	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
 847				 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
 848				 &d71_scaler_funcs,
 849				 1, get_valid_inputs(blk), 1, reg,
 850				 "CU%d_SCALER%d",
 851				 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
 852
 853	if (IS_ERR(c)) {
 854		DRM_ERROR("Failed to initialize scaler");
 855		return PTR_ERR(c);
 856	}
 857
 858	scaler = to_scaler(c);
 859	set_range(&scaler->hsize, 4, __get_blk_line_size(d71, reg, 2048));
 860	set_range(&scaler->vsize, 4, 4096);
 861	scaler->max_downscaling = 6;
 862	scaler->max_upscaling = 64;
 863	scaler->scaling_split_overlap = 8;
 864	scaler->enh_split_overlap = 1;
 865
 866	malidp_write32(c->reg, BLK_CONTROL, 0);
 867
 868	return 0;
 869}
 870
 871static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
 872				     struct drm_display_mode *mode,
 873				     unsigned long aclk_rate,
 874				     struct komeda_data_flow_cfg *dflow)
 875{
 876	u32 h_in = dflow->in_w;
 877	u32 v_in = dflow->in_h;
 878	u32 v_out = dflow->out_h;
 879	u64 fraction, denominator;
 880
 881	/* D71 downscaling must satisfy the following equation
 882	 *
 883	 *   ACLK                   h_in * v_in
 884	 * ------- >= ---------------------------------------------
 885	 *  PXLCLK     (h_total - (1 + 2 * v_in / v_out)) * v_out
 886	 *
 887	 * In only horizontal downscaling situation, the right side should be
 888	 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
 889	 *
 890	 *   ACLK          h_in
 891	 * ------- >= ----------------
 892	 *  PXLCLK     (h_active - 3)
 893	 *
 894	 * To avoid precision lost the equation 1 will be convert to:
 895	 *
 896	 *   ACLK             h_in * v_in
 897	 * ------- >= -----------------------------------
 898	 *  PXLCLK     (h_total -1 ) * v_out -  2 * v_in
 899	 */
 900	if (v_in == v_out) {
 901		fraction = h_in;
 902		denominator = mode->hdisplay - 3;
 903	} else {
 904		fraction = h_in * v_in;
 905		denominator = (mode->htotal - 1) * v_out -  2 * v_in;
 906	}
 907
 908	return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?
 909	       0 : -EINVAL;
 910}
 911
 912static void d71_splitter_update(struct komeda_component *c,
 913				struct komeda_component_state *state)
 914{
 915	struct komeda_splitter_state *st = to_splitter_st(state);
 916	u32 __iomem *reg = c->reg;
 917
 918	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
 919	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 920	malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF);
 921	malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
 922}
 923
 924static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf)
 925{
 926	u32 v[3];
 927
 928	dump_block_header(sf, c->reg);
 929
 930	get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v);
 931	seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]);
 932
 933	get_values_from_reg(c->reg, BLK_CONTROL, 3, v);
 934	seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]);
 935	seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]);
 936	seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]);
 937}
 938
 939static const struct komeda_component_funcs d71_splitter_funcs = {
 940	.update		= d71_splitter_update,
 941	.disable	= d71_component_disable,
 942	.dump_register	= d71_splitter_dump,
 943};
 944
 945static int d71_splitter_init(struct d71_dev *d71,
 946			     struct block_header *blk, u32 __iomem *reg)
 947{
 948	struct komeda_component *c;
 949	struct komeda_splitter *splitter;
 950	u32 pipe_id, comp_id;
 951
 952	get_resources_id(blk->block_info, &pipe_id, &comp_id);
 953
 954	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*splitter),
 955				 comp_id,
 956				 BLOCK_INFO_INPUT_ID(blk->block_info),
 957				 &d71_splitter_funcs,
 958				 1, get_valid_inputs(blk), 2, reg,
 959				 "CU%d_SPLITTER", pipe_id);
 960
 961	if (IS_ERR(c)) {
 962		DRM_ERROR("Failed to initialize splitter");
 963		return -1;
 964	}
 965
 966	splitter = to_splitter(c);
 967
 968	set_range(&splitter->hsize, 4, get_blk_line_size(d71, reg));
 969	set_range(&splitter->vsize, 4, d71->max_vsize);
 970
 971	return 0;
 972}
 973
 974static void d71_merger_update(struct komeda_component *c,
 975			      struct komeda_component_state *state)
 976{
 977	struct komeda_merger_state *st = to_merger_st(state);
 978	u32 __iomem *reg = c->reg;
 979	u32 index;
 980
 981	for_each_changed_input(state, index)
 982		malidp_write32(reg, MG_INPUT_ID0 + index * 4,
 983			       to_d71_input_id(state, index));
 984
 985	malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,
 986					     st->vsize_merged));
 987	malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
 988}
 989
 990static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)
 991{
 992	u32 v;
 993
 994	dump_block_header(sf, c->reg);
 995
 996	get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);
 997	seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);
 998
 999	get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);
1000	seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);
1001
1002	get_values_from_reg(c->reg, BLK_CONTROL, 1, &v);
1003	seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v);
1004
1005	get_values_from_reg(c->reg, MG_SIZE, 1, &v);
1006	seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v);
1007}
1008
1009static const struct komeda_component_funcs d71_merger_funcs = {
1010	.update		= d71_merger_update,
1011	.disable	= d71_component_disable,
1012	.dump_register	= d71_merger_dump,
1013};
1014
1015static int d71_merger_init(struct d71_dev *d71,
1016			   struct block_header *blk, u32 __iomem *reg)
1017{
1018	struct komeda_component *c;
1019	struct komeda_merger *merger;
1020	u32 pipe_id, comp_id;
1021
1022	get_resources_id(blk->block_info, &pipe_id, &comp_id);
1023
1024	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger),
1025				 comp_id,
1026				 BLOCK_INFO_INPUT_ID(blk->block_info),
1027				 &d71_merger_funcs,
1028				 MG_NUM_INPUTS_IDS, get_valid_inputs(blk),
1029				 MG_NUM_OUTPUTS_IDS, reg,
1030				 "CU%d_MERGER", pipe_id);
1031
1032	if (IS_ERR(c)) {
1033		DRM_ERROR("Failed to initialize merger.\n");
1034		return PTR_ERR(c);
1035	}
1036
1037	merger = to_merger(c);
1038
1039	set_range(&merger->hsize_merged, 4,
1040		  __get_blk_line_size(d71, reg, 4032));
1041	set_range(&merger->vsize_merged, 4, 4096);
1042
1043	return 0;
1044}
1045
1046static void d71_improc_update(struct komeda_component *c,
1047			      struct komeda_component_state *state)
1048{
1049	struct drm_crtc_state *crtc_st = state->crtc->state;
1050	struct komeda_improc_state *st = to_improc_st(state);
1051	struct d71_pipeline *pipe = to_d71_pipeline(c->pipeline);
1052	u32 __iomem *reg = c->reg;
1053	u32 index, mask = 0, ctrl = 0;
1054
1055	for_each_changed_input(state, index)
1056		malidp_write32(reg, BLK_INPUT_ID0 + index * 4,
1057			       to_d71_input_id(state, index));
1058
1059	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
1060	malidp_write32(reg, IPS_DEPTH, st->color_depth);
1061
1062	if (crtc_st->color_mgmt_changed) {
1063		mask |= IPS_CTRL_FT | IPS_CTRL_RGB;
1064
1065		if (crtc_st->gamma_lut) {
1066			malidp_write_group(pipe->dou_ft_coeff_addr, FT_COEFF0,
1067					   KOMEDA_N_GAMMA_COEFFS,
1068					   st->fgamma_coeffs);
1069			ctrl |= IPS_CTRL_FT; /* enable gamma */
1070		}
1071
1072		if (crtc_st->ctm) {
1073			malidp_write_group(reg, IPS_RGB_RGB_COEFF0,
1074					   KOMEDA_N_CTM_COEFFS,
1075					   st->ctm_coeffs);
1076			ctrl |= IPS_CTRL_RGB; /* enable gamut */
1077		}
1078	}
1079
1080	mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;
1081
1082	/* config color format */
1083	if (st->color_format == DRM_COLOR_FORMAT_YCBCR420)
1084		ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420;
1085	else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422)
1086		ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422;
1087	else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444)
1088		ctrl |= IPS_CTRL_YUV;
1089
1090	malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
1091}
1092
1093static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
1094{
1095	u32 v[12], i;
1096
1097	dump_block_header(sf, c->reg);
1098
1099	get_values_from_reg(c->reg, 0x80, 2, v);
1100	seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
1101	seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
1102
1103	get_values_from_reg(c->reg, 0xC0, 1, v);
1104	seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
1105
1106	get_values_from_reg(c->reg, 0xD0, 3, v);
1107	seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
1108	seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
1109	seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
1110
1111	get_values_from_reg(c->reg, 0x130, 12, v);
1112	for (i = 0; i < 12; i++)
1113		seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
1114
1115	get_values_from_reg(c->reg, 0x170, 12, v);
1116	for (i = 0; i < 12; i++)
1117		seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
1118}
1119
1120static const struct komeda_component_funcs d71_improc_funcs = {
1121	.update		= d71_improc_update,
1122	.disable	= d71_component_disable,
1123	.dump_register	= d71_improc_dump,
1124};
1125
1126static int d71_improc_init(struct d71_dev *d71,
1127			   struct block_header *blk, u32 __iomem *reg)
1128{
1129	struct komeda_component *c;
1130	struct komeda_improc *improc;
1131	u32 pipe_id, comp_id, value;
1132
1133	get_resources_id(blk->block_info, &pipe_id, &comp_id);
1134
1135	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
1136				 comp_id,
1137				 BLOCK_INFO_INPUT_ID(blk->block_info),
1138				 &d71_improc_funcs, IPS_NUM_INPUT_IDS,
1139				 get_valid_inputs(blk),
1140				 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
1141	if (IS_ERR(c)) {
1142		DRM_ERROR("Failed to add improc component\n");
1143		return PTR_ERR(c);
1144	}
1145
1146	improc = to_improc(c);
1147	improc->supported_color_depths = BIT(8) | BIT(10);
1148	improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
1149					  DRM_COLOR_FORMAT_YCBCR444 |
1150					  DRM_COLOR_FORMAT_YCBCR422;
1151	value = malidp_read32(reg, BLK_INFO);
1152	if (value & IPS_INFO_CHD420)
1153		improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420;
1154
1155	improc->supports_csc = true;
1156	improc->supports_gamma = true;
1157
1158	return 0;
1159}
1160
1161static void d71_timing_ctrlr_disable(struct komeda_component *c)
1162{
1163	malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
1164}
1165
1166static void d71_timing_ctrlr_update(struct komeda_component *c,
1167				    struct komeda_component_state *state)
1168{
1169	struct drm_crtc_state *crtc_st = state->crtc->state;
1170	struct drm_display_mode *mode = &crtc_st->adjusted_mode;
1171	u32 __iomem *reg = c->reg;
1172	u32 hactive, hfront_porch, hback_porch, hsync_len;
1173	u32 vactive, vfront_porch, vback_porch, vsync_len;
1174	u32 value;
1175
1176	hactive = mode->crtc_hdisplay;
1177	hfront_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;
1178	hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
1179	hback_porch = mode->crtc_htotal - mode->crtc_hsync_end;
1180
1181	vactive = mode->crtc_vdisplay;
1182	vfront_porch = mode->crtc_vsync_start - mode->crtc_vdisplay;
1183	vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
1184	vback_porch = mode->crtc_vtotal - mode->crtc_vsync_end;
1185
1186	malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(hactive, vactive));
1187	malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(hfront_porch,
1188							hback_porch));
1189	malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vfront_porch,
1190							vback_porch));
1191
1192	value = BS_SYNC_VSW(vsync_len) | BS_SYNC_HSW(hsync_len);
1193	value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BS_SYNC_VSP : 0;
1194	value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BS_SYNC_HSP : 0;
1195	malidp_write32(reg, BS_SYNC, value);
1196
1197	malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
1198	malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
1199
1200	/* configure bs control register */
1201	value = BS_CTRL_EN | BS_CTRL_VM;
1202	if (c->pipeline->dual_link) {
1203		malidp_write32(reg, BS_DRIFT_TO, hfront_porch + 16);
1204		value |= BS_CTRL_DL;
1205	}
1206
1207	malidp_write32(reg, BLK_CONTROL, value);
1208}
1209
1210static void d71_timing_ctrlr_dump(struct komeda_component *c,
1211				  struct seq_file *sf)
1212{
1213	u32 v[8], i;
1214
1215	dump_block_header(sf, c->reg);
1216
1217	get_values_from_reg(c->reg, 0xC0, 1, v);
1218	seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
1219
1220	get_values_from_reg(c->reg, 0xD0, 8, v);
1221	seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
1222	seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
1223	seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
1224	seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
1225	seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
1226	seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
1227	seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
1228	seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
1229
1230	get_values_from_reg(c->reg, 0x100, 3, v);
1231	seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
1232	seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
1233	seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
1234
1235	get_values_from_reg(c->reg, 0x110, 3, v);
1236	for (i = 0; i < 3; i++)
1237		seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
1238
1239	get_values_from_reg(c->reg, 0x120, 5, v);
1240	for (i = 0; i < 2; i++) {
1241		seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
1242		seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
1243	}
1244	seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
1245}
1246
1247static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
1248	.update		= d71_timing_ctrlr_update,
1249	.disable	= d71_timing_ctrlr_disable,
1250	.dump_register	= d71_timing_ctrlr_dump,
1251};
1252
1253static int d71_timing_ctrlr_init(struct d71_dev *d71,
1254				 struct block_header *blk, u32 __iomem *reg)
1255{
1256	struct komeda_component *c;
1257	struct komeda_timing_ctrlr *ctrlr;
1258	u32 pipe_id, comp_id;
1259
1260	get_resources_id(blk->block_info, &pipe_id, &comp_id);
1261
1262	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
1263				 KOMEDA_COMPONENT_TIMING_CTRLR,
1264				 BLOCK_INFO_INPUT_ID(blk->block_info),
1265				 &d71_timing_ctrlr_funcs,
1266				 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
1267				 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
1268	if (IS_ERR(c)) {
1269		DRM_ERROR("Failed to add display_ctrl component\n");
1270		return PTR_ERR(c);
1271	}
1272
1273	ctrlr = to_ctrlr(c);
1274
1275	ctrlr->supports_dual_link = d71->supports_dual_link;
1276
1277	return 0;
1278}
1279
1280int d71_probe_block(struct d71_dev *d71,
1281		    struct block_header *blk, u32 __iomem *reg)
1282{
1283	struct d71_pipeline *pipe;
1284	int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
1285
1286	int err = 0;
1287
1288	switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
1289	case D71_BLK_TYPE_GCU:
1290		break;
1291
1292	case D71_BLK_TYPE_LPU:
1293		pipe = d71->pipes[blk_id];
1294		pipe->lpu_addr = reg;
1295		break;
1296
1297	case D71_BLK_TYPE_LPU_LAYER:
1298		err = d71_layer_init(d71, blk, reg);
1299		break;
1300
1301	case D71_BLK_TYPE_LPU_WB_LAYER:
1302		err = d71_wb_layer_init(d71, blk, reg);
1303		break;
1304
1305	case D71_BLK_TYPE_CU:
1306		pipe = d71->pipes[blk_id];
1307		pipe->cu_addr = reg;
1308		err = d71_compiz_init(d71, blk, reg);
1309		break;
1310
1311	case D71_BLK_TYPE_CU_SCALER:
1312		err = d71_scaler_init(d71, blk, reg);
1313		break;
1314
1315	case D71_BLK_TYPE_CU_SPLITTER:
1316		err = d71_splitter_init(d71, blk, reg);
1317		break;
1318
1319	case D71_BLK_TYPE_CU_MERGER:
1320		err = d71_merger_init(d71, blk, reg);
1321		break;
1322
1323	case D71_BLK_TYPE_DOU:
1324		pipe = d71->pipes[blk_id];
1325		pipe->dou_addr = reg;
1326		break;
1327
1328	case D71_BLK_TYPE_DOU_IPS:
1329		err = d71_improc_init(d71, blk, reg);
1330		break;
1331
1332	case D71_BLK_TYPE_DOU_FT_COEFF:
1333		pipe = d71->pipes[blk_id];
1334		pipe->dou_ft_coeff_addr = reg;
1335		break;
1336
1337	case D71_BLK_TYPE_DOU_BS:
1338		err = d71_timing_ctrlr_init(d71, blk, reg);
1339		break;
1340
1341	case D71_BLK_TYPE_GLB_LT_COEFF:
1342		break;
1343
1344	case D71_BLK_TYPE_GLB_SCL_COEFF:
1345		d71->glb_scl_coeff_addr[blk_id] = reg;
1346		break;
1347
1348	default:
1349		DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
1350			  blk->block_info);
1351		err = -EINVAL;
1352		break;
1353	}
1354
1355	return err;
1356}
1357
1358static void d71_gcu_dump(struct d71_dev *d71, struct seq_file *sf)
1359{
1360	u32 v[5];
1361
1362	seq_puts(sf, "\n------ GCU ------\n");
1363
1364	get_values_from_reg(d71->gcu_addr, 0, 3, v);
1365	seq_printf(sf, "GLB_ARCH_ID:\t\t0x%X\n", v[0]);
1366	seq_printf(sf, "GLB_CORE_ID:\t\t0x%X\n", v[1]);
1367	seq_printf(sf, "GLB_CORE_INFO:\t\t0x%X\n", v[2]);
1368
1369	get_values_from_reg(d71->gcu_addr, 0x10, 1, v);
1370	seq_printf(sf, "GLB_IRQ_STATUS:\t\t0x%X\n", v[0]);
1371
1372	get_values_from_reg(d71->gcu_addr, 0xA0, 5, v);
1373	seq_printf(sf, "GCU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
1374	seq_printf(sf, "GCU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
1375	seq_printf(sf, "GCU_IRQ_MASK:\t\t0x%X\n", v[2]);
1376	seq_printf(sf, "GCU_IRQ_STATUS:\t\t0x%X\n", v[3]);
1377	seq_printf(sf, "GCU_STATUS:\t\t0x%X\n", v[4]);
1378
1379	get_values_from_reg(d71->gcu_addr, 0xD0, 3, v);
1380	seq_printf(sf, "GCU_CONTROL:\t\t0x%X\n", v[0]);
1381	seq_printf(sf, "GCU_CONFIG_VALID0:\t0x%X\n", v[1]);
1382	seq_printf(sf, "GCU_CONFIG_VALID1:\t0x%X\n", v[2]);
1383}
1384
1385static void d71_lpu_dump(struct d71_pipeline *pipe, struct seq_file *sf)
1386{
1387	u32 v[6];
1388
1389	seq_printf(sf, "\n------ LPU%d ------\n", pipe->base.id);
1390
1391	dump_block_header(sf, pipe->lpu_addr);
1392
1393	get_values_from_reg(pipe->lpu_addr, 0xA0, 6, v);
1394	seq_printf(sf, "LPU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
1395	seq_printf(sf, "LPU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
1396	seq_printf(sf, "LPU_IRQ_MASK:\t\t0x%X\n", v[2]);
1397	seq_printf(sf, "LPU_IRQ_STATUS:\t\t0x%X\n", v[3]);
1398	seq_printf(sf, "LPU_STATUS:\t\t0x%X\n", v[4]);
1399	seq_printf(sf, "LPU_TBU_STATUS:\t\t0x%X\n", v[5]);
1400
1401	get_values_from_reg(pipe->lpu_addr, 0xC0, 1, v);
1402	seq_printf(sf, "LPU_INFO:\t\t0x%X\n", v[0]);
1403
1404	get_values_from_reg(pipe->lpu_addr, 0xD0, 3, v);
1405	seq_printf(sf, "LPU_RAXI_CONTROL:\t0x%X\n", v[0]);
1406	seq_printf(sf, "LPU_WAXI_CONTROL:\t0x%X\n", v[1]);
1407	seq_printf(sf, "LPU_TBU_CONTROL:\t0x%X\n", v[2]);
1408}
1409
1410static void d71_dou_dump(struct d71_pipeline *pipe, struct seq_file *sf)
1411{
1412	u32 v[5];
1413
1414	seq_printf(sf, "\n------ DOU%d ------\n", pipe->base.id);
1415
1416	dump_block_header(sf, pipe->dou_addr);
1417
1418	get_values_from_reg(pipe->dou_addr, 0xA0, 5, v);
1419	seq_printf(sf, "DOU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
1420	seq_printf(sf, "DOU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
1421	seq_printf(sf, "DOU_IRQ_MASK:\t\t0x%X\n", v[2]);
1422	seq_printf(sf, "DOU_IRQ_STATUS:\t\t0x%X\n", v[3]);
1423	seq_printf(sf, "DOU_STATUS:\t\t0x%X\n", v[4]);
1424}
1425
1426static void d71_pipeline_dump(struct komeda_pipeline *pipe, struct seq_file *sf)
1427{
1428	struct d71_pipeline *d71_pipe = to_d71_pipeline(pipe);
1429
1430	d71_lpu_dump(d71_pipe, sf);
1431	d71_dou_dump(d71_pipe, sf);
1432}
1433
1434const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1435	.downscaling_clk_check	= d71_downscaling_clk_check,
1436	.dump_register		= d71_pipeline_dump,
1437};
1438
1439void d71_dump(struct komeda_dev *mdev, struct seq_file *sf)
1440{
1441	struct d71_dev *d71 = mdev->chip_data;
1442
1443	d71_gcu_dump(d71, sf);
1444}
~/ Read-only file preview.