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