xref: /openbmc/linux/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c (revision abade675e02e1b73da0c20ffaf08fbe309038298)
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 
14 static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id)
15 {
16 	u32 id = BLOCK_INFO_BLK_ID(hw_id);
17 	u32 pipe = id;
18 
19 	switch (BLOCK_INFO_BLK_TYPE(hw_id)) {
20 	case D71_BLK_TYPE_LPU_WB_LAYER:
21 		id = KOMEDA_COMPONENT_WB_LAYER;
22 		break;
23 	case D71_BLK_TYPE_CU_SPLITTER:
24 		id = KOMEDA_COMPONENT_SPLITTER;
25 		break;
26 	case D71_BLK_TYPE_CU_SCALER:
27 		pipe = id / D71_PIPELINE_MAX_SCALERS;
28 		id %= D71_PIPELINE_MAX_SCALERS;
29 		id += KOMEDA_COMPONENT_SCALER0;
30 		break;
31 	case D71_BLK_TYPE_CU:
32 		id += KOMEDA_COMPONENT_COMPIZ0;
33 		break;
34 	case D71_BLK_TYPE_LPU_LAYER:
35 		pipe = id / D71_PIPELINE_MAX_LAYERS;
36 		id %= D71_PIPELINE_MAX_LAYERS;
37 		id += KOMEDA_COMPONENT_LAYER0;
38 		break;
39 	case D71_BLK_TYPE_DOU_IPS:
40 		id += KOMEDA_COMPONENT_IPS0;
41 		break;
42 	case D71_BLK_TYPE_CU_MERGER:
43 		id = KOMEDA_COMPONENT_MERGER;
44 		break;
45 	case D71_BLK_TYPE_DOU:
46 		id = KOMEDA_COMPONENT_TIMING_CTRLR;
47 		break;
48 	default:
49 		id = 0xFFFFFFFF;
50 	}
51 
52 	if (comp_id)
53 		*comp_id = id;
54 
55 	if (pipe_id)
56 		*pipe_id = pipe;
57 }
58 
59 static u32 get_valid_inputs(struct block_header *blk)
60 {
61 	u32 valid_inputs = 0, comp_id;
62 	int i;
63 
64 	for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++) {
65 		get_resources_id(blk->input_ids[i], NULL, &comp_id);
66 		if (comp_id == 0xFFFFFFFF)
67 			continue;
68 		valid_inputs |= BIT(comp_id);
69 	}
70 
71 	return valid_inputs;
72 }
73 
74 static void get_values_from_reg(void __iomem *reg, u32 offset,
75 				u32 count, u32 *val)
76 {
77 	u32 i, addr;
78 
79 	for (i = 0; i < count; i++) {
80 		addr = offset + (i << 2);
81 		/* 0xA4 is WO register */
82 		if (addr != 0xA4)
83 			val[i] = malidp_read32(reg, addr);
84 		else
85 			val[i] = 0xDEADDEAD;
86 	}
87 }
88 
89 static void dump_block_header(struct seq_file *sf, void __iomem *reg)
90 {
91 	struct block_header hdr;
92 	u32 i, n_input, n_output;
93 
94 	d71_read_block_header(reg, &hdr);
95 	seq_printf(sf, "BLOCK_INFO:\t\t0x%X\n", hdr.block_info);
96 	seq_printf(sf, "PIPELINE_INFO:\t\t0x%X\n", hdr.pipeline_info);
97 
98 	n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info);
99 	n_input  = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info);
100 
101 	for (i = 0; i < n_input; i++)
102 		seq_printf(sf, "VALID_INPUT_ID%u:\t0x%X\n",
103 			   i, hdr.input_ids[i]);
104 
105 	for (i = 0; i < n_output; i++)
106 		seq_printf(sf, "OUTPUT_ID%u:\t\t0x%X\n",
107 			   i, hdr.output_ids[i]);
108 }
109 
110 static u32 to_rot_ctrl(u32 rot)
111 {
112 	u32 lr_ctrl = 0;
113 
114 	switch (rot & DRM_MODE_ROTATE_MASK) {
115 	case DRM_MODE_ROTATE_0:
116 		lr_ctrl |= L_ROT(L_ROT_R0);
117 		break;
118 	case DRM_MODE_ROTATE_90:
119 		lr_ctrl |= L_ROT(L_ROT_R90);
120 		break;
121 	case DRM_MODE_ROTATE_180:
122 		lr_ctrl |= L_ROT(L_ROT_R180);
123 		break;
124 	case DRM_MODE_ROTATE_270:
125 		lr_ctrl |= L_ROT(L_ROT_R270);
126 		break;
127 	}
128 
129 	if (rot & DRM_MODE_REFLECT_X)
130 		lr_ctrl |= L_HFLIP;
131 	if (rot & DRM_MODE_REFLECT_Y)
132 		lr_ctrl |= L_VFLIP;
133 
134 	return lr_ctrl;
135 }
136 
137 static inline u32 to_d71_input_id(struct komeda_component_output *output)
138 {
139 	struct komeda_component *comp = output->component;
140 
141 	return comp ? (comp->hw_id + output->output_port) : 0;
142 }
143 
144 static void d71_layer_disable(struct komeda_component *c)
145 {
146 	malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
147 }
148 
149 static void d71_layer_update(struct komeda_component *c,
150 			     struct komeda_component_state *state)
151 {
152 	struct komeda_layer_state *st = to_layer_st(state);
153 	struct drm_plane_state *plane_st = state->plane->state;
154 	struct drm_framebuffer *fb = plane_st->fb;
155 	struct komeda_fb *kfb = to_kfb(fb);
156 	u32 __iomem *reg = c->reg;
157 	u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
158 	u32 ctrl = L_EN | to_rot_ctrl(st->rot);
159 	int i;
160 
161 	for (i = 0; i < fb->format->num_planes; i++) {
162 		malidp_write32(reg,
163 			       BLK_P0_PTR_LOW + i * LAYER_PER_PLANE_REGS * 4,
164 			       lower_32_bits(st->addr[i]));
165 		malidp_write32(reg,
166 			       BLK_P0_PTR_HIGH + i * LAYER_PER_PLANE_REGS * 4,
167 			       upper_32_bits(st->addr[i]));
168 		if (i >= 2)
169 			break;
170 
171 		malidp_write32(reg,
172 			       BLK_P0_STRIDE + i * LAYER_PER_PLANE_REGS * 4,
173 			       fb->pitches[i] & 0xFFFF);
174 	}
175 
176 	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
177 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
178 
179 	malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
180 }
181 
182 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
183 {
184 	u32 v[15], i;
185 	bool rich, rgb2rgb;
186 	char *prefix;
187 
188 	get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
189 	if (v[14] & 0x1) {
190 		rich = true;
191 		prefix = "LR_";
192 	} else {
193 		rich = false;
194 		prefix = "LS_";
195 	}
196 
197 	rgb2rgb = !!(v[14] & L_INFO_CM);
198 
199 	dump_block_header(sf, c->reg);
200 
201 	seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
202 
203 	get_values_from_reg(c->reg, 0xD0, 1, v);
204 	seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
205 	if (rich) {
206 		get_values_from_reg(c->reg, 0xD4, 1, v);
207 		seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
208 	}
209 	get_values_from_reg(c->reg, 0xD8, 4, v);
210 	seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
211 	seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
212 	seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
213 	seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
214 
215 	get_values_from_reg(c->reg, 0x100, 3, v);
216 	seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
217 	seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
218 	seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
219 
220 	get_values_from_reg(c->reg, 0x110, 2, v);
221 	seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
222 	seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
223 	if (rich) {
224 		get_values_from_reg(c->reg, 0x118, 1, v);
225 		seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
226 
227 		get_values_from_reg(c->reg, 0x120, 2, v);
228 		seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
229 		seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
230 
231 		get_values_from_reg(c->reg, 0x130, 12, v);
232 		for (i = 0; i < 12; i++)
233 			seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
234 	}
235 
236 	if (rgb2rgb) {
237 		get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
238 		for (i = 0; i < 12; i++)
239 			seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
240 	}
241 
242 	get_values_from_reg(c->reg, 0x160, 3, v);
243 	seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
244 	seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
245 	seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
246 }
247 
248 static struct komeda_component_funcs d71_layer_funcs = {
249 	.update		= d71_layer_update,
250 	.disable	= d71_layer_disable,
251 	.dump_register	= d71_layer_dump,
252 };
253 
254 static int d71_layer_init(struct d71_dev *d71,
255 			  struct block_header *blk, u32 __iomem *reg)
256 {
257 	struct komeda_component *c;
258 	struct komeda_layer *layer;
259 	u32 pipe_id, layer_id, layer_info;
260 
261 	get_resources_id(blk->block_info, &pipe_id, &layer_id);
262 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
263 				 layer_id,
264 				 BLOCK_INFO_INPUT_ID(blk->block_info),
265 				 &d71_layer_funcs, 0,
266 				 get_valid_inputs(blk),
267 				 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
268 	if (IS_ERR(c)) {
269 		DRM_ERROR("Failed to add layer component\n");
270 		return PTR_ERR(c);
271 	}
272 
273 	layer = to_layer(c);
274 	layer_info = malidp_read32(reg, LAYER_INFO);
275 
276 	if (layer_info & L_INFO_RF)
277 		layer->layer_type = KOMEDA_FMT_RICH_LAYER;
278 	else
279 		layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
280 
281 	set_range(&layer->hsize_in, 4, d71->max_line_size);
282 	set_range(&layer->vsize_in, 4, d71->max_vsize);
283 
284 	malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
285 
286 	layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
287 
288 	return 0;
289 }
290 
291 static int d71_wb_layer_init(struct d71_dev *d71,
292 			     struct block_header *blk, u32 __iomem *reg)
293 {
294 	DRM_DEBUG("Detect D71_Wb_Layer.\n");
295 
296 	return 0;
297 }
298 
299 static void d71_component_disable(struct komeda_component *c)
300 {
301 	u32 __iomem *reg = c->reg;
302 	u32 i;
303 
304 	malidp_write32(reg, BLK_CONTROL, 0);
305 
306 	for (i = 0; i < c->max_active_inputs; i++)
307 		malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
308 }
309 
310 static void compiz_enable_input(u32 __iomem *id_reg,
311 				u32 __iomem *cfg_reg,
312 				u32 input_hw_id,
313 				struct komeda_compiz_input_cfg *cin)
314 {
315 	u32 ctrl = CU_INPUT_CTRL_EN;
316 	u8 blend = cin->pixel_blend_mode;
317 
318 	if (blend == DRM_MODE_BLEND_PIXEL_NONE)
319 		ctrl |= CU_INPUT_CTRL_PAD;
320 	else if (blend == DRM_MODE_BLEND_PREMULTI)
321 		ctrl |= CU_INPUT_CTRL_PMUL;
322 
323 	ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
324 
325 	malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
326 
327 	malidp_write32(cfg_reg, CU_INPUT0_SIZE,
328 		       HV_SIZE(cin->hsize, cin->vsize));
329 	malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
330 		       HV_OFFSET(cin->hoffset, cin->voffset));
331 	malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
332 }
333 
334 static void d71_compiz_update(struct komeda_component *c,
335 			      struct komeda_component_state *state)
336 {
337 	struct komeda_compiz_state *st = to_compiz_st(state);
338 	u32 __iomem *reg = c->reg;
339 	u32 __iomem *id_reg, *cfg_reg;
340 	u32 index, input_hw_id;
341 
342 	for_each_changed_input(state, index) {
343 		id_reg = reg + index;
344 		cfg_reg = reg + index * CU_PER_INPUT_REGS;
345 		input_hw_id = to_d71_input_id(&state->inputs[index]);
346 		if (state->active_inputs & BIT(index)) {
347 			compiz_enable_input(id_reg, cfg_reg,
348 					    input_hw_id, &st->cins[index]);
349 		} else {
350 			malidp_write32(id_reg, BLK_INPUT_ID0, 0);
351 			malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
352 		}
353 	}
354 
355 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
356 }
357 
358 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
359 {
360 	u32 v[8], i;
361 
362 	dump_block_header(sf, c->reg);
363 
364 	get_values_from_reg(c->reg, 0x80, 5, v);
365 	for (i = 0; i < 5; i++)
366 		seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
367 
368 	get_values_from_reg(c->reg, 0xA0, 5, v);
369 	seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
370 	seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
371 	seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
372 	seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
373 	seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
374 
375 	get_values_from_reg(c->reg, 0xD0, 2, v);
376 	seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
377 	seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
378 
379 	get_values_from_reg(c->reg, 0xDC, 1, v);
380 	seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
381 
382 	for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
383 		get_values_from_reg(c->reg, v[4], 3, v);
384 		seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
385 		seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
386 		seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
387 	}
388 
389 	get_values_from_reg(c->reg, 0x130, 2, v);
390 	seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
391 	seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
392 }
393 
394 static struct komeda_component_funcs d71_compiz_funcs = {
395 	.update		= d71_compiz_update,
396 	.disable	= d71_component_disable,
397 	.dump_register	= d71_compiz_dump,
398 };
399 
400 static int d71_compiz_init(struct d71_dev *d71,
401 			   struct block_header *blk, u32 __iomem *reg)
402 {
403 	struct komeda_component *c;
404 	struct komeda_compiz *compiz;
405 	u32 pipe_id, comp_id;
406 
407 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
408 
409 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
410 				 comp_id,
411 				 BLOCK_INFO_INPUT_ID(blk->block_info),
412 				 &d71_compiz_funcs,
413 				 CU_NUM_INPUT_IDS, get_valid_inputs(blk),
414 				 CU_NUM_OUTPUT_IDS, reg,
415 				 "CU%d", pipe_id);
416 	if (IS_ERR(c))
417 		return PTR_ERR(c);
418 
419 	compiz = to_compiz(c);
420 
421 	set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
422 	set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
423 
424 	return 0;
425 }
426 
427 static void d71_improc_update(struct komeda_component *c,
428 			      struct komeda_component_state *state)
429 {
430 	struct komeda_improc_state *st = to_improc_st(state);
431 	u32 __iomem *reg = c->reg;
432 	u32 index, input_hw_id;
433 
434 	for_each_changed_input(state, index) {
435 		input_hw_id = state->active_inputs & BIT(index) ?
436 			      to_d71_input_id(&state->inputs[index]) : 0;
437 		malidp_write32(reg, BLK_INPUT_ID0 + index * 4, input_hw_id);
438 	}
439 
440 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
441 }
442 
443 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
444 {
445 	u32 v[12], i;
446 
447 	dump_block_header(sf, c->reg);
448 
449 	get_values_from_reg(c->reg, 0x80, 2, v);
450 	seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
451 	seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
452 
453 	get_values_from_reg(c->reg, 0xC0, 1, v);
454 	seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
455 
456 	get_values_from_reg(c->reg, 0xD0, 3, v);
457 	seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
458 	seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
459 	seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
460 
461 	get_values_from_reg(c->reg, 0x130, 12, v);
462 	for (i = 0; i < 12; i++)
463 		seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
464 
465 	get_values_from_reg(c->reg, 0x170, 12, v);
466 	for (i = 0; i < 12; i++)
467 		seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
468 }
469 
470 static struct komeda_component_funcs d71_improc_funcs = {
471 	.update		= d71_improc_update,
472 	.disable	= d71_component_disable,
473 	.dump_register	= d71_improc_dump,
474 };
475 
476 static int d71_improc_init(struct d71_dev *d71,
477 			   struct block_header *blk, u32 __iomem *reg)
478 {
479 	struct komeda_component *c;
480 	struct komeda_improc *improc;
481 	u32 pipe_id, comp_id, value;
482 
483 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
484 
485 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
486 				 comp_id,
487 				 BLOCK_INFO_INPUT_ID(blk->block_info),
488 				 &d71_improc_funcs, IPS_NUM_INPUT_IDS,
489 				 get_valid_inputs(blk),
490 				 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
491 	if (IS_ERR(c)) {
492 		DRM_ERROR("Failed to add improc component\n");
493 		return PTR_ERR(c);
494 	}
495 
496 	improc = to_improc(c);
497 	improc->supported_color_depths = BIT(8) | BIT(10);
498 	improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
499 					  DRM_COLOR_FORMAT_YCRCB444 |
500 					  DRM_COLOR_FORMAT_YCRCB422;
501 	value = malidp_read32(reg, BLK_INFO);
502 	if (value & IPS_INFO_CHD420)
503 		improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
504 
505 	improc->supports_csc = true;
506 	improc->supports_gamma = true;
507 
508 	return 0;
509 }
510 
511 static void d71_timing_ctrlr_disable(struct komeda_component *c)
512 {
513 	malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
514 }
515 
516 static void d71_timing_ctrlr_update(struct komeda_component *c,
517 				    struct komeda_component_state *state)
518 {
519 	struct drm_crtc_state *crtc_st = state->crtc->state;
520 	u32 __iomem *reg = c->reg;
521 	struct videomode vm;
522 	u32 value;
523 
524 	drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm);
525 
526 	malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive));
527 	malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch,
528 							vm.hback_porch));
529 	malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch,
530 							vm.vback_porch));
531 
532 	value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len);
533 	value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0;
534 	value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0;
535 	malidp_write32(reg, BS_SYNC, value);
536 
537 	malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
538 	malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
539 
540 	/* configure bs control register */
541 	value = BS_CTRL_EN | BS_CTRL_VM;
542 
543 	malidp_write32(reg, BLK_CONTROL, value);
544 }
545 
546 static void d71_timing_ctrlr_dump(struct komeda_component *c,
547 				  struct seq_file *sf)
548 {
549 	u32 v[8], i;
550 
551 	dump_block_header(sf, c->reg);
552 
553 	get_values_from_reg(c->reg, 0xC0, 1, v);
554 	seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
555 
556 	get_values_from_reg(c->reg, 0xD0, 8, v);
557 	seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
558 	seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
559 	seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
560 	seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
561 	seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
562 	seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
563 	seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
564 	seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
565 
566 	get_values_from_reg(c->reg, 0x100, 3, v);
567 	seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
568 	seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
569 	seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
570 
571 	get_values_from_reg(c->reg, 0x110, 3, v);
572 	for (i = 0; i < 3; i++)
573 		seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
574 
575 	get_values_from_reg(c->reg, 0x120, 5, v);
576 	for (i = 0; i < 2; i++) {
577 		seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
578 		seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
579 	}
580 	seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
581 }
582 
583 static struct komeda_component_funcs d71_timing_ctrlr_funcs = {
584 	.update		= d71_timing_ctrlr_update,
585 	.disable	= d71_timing_ctrlr_disable,
586 	.dump_register	= d71_timing_ctrlr_dump,
587 };
588 
589 static int d71_timing_ctrlr_init(struct d71_dev *d71,
590 				 struct block_header *blk, u32 __iomem *reg)
591 {
592 	struct komeda_component *c;
593 	struct komeda_timing_ctrlr *ctrlr;
594 	u32 pipe_id, comp_id;
595 
596 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
597 
598 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
599 				 KOMEDA_COMPONENT_TIMING_CTRLR,
600 				 BLOCK_INFO_INPUT_ID(blk->block_info),
601 				 &d71_timing_ctrlr_funcs,
602 				 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
603 				 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
604 	if (IS_ERR(c)) {
605 		DRM_ERROR("Failed to add display_ctrl component\n");
606 		return PTR_ERR(c);
607 	}
608 
609 	ctrlr = to_ctrlr(c);
610 
611 	ctrlr->supports_dual_link = true;
612 
613 	return 0;
614 }
615 
616 int d71_probe_block(struct d71_dev *d71,
617 		    struct block_header *blk, u32 __iomem *reg)
618 {
619 	struct d71_pipeline *pipe;
620 	int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
621 
622 	int err = 0;
623 
624 	switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
625 	case D71_BLK_TYPE_GCU:
626 		break;
627 
628 	case D71_BLK_TYPE_LPU:
629 		pipe = d71->pipes[blk_id];
630 		pipe->lpu_addr = reg;
631 		break;
632 
633 	case D71_BLK_TYPE_LPU_LAYER:
634 		err = d71_layer_init(d71, blk, reg);
635 		break;
636 
637 	case D71_BLK_TYPE_LPU_WB_LAYER:
638 		err = d71_wb_layer_init(d71, blk, reg);
639 		break;
640 
641 	case D71_BLK_TYPE_CU:
642 		pipe = d71->pipes[blk_id];
643 		pipe->cu_addr = reg;
644 		err = d71_compiz_init(d71, blk, reg);
645 		break;
646 
647 	case D71_BLK_TYPE_CU_SPLITTER:
648 	case D71_BLK_TYPE_CU_SCALER:
649 	case D71_BLK_TYPE_CU_MERGER:
650 		break;
651 
652 	case D71_BLK_TYPE_DOU:
653 		pipe = d71->pipes[blk_id];
654 		pipe->dou_addr = reg;
655 		break;
656 
657 	case D71_BLK_TYPE_DOU_IPS:
658 		err = d71_improc_init(d71, blk, reg);
659 		break;
660 
661 	case D71_BLK_TYPE_DOU_FT_COEFF:
662 		pipe = d71->pipes[blk_id];
663 		pipe->dou_ft_coeff_addr = reg;
664 		break;
665 
666 	case D71_BLK_TYPE_DOU_BS:
667 		err = d71_timing_ctrlr_init(d71, blk, reg);
668 		break;
669 
670 	case D71_BLK_TYPE_GLB_LT_COEFF:
671 		break;
672 
673 	case D71_BLK_TYPE_GLB_SCL_COEFF:
674 		d71->glb_scl_coeff_addr[blk_id] = reg;
675 		break;
676 
677 	default:
678 		DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
679 			  blk->block_info);
680 		err = -EINVAL;
681 		break;
682 	}
683 
684 	return err;
685 }
686