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