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