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 static u32 to_rot_ctrl(u32 rot)
110 {
111 	u32 lr_ctrl = 0;
112 
113 	switch (rot & DRM_MODE_ROTATE_MASK) {
114 	case DRM_MODE_ROTATE_0:
115 		lr_ctrl |= L_ROT(L_ROT_R0);
116 		break;
117 	case DRM_MODE_ROTATE_90:
118 		lr_ctrl |= L_ROT(L_ROT_R90);
119 		break;
120 	case DRM_MODE_ROTATE_180:
121 		lr_ctrl |= L_ROT(L_ROT_R180);
122 		break;
123 	case DRM_MODE_ROTATE_270:
124 		lr_ctrl |= L_ROT(L_ROT_R270);
125 		break;
126 	}
127 
128 	if (rot & DRM_MODE_REFLECT_X)
129 		lr_ctrl |= L_HFLIP;
130 	if (rot & DRM_MODE_REFLECT_Y)
131 		lr_ctrl |= L_VFLIP;
132 
133 	return lr_ctrl;
134 }
135 
136 static u32 to_ad_ctrl(u64 modifier)
137 {
138 	u32 afbc_ctrl = AD_AEN;
139 
140 	if (!modifier)
141 		return 0;
142 
143 	if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
144 	    AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
145 		afbc_ctrl |= AD_WB;
146 
147 	if (modifier & AFBC_FORMAT_MOD_YTR)
148 		afbc_ctrl |= AD_YT;
149 	if (modifier & AFBC_FORMAT_MOD_SPLIT)
150 		afbc_ctrl |= AD_BS;
151 	if (modifier & AFBC_FORMAT_MOD_TILED)
152 		afbc_ctrl |= AD_TH;
153 
154 	return afbc_ctrl;
155 }
156 
157 static inline u32 to_d71_input_id(struct komeda_component_state *st, int idx)
158 {
159 	struct komeda_component_output *input = &st->inputs[idx];
160 
161 	/* if input is not active, set hw input_id(0) to disable it */
162 	if (has_bit(idx, st->active_inputs))
163 		return input->component->hw_id + input->output_port;
164 	else
165 		return 0;
166 }
167 
168 static void d71_layer_update_fb(struct komeda_component *c,
169 				struct komeda_fb *kfb,
170 				dma_addr_t *addr)
171 {
172 	struct drm_framebuffer *fb = &kfb->base;
173 	const struct drm_format_info *info = fb->format;
174 	u32 __iomem *reg = c->reg;
175 	int block_h;
176 
177 	if (info->num_planes > 2)
178 		malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);
179 
180 	if (info->num_planes > 1) {
181 		block_h = drm_format_info_block_height(info, 1);
182 		malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);
183 		malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);
184 	}
185 
186 	block_h = drm_format_info_block_height(info, 0);
187 	malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);
188 	malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);
189 	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
190 }
191 
192 static void d71_layer_disable(struct komeda_component *c)
193 {
194 	malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
195 }
196 
197 static void d71_layer_update(struct komeda_component *c,
198 			     struct komeda_component_state *state)
199 {
200 	struct komeda_layer_state *st = to_layer_st(state);
201 	struct drm_plane_state *plane_st = state->plane->state;
202 	struct drm_framebuffer *fb = plane_st->fb;
203 	struct komeda_fb *kfb = to_kfb(fb);
204 	u32 __iomem *reg = c->reg;
205 	u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
206 	u32 ctrl = L_EN | to_rot_ctrl(st->rot);
207 
208 	d71_layer_update_fb(c, kfb, st->addr);
209 
210 	malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
211 	if (fb->modifier) {
212 		u64 addr;
213 
214 		malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
215 							     st->afbc_crop_r));
216 		malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
217 							     st->afbc_crop_b));
218 		/* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
219 		if (fb->modifier & AFBC_FORMAT_MOD_TILED)
220 			addr = st->addr[0] + kfb->offset_payload;
221 		else
222 			addr = st->addr[0] + kfb->afbc_size - 1;
223 
224 		malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
225 		malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
226 	}
227 
228 	if (fb->format->is_yuv) {
229 		u32 upsampling = 0;
230 
231 		switch (kfb->format_caps->fourcc) {
232 		case DRM_FORMAT_YUYV:
233 			upsampling = fb->modifier ? LR_CHI422_BILINEAR :
234 				     LR_CHI422_REPLICATION;
235 			break;
236 		case DRM_FORMAT_UYVY:
237 			upsampling = LR_CHI422_REPLICATION;
238 			break;
239 		case DRM_FORMAT_NV12:
240 		case DRM_FORMAT_YUV420_8BIT:
241 		case DRM_FORMAT_YUV420_10BIT:
242 		case DRM_FORMAT_YUV420:
243 		case DRM_FORMAT_P010:
244 		/* these fmt support MPGE/JPEG both, here perfer JPEG*/
245 			upsampling = LR_CHI420_JPEG;
246 			break;
247 		case DRM_FORMAT_X0L2:
248 			upsampling = LR_CHI420_JPEG;
249 			break;
250 		default:
251 			break;
252 		}
253 
254 		malidp_write32(reg, LAYER_R_CONTROL, upsampling);
255 		malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,
256 				   KOMEDA_N_YUV2RGB_COEFFS,
257 				   komeda_select_yuv2rgb_coeffs(
258 					plane_st->color_encoding,
259 					plane_st->color_range));
260 	}
261 
262 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
263 
264 	if (kfb->is_va)
265 		ctrl |= L_TBU_EN;
266 	malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
267 }
268 
269 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
270 {
271 	u32 v[15], i;
272 	bool rich, rgb2rgb;
273 	char *prefix;
274 
275 	get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
276 	if (v[14] & 0x1) {
277 		rich = true;
278 		prefix = "LR_";
279 	} else {
280 		rich = false;
281 		prefix = "LS_";
282 	}
283 
284 	rgb2rgb = !!(v[14] & L_INFO_CM);
285 
286 	dump_block_header(sf, c->reg);
287 
288 	seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
289 
290 	get_values_from_reg(c->reg, 0xD0, 1, v);
291 	seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
292 	if (rich) {
293 		get_values_from_reg(c->reg, 0xD4, 1, v);
294 		seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
295 	}
296 	get_values_from_reg(c->reg, 0xD8, 4, v);
297 	seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
298 	seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
299 	seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
300 	seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
301 
302 	get_values_from_reg(c->reg, 0x100, 3, v);
303 	seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
304 	seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
305 	seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
306 
307 	get_values_from_reg(c->reg, 0x110, 2, v);
308 	seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
309 	seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
310 	if (rich) {
311 		get_values_from_reg(c->reg, 0x118, 1, v);
312 		seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
313 
314 		get_values_from_reg(c->reg, 0x120, 2, v);
315 		seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
316 		seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
317 
318 		get_values_from_reg(c->reg, 0x130, 12, v);
319 		for (i = 0; i < 12; i++)
320 			seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
321 	}
322 
323 	if (rgb2rgb) {
324 		get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
325 		for (i = 0; i < 12; i++)
326 			seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
327 	}
328 
329 	get_values_from_reg(c->reg, 0x160, 3, v);
330 	seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
331 	seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
332 	seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
333 }
334 
335 static const struct komeda_component_funcs d71_layer_funcs = {
336 	.update		= d71_layer_update,
337 	.disable	= d71_layer_disable,
338 	.dump_register	= d71_layer_dump,
339 };
340 
341 static int d71_layer_init(struct d71_dev *d71,
342 			  struct block_header *blk, u32 __iomem *reg)
343 {
344 	struct komeda_component *c;
345 	struct komeda_layer *layer;
346 	u32 pipe_id, layer_id, layer_info;
347 
348 	get_resources_id(blk->block_info, &pipe_id, &layer_id);
349 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
350 				 layer_id,
351 				 BLOCK_INFO_INPUT_ID(blk->block_info),
352 				 &d71_layer_funcs, 0,
353 				 get_valid_inputs(blk),
354 				 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
355 	if (IS_ERR(c)) {
356 		DRM_ERROR("Failed to add layer component\n");
357 		return PTR_ERR(c);
358 	}
359 
360 	layer = to_layer(c);
361 	layer_info = malidp_read32(reg, LAYER_INFO);
362 
363 	if (layer_info & L_INFO_RF)
364 		layer->layer_type = KOMEDA_FMT_RICH_LAYER;
365 	else
366 		layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
367 
368 	set_range(&layer->hsize_in, 4, d71->max_line_size);
369 	set_range(&layer->vsize_in, 4, d71->max_vsize);
370 
371 	malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
372 
373 	layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
374 
375 	return 0;
376 }
377 
378 static void d71_wb_layer_update(struct komeda_component *c,
379 				struct komeda_component_state *state)
380 {
381 	struct komeda_layer_state *st = to_layer_st(state);
382 	struct drm_connector_state *conn_st = state->wb_conn->state;
383 	struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
384 	u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
385 	u32 __iomem *reg = c->reg;
386 
387 	d71_layer_update_fb(c, kfb, st->addr);
388 
389 	if (kfb->is_va)
390 		ctrl |= LW_TBU_EN;
391 
392 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
393 	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
394 	malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
395 }
396 
397 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
398 {
399 	u32 v[12], i;
400 
401 	dump_block_header(sf, c->reg);
402 
403 	get_values_from_reg(c->reg, 0x80, 1, v);
404 	seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
405 
406 	get_values_from_reg(c->reg, 0xD0, 3, v);
407 	seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
408 	seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
409 	seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
410 
411 	get_values_from_reg(c->reg, 0xE0, 1, v);
412 	seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
413 
414 	for (i = 0; i < 2; i++) {
415 		get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
416 		seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
417 		seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
418 		seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
419 	}
420 
421 	get_values_from_reg(c->reg, 0x130, 12, v);
422 	for (i = 0; i < 12; i++)
423 		seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
424 }
425 
426 static void d71_wb_layer_disable(struct komeda_component *c)
427 {
428 	malidp_write32(c->reg, BLK_INPUT_ID0, 0);
429 	malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
430 }
431 
432 static const struct komeda_component_funcs d71_wb_layer_funcs = {
433 	.update		= d71_wb_layer_update,
434 	.disable	= d71_wb_layer_disable,
435 	.dump_register	= d71_wb_layer_dump,
436 };
437 
438 static int d71_wb_layer_init(struct d71_dev *d71,
439 			     struct block_header *blk, u32 __iomem *reg)
440 {
441 	struct komeda_component *c;
442 	struct komeda_layer *wb_layer;
443 	u32 pipe_id, layer_id;
444 
445 	get_resources_id(blk->block_info, &pipe_id, &layer_id);
446 
447 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
448 				 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
449 				 &d71_wb_layer_funcs,
450 				 1, get_valid_inputs(blk), 0, reg,
451 				 "LPU%d_LAYER_WR", pipe_id);
452 	if (IS_ERR(c)) {
453 		DRM_ERROR("Failed to add wb_layer component\n");
454 		return PTR_ERR(c);
455 	}
456 
457 	wb_layer = to_layer(c);
458 	wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
459 
460 	set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size);
461 	set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
462 
463 	return 0;
464 }
465 
466 static void d71_component_disable(struct komeda_component *c)
467 {
468 	u32 __iomem *reg = c->reg;
469 	u32 i;
470 
471 	malidp_write32(reg, BLK_CONTROL, 0);
472 
473 	for (i = 0; i < c->max_active_inputs; i++) {
474 		malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
475 
476 		/* Besides clearing the input ID to zero, D71 compiz also has
477 		 * input enable bit in CU_INPUTx_CONTROL which need to be
478 		 * cleared.
479 		 */
480 		if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))
481 			malidp_write32(reg, CU_INPUT0_CONTROL +
482 				       i * CU_PER_INPUT_REGS * 4,
483 				       CU_INPUT_CTRL_ALPHA(0xFF));
484 	}
485 }
486 
487 static void compiz_enable_input(u32 __iomem *id_reg,
488 				u32 __iomem *cfg_reg,
489 				u32 input_hw_id,
490 				struct komeda_compiz_input_cfg *cin)
491 {
492 	u32 ctrl = CU_INPUT_CTRL_EN;
493 	u8 blend = cin->pixel_blend_mode;
494 
495 	if (blend == DRM_MODE_BLEND_PIXEL_NONE)
496 		ctrl |= CU_INPUT_CTRL_PAD;
497 	else if (blend == DRM_MODE_BLEND_PREMULTI)
498 		ctrl |= CU_INPUT_CTRL_PMUL;
499 
500 	ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
501 
502 	malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
503 
504 	malidp_write32(cfg_reg, CU_INPUT0_SIZE,
505 		       HV_SIZE(cin->hsize, cin->vsize));
506 	malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
507 		       HV_OFFSET(cin->hoffset, cin->voffset));
508 	malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
509 }
510 
511 static void d71_compiz_update(struct komeda_component *c,
512 			      struct komeda_component_state *state)
513 {
514 	struct komeda_compiz_state *st = to_compiz_st(state);
515 	u32 __iomem *reg = c->reg;
516 	u32 __iomem *id_reg, *cfg_reg;
517 	u32 index;
518 
519 	for_each_changed_input(state, index) {
520 		id_reg = reg + index;
521 		cfg_reg = reg + index * CU_PER_INPUT_REGS;
522 		if (state->active_inputs & BIT(index)) {
523 			compiz_enable_input(id_reg, cfg_reg,
524 					    to_d71_input_id(state, index),
525 					    &st->cins[index]);
526 		} else {
527 			malidp_write32(id_reg, BLK_INPUT_ID0, 0);
528 			malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
529 		}
530 	}
531 
532 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
533 }
534 
535 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
536 {
537 	u32 v[8], i;
538 
539 	dump_block_header(sf, c->reg);
540 
541 	get_values_from_reg(c->reg, 0x80, 5, v);
542 	for (i = 0; i < 5; i++)
543 		seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
544 
545 	get_values_from_reg(c->reg, 0xA0, 5, v);
546 	seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
547 	seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
548 	seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
549 	seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
550 	seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
551 
552 	get_values_from_reg(c->reg, 0xD0, 2, v);
553 	seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
554 	seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
555 
556 	get_values_from_reg(c->reg, 0xDC, 1, v);
557 	seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
558 
559 	for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
560 		get_values_from_reg(c->reg, v[4], 3, v);
561 		seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
562 		seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
563 		seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
564 	}
565 
566 	get_values_from_reg(c->reg, 0x130, 2, v);
567 	seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
568 	seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
569 }
570 
571 static const struct komeda_component_funcs d71_compiz_funcs = {
572 	.update		= d71_compiz_update,
573 	.disable	= d71_component_disable,
574 	.dump_register	= d71_compiz_dump,
575 };
576 
577 static int d71_compiz_init(struct d71_dev *d71,
578 			   struct block_header *blk, u32 __iomem *reg)
579 {
580 	struct komeda_component *c;
581 	struct komeda_compiz *compiz;
582 	u32 pipe_id, comp_id;
583 
584 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
585 
586 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
587 				 comp_id,
588 				 BLOCK_INFO_INPUT_ID(blk->block_info),
589 				 &d71_compiz_funcs,
590 				 CU_NUM_INPUT_IDS, get_valid_inputs(blk),
591 				 CU_NUM_OUTPUT_IDS, reg,
592 				 "CU%d", pipe_id);
593 	if (IS_ERR(c))
594 		return PTR_ERR(c);
595 
596 	compiz = to_compiz(c);
597 
598 	set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
599 	set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
600 
601 	return 0;
602 }
603 
604 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
605 					 u32 vsize_in, u32 hsize_out,
606 					 u32 vsize_out)
607 {
608 	u32 val = 0;
609 
610 	if (hsize_in <= hsize_out)
611 		val  |= 0x62;
612 	else if (hsize_in <= (hsize_out + hsize_out / 2))
613 		val |= 0x63;
614 	else if (hsize_in <= hsize_out * 2)
615 		val |= 0x64;
616 	else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
617 		val |= 0x65;
618 	else
619 		val |= 0x66;
620 
621 	if (vsize_in <= vsize_out)
622 		val  |= SC_VTSEL(0x6A);
623 	else if (vsize_in <= (vsize_out + vsize_out / 2))
624 		val |= SC_VTSEL(0x6B);
625 	else if (vsize_in <= vsize_out * 2)
626 		val |= SC_VTSEL(0x6C);
627 	else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
628 		val |= SC_VTSEL(0x6D);
629 	else
630 		val |= SC_VTSEL(0x6E);
631 
632 	malidp_write32(reg, SC_COEFFTAB, val);
633 }
634 
635 static void d71_scaler_update(struct komeda_component *c,
636 			      struct komeda_component_state *state)
637 {
638 	struct komeda_scaler_state *st = to_scaler_st(state);
639 	u32 __iomem *reg = c->reg;
640 	u32 init_ph, delta_ph, ctrl;
641 
642 	d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
643 				     st->hsize_out, st->vsize_out);
644 
645 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
646 	malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
647 	malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop));
648 
649 	/* for right part, HW only sample the valid pixel which means the pixels
650 	 * in left_crop will be jumpped, and the first sample pixel is:
651 	 *
652 	 * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5;
653 	 *
654 	 * Then the corresponding texel in src is:
655 	 *
656 	 * h_delta_phase = st->total_hsize_in / st->total_hsize_out;
657 	 * src_a = dst_A * h_delta_phase;
658 	 *
659 	 * and h_init_phase is src_a deduct the real source start src_S;
660 	 *
661 	 * src_S = st->total_hsize_in - st->hsize_in;
662 	 * h_init_phase = src_a - src_S;
663 	 *
664 	 * And HW precision for the initial/delta_phase is 16:16 fixed point,
665 	 * the following is the simplified formula
666 	 */
667 	if (st->right_part) {
668 		u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop;
669 
670 		if (st->en_img_enhancement)
671 			dst_a -= 1;
672 
673 		init_ph = ((st->total_hsize_in * (2 * dst_a + 1) -
674 			    2 * st->total_hsize_out * (st->total_hsize_in -
675 			    st->hsize_in)) << 15) / st->total_hsize_out;
676 	} else {
677 		init_ph = (st->total_hsize_in << 15) / st->total_hsize_out;
678 	}
679 
680 	malidp_write32(reg, SC_H_INIT_PH, init_ph);
681 
682 	delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out;
683 	malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
684 
685 	init_ph = (st->total_vsize_in << 15) / st->vsize_out;
686 	malidp_write32(reg, SC_V_INIT_PH, init_ph);
687 
688 	delta_ph = (st->total_vsize_in << 16) / st->vsize_out;
689 	malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
690 
691 	ctrl = 0;
692 	ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
693 	ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
694 	ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
695 	/* If we use the hardware splitter we shouldn't set SC_CTRL_LS */
696 	if (st->en_split &&
697 	    state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER)
698 		ctrl |= SC_CTRL_LS;
699 
700 	malidp_write32(reg, BLK_CONTROL, ctrl);
701 	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
702 }
703 
704 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
705 {
706 	u32 v[9];
707 
708 	dump_block_header(sf, c->reg);
709 
710 	get_values_from_reg(c->reg, 0x80, 1, v);
711 	seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
712 
713 	get_values_from_reg(c->reg, 0xD0, 1, v);
714 	seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
715 
716 	get_values_from_reg(c->reg, 0xDC, 9, v);
717 	seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
718 	seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
719 	seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
720 	seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
721 	seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
722 	seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
723 	seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
724 	seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
725 	seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
726 }
727 
728 static const struct komeda_component_funcs d71_scaler_funcs = {
729 	.update		= d71_scaler_update,
730 	.disable	= d71_component_disable,
731 	.dump_register	= d71_scaler_dump,
732 };
733 
734 static int d71_scaler_init(struct d71_dev *d71,
735 			   struct block_header *blk, u32 __iomem *reg)
736 {
737 	struct komeda_component *c;
738 	struct komeda_scaler *scaler;
739 	u32 pipe_id, comp_id;
740 
741 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
742 
743 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
744 				 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
745 				 &d71_scaler_funcs,
746 				 1, get_valid_inputs(blk), 1, reg,
747 				 "CU%d_SCALER%d",
748 				 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
749 
750 	if (IS_ERR(c)) {
751 		DRM_ERROR("Failed to initialize scaler");
752 		return PTR_ERR(c);
753 	}
754 
755 	scaler = to_scaler(c);
756 	set_range(&scaler->hsize, 4, 2048);
757 	set_range(&scaler->vsize, 4, 4096);
758 	scaler->max_downscaling = 6;
759 	scaler->max_upscaling = 64;
760 	scaler->scaling_split_overlap = 8;
761 	scaler->enh_split_overlap = 1;
762 
763 	malidp_write32(c->reg, BLK_CONTROL, 0);
764 
765 	return 0;
766 }
767 
768 static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
769 				     struct drm_display_mode *mode,
770 				     unsigned long aclk_rate,
771 				     struct komeda_data_flow_cfg *dflow)
772 {
773 	u32 h_in = dflow->in_w;
774 	u32 v_in = dflow->in_h;
775 	u32 v_out = dflow->out_h;
776 	u64 fraction, denominator;
777 
778 	/* D71 downscaling must satisfy the following equation
779 	 *
780 	 *   ACLK                   h_in * v_in
781 	 * ------- >= ---------------------------------------------
782 	 *  PXLCLK     (h_total - (1 + 2 * v_in / v_out)) * v_out
783 	 *
784 	 * In only horizontal downscaling situation, the right side should be
785 	 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
786 	 *
787 	 *   ACLK          h_in
788 	 * ------- >= ----------------
789 	 *  PXLCLK     (h_active - 3)
790 	 *
791 	 * To avoid precision lost the equation 1 will be convert to:
792 	 *
793 	 *   ACLK             h_in * v_in
794 	 * ------- >= -----------------------------------
795 	 *  PXLCLK     (h_total -1 ) * v_out -  2 * v_in
796 	 */
797 	if (v_in == v_out) {
798 		fraction = h_in;
799 		denominator = mode->hdisplay - 3;
800 	} else {
801 		fraction = h_in * v_in;
802 		denominator = (mode->htotal - 1) * v_out -  2 * v_in;
803 	}
804 
805 	return aclk_rate * denominator >= mode->crtc_clock * 1000 * fraction ?
806 	       0 : -EINVAL;
807 }
808 
809 static void d71_splitter_update(struct komeda_component *c,
810 				struct komeda_component_state *state)
811 {
812 	struct komeda_splitter_state *st = to_splitter_st(state);
813 	u32 __iomem *reg = c->reg;
814 
815 	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0));
816 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
817 	malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF);
818 	malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
819 }
820 
821 static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf)
822 {
823 	u32 v[3];
824 
825 	dump_block_header(sf, c->reg);
826 
827 	get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v);
828 	seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]);
829 
830 	get_values_from_reg(c->reg, BLK_CONTROL, 3, v);
831 	seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]);
832 	seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]);
833 	seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]);
834 }
835 
836 static const struct komeda_component_funcs d71_splitter_funcs = {
837 	.update		= d71_splitter_update,
838 	.disable	= d71_component_disable,
839 	.dump_register	= d71_splitter_dump,
840 };
841 
842 static int d71_splitter_init(struct d71_dev *d71,
843 			     struct block_header *blk, u32 __iomem *reg)
844 {
845 	struct komeda_component *c;
846 	struct komeda_splitter *splitter;
847 	u32 pipe_id, comp_id;
848 
849 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
850 
851 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*splitter),
852 				 comp_id,
853 				 BLOCK_INFO_INPUT_ID(blk->block_info),
854 				 &d71_splitter_funcs,
855 				 1, get_valid_inputs(blk), 2, reg,
856 				 "CU%d_SPLITTER", pipe_id);
857 
858 	if (IS_ERR(c)) {
859 		DRM_ERROR("Failed to initialize splitter");
860 		return -1;
861 	}
862 
863 	splitter = to_splitter(c);
864 
865 	set_range(&splitter->hsize, 4, d71->max_line_size);
866 	set_range(&splitter->vsize, 4, d71->max_vsize);
867 
868 	return 0;
869 }
870 
871 static void d71_merger_update(struct komeda_component *c,
872 			      struct komeda_component_state *state)
873 {
874 	struct komeda_merger_state *st = to_merger_st(state);
875 	u32 __iomem *reg = c->reg;
876 	u32 index;
877 
878 	for_each_changed_input(state, index)
879 		malidp_write32(reg, MG_INPUT_ID0 + index * 4,
880 			       to_d71_input_id(state, index));
881 
882 	malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged,
883 					     st->vsize_merged));
884 	malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN);
885 }
886 
887 static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf)
888 {
889 	u32 v;
890 
891 	dump_block_header(sf, c->reg);
892 
893 	get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v);
894 	seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v);
895 
896 	get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v);
897 	seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v);
898 
899 	get_values_from_reg(c->reg, BLK_CONTROL, 1, &v);
900 	seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v);
901 
902 	get_values_from_reg(c->reg, MG_SIZE, 1, &v);
903 	seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v);
904 }
905 
906 static const struct komeda_component_funcs d71_merger_funcs = {
907 	.update		= d71_merger_update,
908 	.disable	= d71_component_disable,
909 	.dump_register	= d71_merger_dump,
910 };
911 
912 static int d71_merger_init(struct d71_dev *d71,
913 			   struct block_header *blk, u32 __iomem *reg)
914 {
915 	struct komeda_component *c;
916 	struct komeda_merger *merger;
917 	u32 pipe_id, comp_id;
918 
919 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
920 
921 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger),
922 				 comp_id,
923 				 BLOCK_INFO_INPUT_ID(blk->block_info),
924 				 &d71_merger_funcs,
925 				 MG_NUM_INPUTS_IDS, get_valid_inputs(blk),
926 				 MG_NUM_OUTPUTS_IDS, reg,
927 				 "CU%d_MERGER", pipe_id);
928 
929 	if (IS_ERR(c)) {
930 		DRM_ERROR("Failed to initialize merger.\n");
931 		return PTR_ERR(c);
932 	}
933 
934 	merger = to_merger(c);
935 
936 	set_range(&merger->hsize_merged, 4, 4032);
937 	set_range(&merger->vsize_merged, 4, 4096);
938 
939 	return 0;
940 }
941 
942 static void d71_improc_update(struct komeda_component *c,
943 			      struct komeda_component_state *state)
944 {
945 	struct komeda_improc_state *st = to_improc_st(state);
946 	u32 __iomem *reg = c->reg;
947 	u32 index;
948 
949 	for_each_changed_input(state, index)
950 		malidp_write32(reg, BLK_INPUT_ID0 + index * 4,
951 			       to_d71_input_id(state, index));
952 
953 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
954 }
955 
956 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
957 {
958 	u32 v[12], i;
959 
960 	dump_block_header(sf, c->reg);
961 
962 	get_values_from_reg(c->reg, 0x80, 2, v);
963 	seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
964 	seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
965 
966 	get_values_from_reg(c->reg, 0xC0, 1, v);
967 	seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
968 
969 	get_values_from_reg(c->reg, 0xD0, 3, v);
970 	seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
971 	seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
972 	seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
973 
974 	get_values_from_reg(c->reg, 0x130, 12, v);
975 	for (i = 0; i < 12; i++)
976 		seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
977 
978 	get_values_from_reg(c->reg, 0x170, 12, v);
979 	for (i = 0; i < 12; i++)
980 		seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
981 }
982 
983 static const struct komeda_component_funcs d71_improc_funcs = {
984 	.update		= d71_improc_update,
985 	.disable	= d71_component_disable,
986 	.dump_register	= d71_improc_dump,
987 };
988 
989 static int d71_improc_init(struct d71_dev *d71,
990 			   struct block_header *blk, u32 __iomem *reg)
991 {
992 	struct komeda_component *c;
993 	struct komeda_improc *improc;
994 	u32 pipe_id, comp_id, value;
995 
996 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
997 
998 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
999 				 comp_id,
1000 				 BLOCK_INFO_INPUT_ID(blk->block_info),
1001 				 &d71_improc_funcs, IPS_NUM_INPUT_IDS,
1002 				 get_valid_inputs(blk),
1003 				 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
1004 	if (IS_ERR(c)) {
1005 		DRM_ERROR("Failed to add improc component\n");
1006 		return PTR_ERR(c);
1007 	}
1008 
1009 	improc = to_improc(c);
1010 	improc->supported_color_depths = BIT(8) | BIT(10);
1011 	improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
1012 					  DRM_COLOR_FORMAT_YCRCB444 |
1013 					  DRM_COLOR_FORMAT_YCRCB422;
1014 	value = malidp_read32(reg, BLK_INFO);
1015 	if (value & IPS_INFO_CHD420)
1016 		improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
1017 
1018 	improc->supports_csc = true;
1019 	improc->supports_gamma = true;
1020 
1021 	return 0;
1022 }
1023 
1024 static void d71_timing_ctrlr_disable(struct komeda_component *c)
1025 {
1026 	malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
1027 }
1028 
1029 static void d71_timing_ctrlr_update(struct komeda_component *c,
1030 				    struct komeda_component_state *state)
1031 {
1032 	struct drm_crtc_state *crtc_st = state->crtc->state;
1033 	struct drm_display_mode *mode = &crtc_st->adjusted_mode;
1034 	u32 __iomem *reg = c->reg;
1035 	u32 hactive, hfront_porch, hback_porch, hsync_len;
1036 	u32 vactive, vfront_porch, vback_porch, vsync_len;
1037 	u32 value;
1038 
1039 	hactive = mode->crtc_hdisplay;
1040 	hfront_porch = mode->crtc_hsync_start - mode->crtc_hdisplay;
1041 	hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
1042 	hback_porch = mode->crtc_htotal - mode->crtc_hsync_end;
1043 
1044 	vactive = mode->crtc_vdisplay;
1045 	vfront_porch = mode->crtc_vsync_start - mode->crtc_vdisplay;
1046 	vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
1047 	vback_porch = mode->crtc_vtotal - mode->crtc_vsync_end;
1048 
1049 	malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(hactive, vactive));
1050 	malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(hfront_porch,
1051 							hback_porch));
1052 	malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vfront_porch,
1053 							vback_porch));
1054 
1055 	value = BS_SYNC_VSW(vsync_len) | BS_SYNC_HSW(hsync_len);
1056 	value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BS_SYNC_VSP : 0;
1057 	value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BS_SYNC_HSP : 0;
1058 	malidp_write32(reg, BS_SYNC, value);
1059 
1060 	malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
1061 	malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
1062 
1063 	/* configure bs control register */
1064 	value = BS_CTRL_EN | BS_CTRL_VM;
1065 	if (c->pipeline->dual_link) {
1066 		malidp_write32(reg, BS_DRIFT_TO, hfront_porch + 16);
1067 		value |= BS_CTRL_DL;
1068 	}
1069 
1070 	malidp_write32(reg, BLK_CONTROL, value);
1071 }
1072 
1073 static void d71_timing_ctrlr_dump(struct komeda_component *c,
1074 				  struct seq_file *sf)
1075 {
1076 	u32 v[8], i;
1077 
1078 	dump_block_header(sf, c->reg);
1079 
1080 	get_values_from_reg(c->reg, 0xC0, 1, v);
1081 	seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
1082 
1083 	get_values_from_reg(c->reg, 0xD0, 8, v);
1084 	seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
1085 	seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
1086 	seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
1087 	seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
1088 	seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
1089 	seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
1090 	seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
1091 	seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
1092 
1093 	get_values_from_reg(c->reg, 0x100, 3, v);
1094 	seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
1095 	seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
1096 	seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
1097 
1098 	get_values_from_reg(c->reg, 0x110, 3, v);
1099 	for (i = 0; i < 3; i++)
1100 		seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
1101 
1102 	get_values_from_reg(c->reg, 0x120, 5, v);
1103 	for (i = 0; i < 2; i++) {
1104 		seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
1105 		seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
1106 	}
1107 	seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
1108 }
1109 
1110 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
1111 	.update		= d71_timing_ctrlr_update,
1112 	.disable	= d71_timing_ctrlr_disable,
1113 	.dump_register	= d71_timing_ctrlr_dump,
1114 };
1115 
1116 static int d71_timing_ctrlr_init(struct d71_dev *d71,
1117 				 struct block_header *blk, u32 __iomem *reg)
1118 {
1119 	struct komeda_component *c;
1120 	struct komeda_timing_ctrlr *ctrlr;
1121 	u32 pipe_id, comp_id;
1122 
1123 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
1124 
1125 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
1126 				 KOMEDA_COMPONENT_TIMING_CTRLR,
1127 				 BLOCK_INFO_INPUT_ID(blk->block_info),
1128 				 &d71_timing_ctrlr_funcs,
1129 				 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
1130 				 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
1131 	if (IS_ERR(c)) {
1132 		DRM_ERROR("Failed to add display_ctrl component\n");
1133 		return PTR_ERR(c);
1134 	}
1135 
1136 	ctrlr = to_ctrlr(c);
1137 
1138 	ctrlr->supports_dual_link = true;
1139 
1140 	return 0;
1141 }
1142 
1143 int d71_probe_block(struct d71_dev *d71,
1144 		    struct block_header *blk, u32 __iomem *reg)
1145 {
1146 	struct d71_pipeline *pipe;
1147 	int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
1148 
1149 	int err = 0;
1150 
1151 	switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
1152 	case D71_BLK_TYPE_GCU:
1153 		break;
1154 
1155 	case D71_BLK_TYPE_LPU:
1156 		pipe = d71->pipes[blk_id];
1157 		pipe->lpu_addr = reg;
1158 		break;
1159 
1160 	case D71_BLK_TYPE_LPU_LAYER:
1161 		err = d71_layer_init(d71, blk, reg);
1162 		break;
1163 
1164 	case D71_BLK_TYPE_LPU_WB_LAYER:
1165 		err = d71_wb_layer_init(d71, blk, reg);
1166 		break;
1167 
1168 	case D71_BLK_TYPE_CU:
1169 		pipe = d71->pipes[blk_id];
1170 		pipe->cu_addr = reg;
1171 		err = d71_compiz_init(d71, blk, reg);
1172 		break;
1173 
1174 	case D71_BLK_TYPE_CU_SCALER:
1175 		err = d71_scaler_init(d71, blk, reg);
1176 		break;
1177 
1178 	case D71_BLK_TYPE_CU_SPLITTER:
1179 		err = d71_splitter_init(d71, blk, reg);
1180 		break;
1181 
1182 	case D71_BLK_TYPE_CU_MERGER:
1183 		err = d71_merger_init(d71, blk, reg);
1184 		break;
1185 
1186 	case D71_BLK_TYPE_DOU:
1187 		pipe = d71->pipes[blk_id];
1188 		pipe->dou_addr = reg;
1189 		break;
1190 
1191 	case D71_BLK_TYPE_DOU_IPS:
1192 		err = d71_improc_init(d71, blk, reg);
1193 		break;
1194 
1195 	case D71_BLK_TYPE_DOU_FT_COEFF:
1196 		pipe = d71->pipes[blk_id];
1197 		pipe->dou_ft_coeff_addr = reg;
1198 		break;
1199 
1200 	case D71_BLK_TYPE_DOU_BS:
1201 		err = d71_timing_ctrlr_init(d71, blk, reg);
1202 		break;
1203 
1204 	case D71_BLK_TYPE_GLB_LT_COEFF:
1205 		break;
1206 
1207 	case D71_BLK_TYPE_GLB_SCL_COEFF:
1208 		d71->glb_scl_coeff_addr[blk_id] = reg;
1209 		break;
1210 
1211 	default:
1212 		DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
1213 			  blk->block_info);
1214 		err = -EINVAL;
1215 		break;
1216 	}
1217 
1218 	return err;
1219 }
1220 
1221 const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1222 	.downscaling_clk_check = d71_downscaling_clk_check,
1223 };
1224