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