cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

d71_component.c (41010B)


      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}