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 
437 static void compiz_enable_input(u32 __iomem *id_reg,
438 				u32 __iomem *cfg_reg,
439 				u32 input_hw_id,
440 				struct komeda_compiz_input_cfg *cin)
441 {
442 	u32 ctrl = CU_INPUT_CTRL_EN;
443 	u8 blend = cin->pixel_blend_mode;
444 
445 	if (blend == DRM_MODE_BLEND_PIXEL_NONE)
446 		ctrl |= CU_INPUT_CTRL_PAD;
447 	else if (blend == DRM_MODE_BLEND_PREMULTI)
448 		ctrl |= CU_INPUT_CTRL_PMUL;
449 
450 	ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha);
451 
452 	malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id);
453 
454 	malidp_write32(cfg_reg, CU_INPUT0_SIZE,
455 		       HV_SIZE(cin->hsize, cin->vsize));
456 	malidp_write32(cfg_reg, CU_INPUT0_OFFSET,
457 		       HV_OFFSET(cin->hoffset, cin->voffset));
458 	malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl);
459 }
460 
461 static void d71_compiz_update(struct komeda_component *c,
462 			      struct komeda_component_state *state)
463 {
464 	struct komeda_compiz_state *st = to_compiz_st(state);
465 	u32 __iomem *reg = c->reg;
466 	u32 __iomem *id_reg, *cfg_reg;
467 	u32 index, input_hw_id;
468 
469 	for_each_changed_input(state, index) {
470 		id_reg = reg + index;
471 		cfg_reg = reg + index * CU_PER_INPUT_REGS;
472 		input_hw_id = to_d71_input_id(&state->inputs[index]);
473 		if (state->active_inputs & BIT(index)) {
474 			compiz_enable_input(id_reg, cfg_reg,
475 					    input_hw_id, &st->cins[index]);
476 		} else {
477 			malidp_write32(id_reg, BLK_INPUT_ID0, 0);
478 			malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0);
479 		}
480 	}
481 
482 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
483 }
484 
485 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
486 {
487 	u32 v[8], i;
488 
489 	dump_block_header(sf, c->reg);
490 
491 	get_values_from_reg(c->reg, 0x80, 5, v);
492 	for (i = 0; i < 5; i++)
493 		seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
494 
495 	get_values_from_reg(c->reg, 0xA0, 5, v);
496 	seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
497 	seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
498 	seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
499 	seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
500 	seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
501 
502 	get_values_from_reg(c->reg, 0xD0, 2, v);
503 	seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
504 	seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
505 
506 	get_values_from_reg(c->reg, 0xDC, 1, v);
507 	seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
508 
509 	for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
510 		get_values_from_reg(c->reg, v[4], 3, v);
511 		seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
512 		seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
513 		seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
514 	}
515 
516 	get_values_from_reg(c->reg, 0x130, 2, v);
517 	seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
518 	seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
519 }
520 
521 static const struct komeda_component_funcs d71_compiz_funcs = {
522 	.update		= d71_compiz_update,
523 	.disable	= d71_component_disable,
524 	.dump_register	= d71_compiz_dump,
525 };
526 
527 static int d71_compiz_init(struct d71_dev *d71,
528 			   struct block_header *blk, u32 __iomem *reg)
529 {
530 	struct komeda_component *c;
531 	struct komeda_compiz *compiz;
532 	u32 pipe_id, comp_id;
533 
534 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
535 
536 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz),
537 				 comp_id,
538 				 BLOCK_INFO_INPUT_ID(blk->block_info),
539 				 &d71_compiz_funcs,
540 				 CU_NUM_INPUT_IDS, get_valid_inputs(blk),
541 				 CU_NUM_OUTPUT_IDS, reg,
542 				 "CU%d", pipe_id);
543 	if (IS_ERR(c))
544 		return PTR_ERR(c);
545 
546 	compiz = to_compiz(c);
547 
548 	set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size);
549 	set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize);
550 
551 	return 0;
552 }
553 
554 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in,
555 					 u32 vsize_in, u32 hsize_out,
556 					 u32 vsize_out)
557 {
558 	u32 val = 0;
559 
560 	if (hsize_in <= hsize_out)
561 		val  |= 0x62;
562 	else if (hsize_in <= (hsize_out + hsize_out / 2))
563 		val |= 0x63;
564 	else if (hsize_in <= hsize_out * 2)
565 		val |= 0x64;
566 	else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4)
567 		val |= 0x65;
568 	else
569 		val |= 0x66;
570 
571 	if (vsize_in <= vsize_out)
572 		val  |= SC_VTSEL(0x6A);
573 	else if (vsize_in <= (vsize_out + vsize_out / 2))
574 		val |= SC_VTSEL(0x6B);
575 	else if (vsize_in <= vsize_out * 2)
576 		val |= SC_VTSEL(0x6C);
577 	else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4)
578 		val |= SC_VTSEL(0x6D);
579 	else
580 		val |= SC_VTSEL(0x6E);
581 
582 	malidp_write32(reg, SC_COEFFTAB, val);
583 }
584 
585 static void d71_scaler_update(struct komeda_component *c,
586 			      struct komeda_component_state *state)
587 {
588 	struct komeda_scaler_state *st = to_scaler_st(state);
589 	u32 __iomem *reg = c->reg;
590 	u32 init_ph, delta_ph, ctrl;
591 
592 	d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in,
593 				     st->hsize_out, st->vsize_out);
594 
595 	malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in));
596 	malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out));
597 
598 	init_ph = (st->hsize_in << 15) / st->hsize_out;
599 	malidp_write32(reg, SC_H_INIT_PH, init_ph);
600 
601 	delta_ph = (st->hsize_in << 16) / st->hsize_out;
602 	malidp_write32(reg, SC_H_DELTA_PH, delta_ph);
603 
604 	init_ph = (st->vsize_in << 15) / st->vsize_out;
605 	malidp_write32(reg, SC_V_INIT_PH, init_ph);
606 
607 	delta_ph = (st->vsize_in << 16) / st->vsize_out;
608 	malidp_write32(reg, SC_V_DELTA_PH, delta_ph);
609 
610 	ctrl = 0;
611 	ctrl |= st->en_scaling ? SC_CTRL_SCL : 0;
612 	ctrl |= st->en_alpha ? SC_CTRL_AP : 0;
613 
614 	malidp_write32(reg, BLK_CONTROL, ctrl);
615 	malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0]));
616 }
617 
618 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf)
619 {
620 	u32 v[9];
621 
622 	dump_block_header(sf, c->reg);
623 
624 	get_values_from_reg(c->reg, 0x80, 1, v);
625 	seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]);
626 
627 	get_values_from_reg(c->reg, 0xD0, 1, v);
628 	seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]);
629 
630 	get_values_from_reg(c->reg, 0xDC, 9, v);
631 	seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]);
632 	seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]);
633 	seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]);
634 	seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]);
635 	seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]);
636 	seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]);
637 	seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]);
638 	seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]);
639 	seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]);
640 }
641 
642 static const struct komeda_component_funcs d71_scaler_funcs = {
643 	.update		= d71_scaler_update,
644 	.disable	= d71_component_disable,
645 	.dump_register	= d71_scaler_dump,
646 };
647 
648 static int d71_scaler_init(struct d71_dev *d71,
649 			   struct block_header *blk, u32 __iomem *reg)
650 {
651 	struct komeda_component *c;
652 	struct komeda_scaler *scaler;
653 	u32 pipe_id, comp_id;
654 
655 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
656 
657 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler),
658 				 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info),
659 				 &d71_scaler_funcs,
660 				 1, get_valid_inputs(blk), 1, reg,
661 				 "CU%d_SCALER%d",
662 				 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info));
663 
664 	if (IS_ERR(c)) {
665 		DRM_ERROR("Failed to initialize scaler");
666 		return PTR_ERR(c);
667 	}
668 
669 	scaler = to_scaler(c);
670 	set_range(&scaler->hsize, 4, d71->max_line_size);
671 	set_range(&scaler->vsize, 4, 4096);
672 	scaler->max_downscaling = 6;
673 	scaler->max_upscaling = 64;
674 
675 	malidp_write32(c->reg, BLK_CONTROL, 0);
676 
677 	return 0;
678 }
679 
680 static void d71_improc_update(struct komeda_component *c,
681 			      struct komeda_component_state *state)
682 {
683 	struct komeda_improc_state *st = to_improc_st(state);
684 	u32 __iomem *reg = c->reg;
685 	u32 index, input_hw_id;
686 
687 	for_each_changed_input(state, index) {
688 		input_hw_id = state->active_inputs & BIT(index) ?
689 			      to_d71_input_id(&state->inputs[index]) : 0;
690 		malidp_write32(reg, BLK_INPUT_ID0 + index * 4, input_hw_id);
691 	}
692 
693 	malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
694 }
695 
696 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
697 {
698 	u32 v[12], i;
699 
700 	dump_block_header(sf, c->reg);
701 
702 	get_values_from_reg(c->reg, 0x80, 2, v);
703 	seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
704 	seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
705 
706 	get_values_from_reg(c->reg, 0xC0, 1, v);
707 	seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
708 
709 	get_values_from_reg(c->reg, 0xD0, 3, v);
710 	seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
711 	seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
712 	seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
713 
714 	get_values_from_reg(c->reg, 0x130, 12, v);
715 	for (i = 0; i < 12; i++)
716 		seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
717 
718 	get_values_from_reg(c->reg, 0x170, 12, v);
719 	for (i = 0; i < 12; i++)
720 		seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
721 }
722 
723 static const struct komeda_component_funcs d71_improc_funcs = {
724 	.update		= d71_improc_update,
725 	.disable	= d71_component_disable,
726 	.dump_register	= d71_improc_dump,
727 };
728 
729 static int d71_improc_init(struct d71_dev *d71,
730 			   struct block_header *blk, u32 __iomem *reg)
731 {
732 	struct komeda_component *c;
733 	struct komeda_improc *improc;
734 	u32 pipe_id, comp_id, value;
735 
736 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
737 
738 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc),
739 				 comp_id,
740 				 BLOCK_INFO_INPUT_ID(blk->block_info),
741 				 &d71_improc_funcs, IPS_NUM_INPUT_IDS,
742 				 get_valid_inputs(blk),
743 				 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id);
744 	if (IS_ERR(c)) {
745 		DRM_ERROR("Failed to add improc component\n");
746 		return PTR_ERR(c);
747 	}
748 
749 	improc = to_improc(c);
750 	improc->supported_color_depths = BIT(8) | BIT(10);
751 	improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 |
752 					  DRM_COLOR_FORMAT_YCRCB444 |
753 					  DRM_COLOR_FORMAT_YCRCB422;
754 	value = malidp_read32(reg, BLK_INFO);
755 	if (value & IPS_INFO_CHD420)
756 		improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420;
757 
758 	improc->supports_csc = true;
759 	improc->supports_gamma = true;
760 
761 	return 0;
762 }
763 
764 static void d71_timing_ctrlr_disable(struct komeda_component *c)
765 {
766 	malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0);
767 }
768 
769 static void d71_timing_ctrlr_update(struct komeda_component *c,
770 				    struct komeda_component_state *state)
771 {
772 	struct drm_crtc_state *crtc_st = state->crtc->state;
773 	u32 __iomem *reg = c->reg;
774 	struct videomode vm;
775 	u32 value;
776 
777 	drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm);
778 
779 	malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive));
780 	malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch,
781 							vm.hback_porch));
782 	malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch,
783 							vm.vback_porch));
784 
785 	value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len);
786 	value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0;
787 	value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0;
788 	malidp_write32(reg, BS_SYNC, value);
789 
790 	malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1);
791 	malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE);
792 
793 	/* configure bs control register */
794 	value = BS_CTRL_EN | BS_CTRL_VM;
795 
796 	malidp_write32(reg, BLK_CONTROL, value);
797 }
798 
799 static void d71_timing_ctrlr_dump(struct komeda_component *c,
800 				  struct seq_file *sf)
801 {
802 	u32 v[8], i;
803 
804 	dump_block_header(sf, c->reg);
805 
806 	get_values_from_reg(c->reg, 0xC0, 1, v);
807 	seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
808 
809 	get_values_from_reg(c->reg, 0xD0, 8, v);
810 	seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
811 	seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
812 	seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
813 	seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
814 	seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
815 	seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
816 	seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
817 	seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
818 
819 	get_values_from_reg(c->reg, 0x100, 3, v);
820 	seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
821 	seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
822 	seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
823 
824 	get_values_from_reg(c->reg, 0x110, 3, v);
825 	for (i = 0; i < 3; i++)
826 		seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
827 
828 	get_values_from_reg(c->reg, 0x120, 5, v);
829 	for (i = 0; i < 2; i++) {
830 		seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
831 		seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
832 	}
833 	seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
834 }
835 
836 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = {
837 	.update		= d71_timing_ctrlr_update,
838 	.disable	= d71_timing_ctrlr_disable,
839 	.dump_register	= d71_timing_ctrlr_dump,
840 };
841 
842 static int d71_timing_ctrlr_init(struct d71_dev *d71,
843 				 struct block_header *blk, u32 __iomem *reg)
844 {
845 	struct komeda_component *c;
846 	struct komeda_timing_ctrlr *ctrlr;
847 	u32 pipe_id, comp_id;
848 
849 	get_resources_id(blk->block_info, &pipe_id, &comp_id);
850 
851 	c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr),
852 				 KOMEDA_COMPONENT_TIMING_CTRLR,
853 				 BLOCK_INFO_INPUT_ID(blk->block_info),
854 				 &d71_timing_ctrlr_funcs,
855 				 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id),
856 				 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id);
857 	if (IS_ERR(c)) {
858 		DRM_ERROR("Failed to add display_ctrl component\n");
859 		return PTR_ERR(c);
860 	}
861 
862 	ctrlr = to_ctrlr(c);
863 
864 	ctrlr->supports_dual_link = true;
865 
866 	return 0;
867 }
868 
869 int d71_probe_block(struct d71_dev *d71,
870 		    struct block_header *blk, u32 __iomem *reg)
871 {
872 	struct d71_pipeline *pipe;
873 	int blk_id = BLOCK_INFO_BLK_ID(blk->block_info);
874 
875 	int err = 0;
876 
877 	switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) {
878 	case D71_BLK_TYPE_GCU:
879 		break;
880 
881 	case D71_BLK_TYPE_LPU:
882 		pipe = d71->pipes[blk_id];
883 		pipe->lpu_addr = reg;
884 		break;
885 
886 	case D71_BLK_TYPE_LPU_LAYER:
887 		err = d71_layer_init(d71, blk, reg);
888 		break;
889 
890 	case D71_BLK_TYPE_LPU_WB_LAYER:
891 		err = d71_wb_layer_init(d71, blk, reg);
892 		break;
893 
894 	case D71_BLK_TYPE_CU:
895 		pipe = d71->pipes[blk_id];
896 		pipe->cu_addr = reg;
897 		err = d71_compiz_init(d71, blk, reg);
898 		break;
899 
900 	case D71_BLK_TYPE_CU_SCALER:
901 		err = d71_scaler_init(d71, blk, reg);
902 		break;
903 
904 	case D71_BLK_TYPE_CU_SPLITTER:
905 	case D71_BLK_TYPE_CU_MERGER:
906 		break;
907 
908 	case D71_BLK_TYPE_DOU:
909 		pipe = d71->pipes[blk_id];
910 		pipe->dou_addr = reg;
911 		break;
912 
913 	case D71_BLK_TYPE_DOU_IPS:
914 		err = d71_improc_init(d71, blk, reg);
915 		break;
916 
917 	case D71_BLK_TYPE_DOU_FT_COEFF:
918 		pipe = d71->pipes[blk_id];
919 		pipe->dou_ft_coeff_addr = reg;
920 		break;
921 
922 	case D71_BLK_TYPE_DOU_BS:
923 		err = d71_timing_ctrlr_init(d71, blk, reg);
924 		break;
925 
926 	case D71_BLK_TYPE_GLB_LT_COEFF:
927 		break;
928 
929 	case D71_BLK_TYPE_GLB_SCL_COEFF:
930 		d71->glb_scl_coeff_addr[blk_id] = reg;
931 		break;
932 
933 	default:
934 		DRM_ERROR("Unknown block (block_info: 0x%x) is found\n",
935 			  blk->block_info);
936 		err = -EINVAL;
937 		break;
938 	}
939 
940 	return err;
941 }
942