xref: /linux/drivers/gpu/drm/arm/display/komeda/d71/d71_component.c (revision 04e84545b9805f6a141fce0b1f05fb74551094fc)
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_output *output)
160 {
161 	struct komeda_component *comp = output->component;
162 
163 	return comp ? (comp->hw_id + output->output_port) : 0;
164 }
165 
166 static void d71_layer_update_fb(struct komeda_component *c,
167 				struct komeda_fb *kfb,
168 				dma_addr_t *addr)
169 {
170 	struct drm_framebuffer *fb = &kfb->base;
171 	const struct drm_format_info *info = fb->format;
172 	u32 __iomem *reg = c->reg;
173 	int block_h;
174 
175 	if (info->num_planes > 2)
176 		malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]);
177 
178 	if (info->num_planes > 1) {
179 		block_h = drm_format_info_block_height(info, 1);
180 		malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h);
181 		malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]);
182 	}
183 
184 	block_h = drm_format_info_block_height(info, 0);
185 	malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h);
186 	malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]);
187 	malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id);
188 }
189 
190 static void d71_layer_disable(struct komeda_component *c)
191 {
192 	malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
193 }
194 
195 static void d71_layer_update(struct komeda_component *c,
196 			     struct komeda_component_state *state)
197 {
198 	struct komeda_layer_state *st = to_layer_st(state);
199 	struct drm_plane_state *plane_st = state->plane->state;
200 	struct drm_framebuffer *fb = plane_st->fb;
201 	struct komeda_fb *kfb = to_kfb(fb);
202 	u32 __iomem *reg = c->reg;
203 	u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN;
204 	u32 ctrl = L_EN | to_rot_ctrl(st->rot);
205 
206 	d71_layer_update_fb(c, kfb, st->addr);
207 
208 	malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier));
209 	if (fb->modifier) {
210 		u64 addr;
211 
212 		malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l,
213 							     st->afbc_crop_r));
214 		malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t,
215 							     st->afbc_crop_b));
216 		/* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */
217 		if (fb->modifier & AFBC_FORMAT_MOD_TILED)
218 			addr = st->addr[0] + kfb->offset_payload;
219 		else
220 			addr = st->addr[0] + kfb->afbc_size - 1;
221 
222 		malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr));
223 		malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr));
224 	}
225 
226 	if (fb->format->is_yuv) {
227 		u32 upsampling = 0;
228 
229 		switch (kfb->format_caps->fourcc) {
230 		case DRM_FORMAT_YUYV:
231 			upsampling = fb->modifier ? LR_CHI422_BILINEAR :
232 				     LR_CHI422_REPLICATION;
233 			break;
234 		case DRM_FORMAT_UYVY:
235 			upsampling = LR_CHI422_REPLICATION;
236 			break;
237 		case DRM_FORMAT_NV12:
238 		case DRM_FORMAT_YUV420_8BIT:
239 		case DRM_FORMAT_YUV420_10BIT:
240 		case DRM_FORMAT_YUV420:
241 		case DRM_FORMAT_P010:
242 		/* these fmt support MPGE/JPEG both, here perfer JPEG*/
243 			upsampling = LR_CHI420_JPEG;
244 			break;
245 		case DRM_FORMAT_X0L2:
246 			upsampling = LR_CHI420_JPEG;
247 			break;
248 		default:
249 			break;
250 		}
251 
252 		malidp_write32(reg, LAYER_R_CONTROL, upsampling);
253 		malidp_write_group(reg, LAYER_YUV_RGB_COEFF0,
254 				   KOMEDA_N_YUV2RGB_COEFFS,
255 				   komeda_select_yuv2rgb_coeffs(
256 					plane_st->color_encoding,
257 					plane_st->color_range));
258 	}
259 
260 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
261 
262 	if (kfb->is_va)
263 		ctrl |= L_TBU_EN;
264 	malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
265 }
266 
267 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
268 {
269 	u32 v[15], i;
270 	bool rich, rgb2rgb;
271 	char *prefix;
272 
273 	get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
274 	if (v[14] & 0x1) {
275 		rich = true;
276 		prefix = "LR_";
277 	} else {
278 		rich = false;
279 		prefix = "LS_";
280 	}
281 
282 	rgb2rgb = !!(v[14] & L_INFO_CM);
283 
284 	dump_block_header(sf, c->reg);
285 
286 	seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
287 
288 	get_values_from_reg(c->reg, 0xD0, 1, v);
289 	seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
290 	if (rich) {
291 		get_values_from_reg(c->reg, 0xD4, 1, v);
292 		seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
293 	}
294 	get_values_from_reg(c->reg, 0xD8, 4, v);
295 	seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
296 	seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
297 	seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
298 	seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
299 
300 	get_values_from_reg(c->reg, 0x100, 3, v);
301 	seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
302 	seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
303 	seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
304 
305 	get_values_from_reg(c->reg, 0x110, 2, v);
306 	seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
307 	seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
308 	if (rich) {
309 		get_values_from_reg(c->reg, 0x118, 1, v);
310 		seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
311 
312 		get_values_from_reg(c->reg, 0x120, 2, v);
313 		seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
314 		seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
315 
316 		get_values_from_reg(c->reg, 0x130, 12, v);
317 		for (i = 0; i < 12; i++)
318 			seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
319 	}
320 
321 	if (rgb2rgb) {
322 		get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
323 		for (i = 0; i < 12; i++)
324 			seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
325 	}
326 
327 	get_values_from_reg(c->reg, 0x160, 3, v);
328 	seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
329 	seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
330 	seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
331 }
332 
333 static const struct komeda_component_funcs d71_layer_funcs = {
334 	.update		= d71_layer_update,
335 	.disable	= d71_layer_disable,
336 	.dump_register	= d71_layer_dump,
337 };
338 
339 static int d71_layer_init(struct d71_dev *d71,
340 			  struct block_header *blk, u32 __iomem *reg)
341 {
342 	struct komeda_component *c;
343 	struct komeda_layer *layer;
344 	u32 pipe_id, layer_id, layer_info;
345 
346 	get_resources_id(blk->block_info, &pipe_id, &layer_id);
347 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer),
348 				 layer_id,
349 				 BLOCK_INFO_INPUT_ID(blk->block_info),
350 				 &d71_layer_funcs, 0,
351 				 get_valid_inputs(blk),
352 				 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id);
353 	if (IS_ERR(c)) {
354 		DRM_ERROR("Failed to add layer component\n");
355 		return PTR_ERR(c);
356 	}
357 
358 	layer = to_layer(c);
359 	layer_info = malidp_read32(reg, LAYER_INFO);
360 
361 	if (layer_info & L_INFO_RF)
362 		layer->layer_type = KOMEDA_FMT_RICH_LAYER;
363 	else
364 		layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER;
365 
366 	set_range(&layer->hsize_in, 4, d71->max_line_size);
367 	set_range(&layer->vsize_in, 4, d71->max_vsize);
368 
369 	malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP);
370 
371 	layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK;
372 
373 	return 0;
374 }
375 
376 static void d71_wb_layer_update(struct komeda_component *c,
377 				struct komeda_component_state *state)
378 {
379 	struct komeda_layer_state *st = to_layer_st(state);
380 	struct drm_connector_state *conn_st = state->wb_conn->state;
381 	struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb);
382 	u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN;
383 	u32 __iomem *reg = c->reg;
384 
385 	d71_layer_update_fb(c, kfb, st->addr);
386 
387 	if (kfb->is_va)
388 		ctrl |= LW_TBU_EN;
389 
390 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize));
391 	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
392 	malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl);
393 }
394 
395 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf)
396 {
397 	u32 v[12], i;
398 
399 	dump_block_header(sf, c->reg);
400 
401 	get_values_from_reg(c->reg, 0x80, 1, v);
402 	seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]);
403 
404 	get_values_from_reg(c->reg, 0xD0, 3, v);
405 	seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]);
406 	seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]);
407 	seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]);
408 
409 	get_values_from_reg(c->reg, 0xE0, 1, v);
410 	seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]);
411 
412 	for (i = 0; i < 2; i++) {
413 		get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v);
414 		seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]);
415 		seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]);
416 		seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]);
417 	}
418 
419 	get_values_from_reg(c->reg, 0x130, 12, v);
420 	for (i = 0; i < 12; i++)
421 		seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
422 }
423 
424 static void d71_wb_layer_disable(struct komeda_component *c)
425 {
426 	malidp_write32(c->reg, BLK_INPUT_ID0, 0);
427 	malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0);
428 }
429 
430 static const struct komeda_component_funcs d71_wb_layer_funcs = {
431 	.update		= d71_wb_layer_update,
432 	.disable	= d71_wb_layer_disable,
433 	.dump_register	= d71_wb_layer_dump,
434 };
435 
436 static int d71_wb_layer_init(struct d71_dev *d71,
437 			     struct block_header *blk, u32 __iomem *reg)
438 {
439 	struct komeda_component *c;
440 	struct komeda_layer *wb_layer;
441 	u32 pipe_id, layer_id;
442 
443 	get_resources_id(blk->block_info, &pipe_id, &layer_id);
444 
445 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer),
446 				 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info),
447 				 &d71_wb_layer_funcs,
448 				 1, get_valid_inputs(blk), 0, reg,
449 				 "LPU%d_LAYER_WR", pipe_id);
450 	if (IS_ERR(c)) {
451 		DRM_ERROR("Failed to add wb_layer component\n");
452 		return PTR_ERR(c);
453 	}
454 
455 	wb_layer = to_layer(c);
456 	wb_layer->layer_type = KOMEDA_FMT_WB_LAYER;
457 
458 	set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size);
459 	set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
460 
461 	return 0;
462 }
463 
464 static void d71_component_disable(struct komeda_component *c)
465 {
466 	u32 __iomem *reg = c->reg;
467 	u32 i;
468 
469 	malidp_write32(reg, BLK_CONTROL, 0);
470 
471 	for (i = 0; i < c->max_active_inputs; i++) {
472 		malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0);
473 
474 		/* Besides clearing the input ID to zero, D71 compiz also has
475 		 * input enable bit in CU_INPUTx_CONTROL which need to be
476 		 * cleared.
477 		 */
478 		if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS))
479 			malidp_write32(reg, CU_INPUT0_CONTROL +
480 				       i * CU_PER_INPUT_REGS * 4,
481 				       CU_INPUT_CTRL_ALPHA(0xFF));
482 	}
483 }
484 
485 static void compiz_enable_input(u32 __iomem *id_reg,
486 				u32 __iomem *cfg_reg,
487 				u32 input_hw_id,
488 				struct komeda_compiz_input_cfg *cin)
489 {
490 	u32 ctrl = CU_INPUT_CTRL_EN;
491 	u8 blend = cin->pixel_blend_mode;
492 
493 	if (blend == DRM_MODE_BLEND_PIXEL_NONE)
494 		ctrl |= CU_INPUT_CTRL_PAD;
495 	else if (blend == DRM_MODE_BLEND_PREMULTI)
496 		ctrl |= CU_INPUT_CTRL_PMUL;
497 
498 	ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
499 
500 	malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
501 
502 	malidp_write32(cfg_reg, CU_INPUT0_SIZE,
503 		       HV_SIZE(cin->hsize, cin->vsize));
504 	malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
505 		       HV_OFFSET(cin->hoffset, cin->voffset));
506 	malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
507 }
508 
509 static void d71_compiz_update(struct komeda_component *c,
510 			      struct komeda_component_state *state)
511 {
512 	struct komeda_compiz_state *st = to_compiz_st(state);
513 	u32 __iomem *reg = c->reg;
514 	u32 __iomem *id_reg, *cfg_reg;
515 	u32 index, input_hw_id;
516 
517 	for_each_changed_input(state, index) {
518 		id_reg = reg + index;
519 		cfg_reg = reg + index * CU_PER_INPUT_REGS;
520 		input_hw_id = to_d71_input_id(&state->inputs[index]);
521 		if (state->active_inputs & BIT(index)) {
522 			compiz_enable_input(id_reg, cfg_reg,
523 					    input_hw_id, &st->cins[index]);
524 		} else {
525 			malidp_write32(id_reg, BLK_INPUT_ID0, 0);
526 			malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
527 		}
528 	}
529 
530 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
531 }
532 
533 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
534 {
535 	u32 v[8], i;
536 
537 	dump_block_header(sf, c->reg);
538 
539 	get_values_from_reg(c->reg, 0x80, 5, v);
540 	for (i = 0; i < 5; i++)
541 		seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
542 
543 	get_values_from_reg(c->reg, 0xA0, 5, v);
544 	seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
545 	seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
546 	seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
547 	seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
548 	seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
549 
550 	get_values_from_reg(c->reg, 0xD0, 2, v);
551 	seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
552 	seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
553 
554 	get_values_from_reg(c->reg, 0xDC, 1, v);
555 	seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
556 
557 	for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
558 		get_values_from_reg(c->reg, v[4], 3, v);
559 		seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
560 		seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
561 		seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
562 	}
563 
564 	get_values_from_reg(c->reg, 0x130, 2, v);
565 	seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
566 	seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
567 }
568 
569 static const struct komeda_component_funcs d71_compiz_funcs = {
570 	.update		= d71_compiz_update,
571 	.disable	= d71_component_disable,
572 	.dump_register	= d71_compiz_dump,
573 };
574 
575 static int d71_compiz_init(struct d71_dev *d71,
576 			   struct block_header *blk, u32 __iomem *reg)
577 {
578 	struct komeda_component *c;
579 	struct komeda_compiz *compiz;
580 	u32 pipe_id, comp_id;
581 
582 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
583 
584 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
585 				 comp_id,
586 				 BLOCK_INFO_INPUT_ID(blk->block_info),
587 				 &d71_compiz_funcs,
588 				 CU_NUM_INPUT_IDS, get_valid_inputs(blk),
589 				 CU_NUM_OUTPUT_IDS, reg,
590 				 "CU%d", pipe_id);
591 	if (IS_ERR(c))
592 		return PTR_ERR(c);
593 
594 	compiz = to_compiz(c);
595 
596 	set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
597 	set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
598 
599 	return 0;
600 }
601 
602 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
603 					 u32 vsize_in, u32 hsize_out,
604 					 u32 vsize_out)
605 {
606 	u32 val = 0;
607 
608 	if (hsize_in <= hsize_out)
609 		val  |= 0x62;
610 	else if (hsize_in <= (hsize_out + hsize_out / 2))
611 		val |= 0x63;
612 	else if (hsize_in <= hsize_out * 2)
613 		val |= 0x64;
614 	else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
615 		val |= 0x65;
616 	else
617 		val |= 0x66;
618 
619 	if (vsize_in <= vsize_out)
620 		val  |= SC_VTSEL(0x6A);
621 	else if (vsize_in <= (vsize_out + vsize_out / 2))
622 		val |= SC_VTSEL(0x6B);
623 	else if (vsize_in <= vsize_out * 2)
624 		val |= SC_VTSEL(0x6C);
625 	else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
626 		val |= SC_VTSEL(0x6D);
627 	else
628 		val |= SC_VTSEL(0x6E);
629 
630 	malidp_write32(reg, SC_COEFFTAB, val);
631 }
632 
633 static void d71_scaler_update(struct komeda_component *c,
634 			      struct komeda_component_state *state)
635 {
636 	struct komeda_scaler_state *st = to_scaler_st(state);
637 	u32 __iomem *reg = c->reg;
638 	u32 init_ph, delta_ph, ctrl;
639 
640 	d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
641 				     st->hsize_out, st->vsize_out);
642 
643 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
644 	malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
645 
646 	init_ph = (st->hsize_in << 15) / st->hsize_out;
647 	malidp_write32(reg, SC_H_INIT_PH, init_ph);
648 
649 	delta_ph = (st->hsize_in << 16) / st->hsize_out;
650 	malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
651 
652 	init_ph = (st->vsize_in << 15) / st->vsize_out;
653 	malidp_write32(reg, SC_V_INIT_PH, init_ph);
654 
655 	delta_ph = (st->vsize_in << 16) / st->vsize_out;
656 	malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
657 
658 	ctrl = 0;
659 	ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
660 	ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
661 	ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0;
662 
663 	malidp_write32(reg, BLK_CONTROL, ctrl);
664 	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
665 }
666 
667 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
668 {
669 	u32 v[9];
670 
671 	dump_block_header(sf, c->reg);
672 
673 	get_values_from_reg(c->reg, 0x80, 1, v);
674 	seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
675 
676 	get_values_from_reg(c->reg, 0xD0, 1, v);
677 	seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
678 
679 	get_values_from_reg(c->reg, 0xDC, 9, v);
680 	seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
681 	seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
682 	seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
683 	seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
684 	seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
685 	seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
686 	seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
687 	seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
688 	seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
689 }
690 
691 static const struct komeda_component_funcs d71_scaler_funcs = {
692 	.update		= d71_scaler_update,
693 	.disable	= d71_component_disable,
694 	.dump_register	= d71_scaler_dump,
695 };
696 
697 static int d71_scaler_init(struct d71_dev *d71,
698 			   struct block_header *blk, u32 __iomem *reg)
699 {
700 	struct komeda_component *c;
701 	struct komeda_scaler *scaler;
702 	u32 pipe_id, comp_id;
703 
704 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
705 
706 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
707 				 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
708 				 &d71_scaler_funcs,
709 				 1, get_valid_inputs(blk), 1, reg,
710 				 "CU%d_SCALER%d",
711 				 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
712 
713 	if (IS_ERR(c)) {
714 		DRM_ERROR("Failed to initialize scaler");
715 		return PTR_ERR(c);
716 	}
717 
718 	scaler = to_scaler(c);
719 	set_range(&scaler->hsize, 4, d71->max_line_size);
720 	set_range(&scaler->vsize, 4, 4096);
721 	scaler->max_downscaling = 6;
722 	scaler->max_upscaling = 64;
723 
724 	malidp_write32(c->reg, BLK_CONTROL, 0);
725 
726 	return 0;
727 }
728 
729 static int d71_downscaling_clk_check(struct komeda_pipeline *pipe,
730 				     struct drm_display_mode *mode,
731 				     unsigned long mclk_rate,
732 				     struct komeda_data_flow_cfg *dflow)
733 {
734 	u32 h_in = dflow->in_w;
735 	u32 v_in = dflow->in_h;
736 	u32 v_out = dflow->out_h;
737 	u64 fraction, denominator;
738 
739 	/* D71 downscaling must satisfy the following equation
740 	 *
741 	 *   MCLK                   h_in * v_in
742 	 * ------- >= ---------------------------------------------
743 	 *  PXLCLK     (h_total - (1 + 2 * v_in / v_out)) * v_out
744 	 *
745 	 * In only horizontal downscaling situation, the right side should be
746 	 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes
747 	 *
748 	 *   MCLK          h_in
749 	 * ------- >= ----------------
750 	 *  PXLCLK     (h_active - 3)
751 	 *
752 	 * To avoid precision lost the equation 1 will be convert to:
753 	 *
754 	 *   MCLK             h_in * v_in
755 	 * ------- >= -----------------------------------
756 	 *  PXLCLK     (h_total -1 ) * v_out -  2 * v_in
757 	 */
758 	if (v_in == v_out) {
759 		fraction = h_in;
760 		denominator = mode->hdisplay - 3;
761 	} else {
762 		fraction = h_in * v_in;
763 		denominator = (mode->htotal - 1) * v_out -  2 * v_in;
764 	}
765 
766 	return mclk_rate * denominator >= mode->clock * 1000 * fraction ?
767 	       0 : -EINVAL;
768 }
769 
770 static void d71_improc_update(struct komeda_component *c,
771 			      struct komeda_component_state *state)
772 {
773 	struct komeda_improc_state *st = to_improc_st(state);
774 	u32 __iomem *reg = c->reg;
775 	u32 index, input_hw_id;
776 
777 	for_each_changed_input(state, index) {
778 		input_hw_id = state->active_inputs & BIT(index) ?
779 			      to_d71_input_id(&state->inputs[index]) : 0;
780 		malidp_write32(reg, BLK_INPUT_ID0 + index * 4, input_hw_id);
781 	}
782 
783 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
784 }
785 
786 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
787 {
788 	u32 v[12], i;
789 
790 	dump_block_header(sf, c->reg);
791 
792 	get_values_from_reg(c->reg, 0x80, 2, v);
793 	seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
794 	seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
795 
796 	get_values_from_reg(c->reg, 0xC0, 1, v);
797 	seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
798 
799 	get_values_from_reg(c->reg, 0xD0, 3, v);
800 	seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
801 	seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
802 	seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
803 
804 	get_values_from_reg(c->reg, 0x130, 12, v);
805 	for (i = 0; i < 12; i++)
806 		seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
807 
808 	get_values_from_reg(c->reg, 0x170, 12, v);
809 	for (i = 0; i < 12; i++)
810 		seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
811 }
812 
813 static const struct komeda_component_funcs d71_improc_funcs = {
814 	.update		= d71_improc_update,
815 	.disable	= d71_component_disable,
816 	.dump_register	= d71_improc_dump,
817 };
818 
819 static int d71_improc_init(struct d71_dev *d71,
820 			   struct block_header *blk, u32 __iomem *reg)
821 {
822 	struct komeda_component *c;
823 	struct komeda_improc *improc;
824 	u32 pipe_id, comp_id, value;
825 
826 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
827 
828 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
829 				 comp_id,
830 				 BLOCK_INFO_INPUT_ID(blk->block_info),
831 				 &d71_improc_funcs, IPS_NUM_INPUT_IDS,
832 				 get_valid_inputs(blk),
833 				 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
834 	if (IS_ERR(c)) {
835 		DRM_ERROR("Failed to add improc component\n");
836 		return PTR_ERR(c);
837 	}
838 
839 	improc = to_improc(c);
840 	improc->supported_color_depths = BIT(8) | BIT(10);
841 	improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
842 					  DRM_COLOR_FORMAT_YCRCB444 |
843 					  DRM_COLOR_FORMAT_YCRCB422;
844 	value = malidp_read32(reg, BLK_INFO);
845 	if (value & IPS_INFO_CHD420)
846 		improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
847 
848 	improc->supports_csc = true;
849 	improc->supports_gamma = true;
850 
851 	return 0;
852 }
853 
854 static void d71_timing_ctrlr_disable(struct komeda_component *c)
855 {
856 	malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
857 }
858 
859 static void d71_timing_ctrlr_update(struct komeda_component *c,
860 				    struct komeda_component_state *state)
861 {
862 	struct drm_crtc_state *crtc_st = state->crtc->state;
863 	u32 __iomem *reg = c->reg;
864 	struct videomode vm;
865 	u32 value;
866 
867 	drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm);
868 
869 	malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive));
870 	malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch,
871 							vm.hback_porch));
872 	malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch,
873 							vm.vback_porch));
874 
875 	value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len);
876 	value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0;
877 	value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0;
878 	malidp_write32(reg, BS_SYNC, value);
879 
880 	malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
881 	malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
882 
883 	/* configure bs control register */
884 	value = BS_CTRL_EN | BS_CTRL_VM;
885 
886 	malidp_write32(reg, BLK_CONTROL, value);
887 }
888 
889 static void d71_timing_ctrlr_dump(struct komeda_component *c,
890 				  struct seq_file *sf)
891 {
892 	u32 v[8], i;
893 
894 	dump_block_header(sf, c->reg);
895 
896 	get_values_from_reg(c->reg, 0xC0, 1, v);
897 	seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
898 
899 	get_values_from_reg(c->reg, 0xD0, 8, v);
900 	seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
901 	seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
902 	seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
903 	seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
904 	seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
905 	seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
906 	seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
907 	seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
908 
909 	get_values_from_reg(c->reg, 0x100, 3, v);
910 	seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
911 	seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
912 	seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
913 
914 	get_values_from_reg(c->reg, 0x110, 3, v);
915 	for (i = 0; i < 3; i++)
916 		seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
917 
918 	get_values_from_reg(c->reg, 0x120, 5, v);
919 	for (i = 0; i < 2; i++) {
920 		seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
921 		seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
922 	}
923 	seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
924 }
925 
926 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
927 	.update		= d71_timing_ctrlr_update,
928 	.disable	= d71_timing_ctrlr_disable,
929 	.dump_register	= d71_timing_ctrlr_dump,
930 };
931 
932 static int d71_timing_ctrlr_init(struct d71_dev *d71,
933 				 struct block_header *blk, u32 __iomem *reg)
934 {
935 	struct komeda_component *c;
936 	struct komeda_timing_ctrlr *ctrlr;
937 	u32 pipe_id, comp_id;
938 
939 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
940 
941 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
942 				 KOMEDA_COMPONENT_TIMING_CTRLR,
943 				 BLOCK_INFO_INPUT_ID(blk->block_info),
944 				 &d71_timing_ctrlr_funcs,
945 				 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
946 				 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
947 	if (IS_ERR(c)) {
948 		DRM_ERROR("Failed to add display_ctrl component\n");
949 		return PTR_ERR(c);
950 	}
951 
952 	ctrlr = to_ctrlr(c);
953 
954 	ctrlr->supports_dual_link = true;
955 
956 	return 0;
957 }
958 
959 int d71_probe_block(struct d71_dev *d71,
960 		    struct block_header *blk, u32 __iomem *reg)
961 {
962 	struct d71_pipeline *pipe;
963 	int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
964 
965 	int err = 0;
966 
967 	switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
968 	case D71_BLK_TYPE_GCU:
969 		break;
970 
971 	case D71_BLK_TYPE_LPU:
972 		pipe = d71->pipes[blk_id];
973 		pipe->lpu_addr = reg;
974 		break;
975 
976 	case D71_BLK_TYPE_LPU_LAYER:
977 		err = d71_layer_init(d71, blk, reg);
978 		break;
979 
980 	case D71_BLK_TYPE_LPU_WB_LAYER:
981 		err = d71_wb_layer_init(d71, blk, reg);
982 		break;
983 
984 	case D71_BLK_TYPE_CU:
985 		pipe = d71->pipes[blk_id];
986 		pipe->cu_addr = reg;
987 		err = d71_compiz_init(d71, blk, reg);
988 		break;
989 
990 	case D71_BLK_TYPE_CU_SCALER:
991 		err = d71_scaler_init(d71, blk, reg);
992 		break;
993 
994 	case D71_BLK_TYPE_CU_SPLITTER:
995 	case D71_BLK_TYPE_CU_MERGER:
996 		break;
997 
998 	case D71_BLK_TYPE_DOU:
999 		pipe = d71->pipes[blk_id];
1000 		pipe->dou_addr = reg;
1001 		break;
1002 
1003 	case D71_BLK_TYPE_DOU_IPS:
1004 		err = d71_improc_init(d71, blk, reg);
1005 		break;
1006 
1007 	case D71_BLK_TYPE_DOU_FT_COEFF:
1008 		pipe = d71->pipes[blk_id];
1009 		pipe->dou_ft_coeff_addr = reg;
1010 		break;
1011 
1012 	case D71_BLK_TYPE_DOU_BS:
1013 		err = d71_timing_ctrlr_init(d71, blk, reg);
1014 		break;
1015 
1016 	case D71_BLK_TYPE_GLB_LT_COEFF:
1017 		break;
1018 
1019 	case D71_BLK_TYPE_GLB_SCL_COEFF:
1020 		d71->glb_scl_coeff_addr[blk_id] = reg;
1021 		break;
1022 
1023 	default:
1024 		DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
1025 			  blk->block_info);
1026 		err = -EINVAL;
1027 		break;
1028 	}
1029 
1030 	return err;
1031 }
1032 
1033 const struct komeda_pipeline_funcs d71_pipeline_funcs = {
1034 	.downscaling_clk_check = d71_downscaling_clk_check,
1035 };
1036