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