int construct_block_layer_info_offline(uint32_t input_startpos, uint32_t input_width,
	dss_rect_t src_rect, dss_layer_t *layer_cut_block)
{
	dss_rect_t rect_trsform = {0};

	switch (layer_cut_block->transform) {
	case HISI_FB_TRANSFORM_NOP:
	case HISI_FB_TRANSFORM_FLIP_V:
		rect_trsform.x = src_rect.x + input_startpos;
		rect_trsform.y = src_rect.y;
		rect_trsform.w = input_width;
		rect_trsform.h = src_rect.h;
		break;
	case HISI_FB_TRANSFORM_FLIP_H:
	case HISI_FB_TRANSFORM_ROT_180:
		rect_trsform.x = src_rect.x + src_rect.w - input_startpos - input_width;
		rect_trsform.y = src_rect.y;
		rect_trsform.w = input_width;
		rect_trsform.h = src_rect.h;
		break;
	case HISI_FB_TRANSFORM_ROT_90:
	case HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_H:
		rect_trsform.x = src_rect.x;
		rect_trsform.y = src_rect.y + src_rect.h - input_startpos - input_width;
		rect_trsform.w = src_rect.w;
		rect_trsform.h = input_width;
		break;
	case HISI_FB_TRANSFORM_ROT_90 | HISI_FB_TRANSFORM_FLIP_V:
	case HISI_FB_TRANSFORM_ROT_270:
		rect_trsform.x = src_rect.x;
		rect_trsform.y = src_rect.y + input_startpos;
		rect_trsform.w = src_rect.w;
		rect_trsform.h = input_width;
		break;
	default:
		HISI_BA_ERR("unknow dss_layer->transform: %d\n",layer_cut_block->transform);
		return 1;
	}

	/* modify src_rect_mask */
	rect_across_rect(rect_trsform, layer_cut_block->src_rect_mask, &layer_cut_block->src_rect_mask);

	/* modify src */
	//layer_cut_block->src.width = rect_trsform.w;
	//layer_cut_block->src.height = rect_trsform.h;

	/* modify src_rect */
	memcpy(&layer_cut_block->src_rect, &rect_trsform, sizeof(rect_trsform));

	return 0;
}
int get_block_layers(dss_overlay_t *dss_overlay, dss_rect_t block_rect,
	dss_overlay_t *dss_overlay_block)
{
	uint32_t i;
	int status = 0;
	int block_layer_num = 0;
	int FirstTile = 0;
	int LastTile = 0;
	int layer_index = 0;
	int input_startpos = 0;
	int input_endpos = 0;
	int is_dpe2 = 0;

	block_cfg_t b_cfg;
	block_detail_t b_detail;
	uint32_t output_startpos;  /* relative to overlay plane */
	uint32_t output_span;
	dss_layer_t *dss_layer = NULL;
	dss_rect_t dst_cross_rect;
	uint32_t src_layer_span;
	uint32_t acc_hscl = 0;

	/* if layer has no vertical scf, then horizontal
	   scf input can larger than scf_line_buf
	*/
	int scf_linebuf_vertic_check = 1;

	if (!dss_overlay_block || !block_rect.w || !block_rect.h) {
		HISI_BA_ERR("invaild args\n");
		return -1;
	}

	if (!block_algorithm_need(dss_overlay)) {
		/* must all layer in the block_rect*/
		memcpy(dss_overlay_block, dss_overlay, sizeof(dss_overlay_t));
		return 0;
	}

	/* do some init */
	memcpy(&dss_overlay_block->wb_layer_info, &dss_overlay->wb_layer_info, sizeof(dss_wb_layer_t));
	dss_overlay_block->layer_nums = 0;
	//dss_overlay_block->mmu_enable = dss_overlay->mmu_enable;

	for (i = 0; i < dss_overlay->layer_nums; i++) {
		dss_layer = &dss_overlay->layer_infos[i];
		block_layer_num = dss_overlay_block->layer_nums;
		status = rect_across_rect(dss_layer->dst_rect, block_rect, &dst_cross_rect);
		if (status == 0)
			continue;

		output_startpos = dst_cross_rect.x - dss_layer->dst_rect.x;
		output_span = dst_cross_rect.w;
		if ((output_span < SCF_MIN_OUTPUT) && (dss_layer->need_cap & CAP_SCL)) {
			HISI_BA_ERR("block layer[%d] scf output smaller than SCF_MIN_OUTPUT, dump some info\
				dss_layer dst{%d,%d,%d,%d} block_rect{%d,%d,%d,%d}\n",
			dss_layer->chn_idx,
			dss_layer->dst_rect.x,dss_layer->dst_rect.y,
			dss_layer->dst_rect.w,dss_layer->dst_rect.h,
			block_rect.x,block_rect.y,
			block_rect.w,block_rect.h);
			return -2;
		}

		FirstTile = (dss_layer->dst_rect.x >= block_rect.x) ? 1 : 0;
		LastTile = (block_rect.x + block_rect.w > dss_layer->dst_rect.x + dss_layer->dst_rect.w) ? 1 : 0;

		memcpy(&dss_overlay_block->layer_infos[block_layer_num],
			dss_layer, sizeof(dss_layer_t));

		dss_overlay_block->layer_nums++;
		dss_overlay_block->layer_infos[block_layer_num].block_info.first_tile = FirstTile;
		dss_overlay_block->layer_infos[block_layer_num].block_info.last_tile = LastTile;
		memcpy(&dss_overlay_block->layer_infos[block_layer_num].dst_rect,
			&dst_cross_rect, sizeof(dss_rect_t));

		dss_overlay_block->layer_infos[block_layer_num].layer_idx = layer_index++;

		init_block_cfg(&b_detail);
		if (dss_layer->need_cap & CAP_SCL) {
			construt_block_info(dss_layer, &b_cfg, &b_detail);
			if (dss_layer->need_cap & CAP_ROT) {
				src_layer_span = dss_layer->src_rect.h;
                                scf_linebuf_vertic_check = !(dss_layer->src_rect.w == dss_layer->dst_rect.h);
                        } else {
                                src_layer_span = dss_layer->src_rect.w;
                                scf_linebuf_vertic_check = !(dss_layer->src_rect.h == dss_layer->dst_rect.h);
                        }

			is_dpe2 = (dss_layer->chn_idx <= DPE2_CHN3) ? 1 : 0;
			if (GeomInputPlane_offline(FirstTile, LastTile, b_cfg, b_detail.inc_hscl,
					output_startpos, output_span, 0, src_layer_span, is_dpe2, scf_linebuf_vertic_check,
					&acc_hscl, &input_startpos, &input_endpos) != 0)
				return -3;

			dss_overlay_block->layer_infos[block_layer_num].block_info.acc_hscl = acc_hscl;
		} else {
			input_startpos = output_startpos;
			input_endpos = output_startpos + output_span - 1;
		}

		dss_overlay_block->layer_infos[block_layer_num].block_info.h_v_order = b_detail.h_v_order;
		dss_overlay_block->layer_infos[block_layer_num].block_info.h_ratio = b_detail.inc_hscl;
		dss_overlay_block->layer_infos[block_layer_num].block_info.v_ratio = b_detail.inc_vscl;

		construct_block_layer_info_offline(input_startpos,
			input_endpos - input_startpos + 1,
			dss_layer->src_rect,
			&dss_overlay_block->layer_infos[block_layer_num]);
	}
int k3_ov_offline_play(struct k3_fb_data_type *k3fd, unsigned long *argp)
{
	char __iomem *dss_base = NULL;
	dss_overlay_t *pov_req = NULL;
	dss_layer_t *layer = NULL;
	dss_wb_layer_t *wb_layer = NULL;
	int i = 0;
	int k = 0;
	int ret = 0;
	struct fb_info *fbi = NULL;
	int block_num = 0;
	dss_rect_t wb_block_rect;
	struct timeval tv;
	u32 flag;
	u32 wbe_chn = 0;
	bool first_valid_block = true;

	BUG_ON(k3fd == NULL);
	fbi = k3fd->fbi;
	BUG_ON(fbi == NULL);
	pov_req = &(k3fd->ov_req);
	BUG_ON(pov_req == NULL);

	dss_base = k3fd->dss_base;

	do_gettimeofday(&tv);
	flag = tv.tv_usec;

	/*lock for k3fd data*/
	down(&k3fd->ov_wb_sem);

	ret = copy_from_user(pov_req, argp, sizeof(dss_overlay_t));
	if (ret) {
		K3_FB_ERR("copy_from_user failed!\n");
		goto err_nodump;
	}

	wb_layer = &(k3fd->ov_req.wb_layer_info);
	wbe_chn = wb_layer->chn_idx - WBE1_CHN0;
	if(wbe_chn >= K3_DSS_OFFLINE_MAX_NUM){
		K3_FB_ERR("write back chn:%d not surport!\n",wb_layer->chn_idx);
		goto err_nodump;
	}

	if (fbi->fbops->fb_blank)
		fbi->fbops->fb_blank(FB_BLANK_UNBLANK, fbi);

	/*in case of single channel fail.*/
	if (k3fd->offline_wb_status[wbe_chn] == e_status_idle) {
		cmdlist_config_start(k3fd, wbe_chn);
		k3fd->offline_wb_status[wbe_chn] = e_status_wait;
	}

	ret = get_block_rect(pov_req, (wb_layer->dst_rect.x + wb_layer->dst_rect.w),
			(wb_layer->dst_rect.y + wb_layer->dst_rect.h), &block_num, k3fd->block_rects);
	if ((ret != 0) || (block_num == 0)|| block_num >= K3_DSS_OFFLINE_MAX_BLOCK) {
		K3_FB_ERR("get_block_rect failed! ret = %d, block_num[%d]\n", ret, block_num);
		goto err_return;
	}

	for (k = 0; k < block_num; k++) {
		ret = get_block_layers(pov_req, *k3fd->block_rects[k], k3fd->block_overlay);
		if (ret != 0) {
			K3_FB_ERR("get_block_layers err ret = %d\n", ret);
			goto err_return;
		}

		ret = rect_across_rect(*k3fd->block_rects[k], wb_layer->src_rect, &wb_block_rect);
		if (ret == 0) {
			K3_FB_ERR("no cross! block_rects[%d]{%d %d %d %d}, wb src_rect{%d %d %d %d}\n", k,
				k3fd->block_rects[k]->x, k3fd->block_rects[k]->y,
				k3fd->block_rects[k]->w, k3fd->block_rects[k]->h,
				wb_layer->src_rect.x, wb_layer->src_rect.y, wb_layer->src_rect.w, wb_layer->src_rect.h);
			continue;
		}

		if (true == first_valid_block) {
			ret = k3_dss_module_init(k3fd);
			if (ret != 0) {
				K3_FB_ERR("k3_dss_module_init failed! ret = %d\n", ret);
				goto err_return;
			}
		}

		if(g_debug_ovl_offline_cmdlist - 1 == k){
			ret = cmdlist_add_new_list(k3fd, &k3fd->offline_cmdlist_head[wbe_chn], TRUE, flag);
		}else{
			ret = cmdlist_add_new_list(k3fd, &k3fd->offline_cmdlist_head[wbe_chn], FALSE, flag);
		}
		if(ret != 0){
			K3_FB_ERR("cmdlist_add_new_list err:%d \n",ret);
			return ret;
		}

		if (true == first_valid_block) {
			offline_stop_glb(k3fd, wbe_chn);
			k3_dss_scf_coef_load(k3fd);
			first_valid_block = false;
		}

		k3_adp_offline_start_disable(k3fd, pov_req);

		if (g_debug_ovl_offline_composer == 1) {
			K3_FB_INFO("dump block_overlay:\n");

			K3_FB_INFO("{%d %d %d %d} cross {%d %d %d %d} = {%d %d %d %d}\n",
				k3fd->block_rects[k]->x, k3fd->block_rects[k]->y,
				k3fd->block_rects[k]->w, k3fd->block_rects[k]->h,
				wb_layer->src_rect.x, wb_layer->src_rect.y,
				wb_layer->src_rect.w, wb_layer->src_rect.h,
				wb_block_rect.x, wb_block_rect.y,
				wb_block_rect.w, wb_block_rect.h);
		}

		k3_dss_handle_cur_ovl_req(k3fd, k3fd->block_overlay);
		k3_dss_handle_cur_ovl_req_wb(k3fd, k3fd->block_overlay);

		ret = k3_dss_ovl_base_config(k3fd, &wb_block_rect, k3fd->ov_req.ovl_flags);
		if (ret != 0) {
			K3_FB_ERR("k3_dss_ovl_init failed! ret = %d\n", ret);
			goto err_return;
		}

		ret = k3_dss_rdma_bridge_config(k3fd, k3fd->block_overlay);
		if (ret != 0) {
			K3_FB_ERR("k3_dss_rdma_bridge_config failed! ret = %d\n", ret);
			goto err_return;
		}

		/* Go through all layers */
		for (i = 0; i < k3fd->block_overlay->layer_nums; i++) {
			layer = &k3fd->block_overlay->layer_infos[i];

			ret = k3_dss_offline_one_layer_config(k3fd, layer, &wb_block_rect);
			if (ret != 0) {
				K3_FB_ERR("k3_dss_offline_one_layer_config failed, ret = %d\n", ret);
				goto err_return;
			}
		}

		ret = k3_dss_write_back_config(k3fd, wb_layer, &wb_block_rect);
		if (ret != 0) {
			K3_FB_ERR("k3_dss_offline_one_layer_config failed, ret = %d\n", ret);
			goto err_return;
		}

		ret = k3_dss_module_config(k3fd);
		if (ret != 0) {
			K3_FB_ERR("k3_dss_module_config failed! ret = %d\n", ret);
			goto err_return;
		}

		k3_adp_offline_start_enable(k3fd, k3fd->block_overlay);

		if (k < (block_num - 1)) {
			ret = k3_dss_module_init(k3fd);
			if (ret != 0) {
				K3_FB_ERR("k3_dss_module_init failed! ret = %d\n", ret);
				goto err_return;
			}

			k3_dss_handle_prev_ovl_req(k3fd, k3fd->block_overlay);
			k3_dss_handle_prev_ovl_req_wb(k3fd, k3fd->block_overlay);
		}
	}

	ret = offline_add_pending_frame(k3fd, wbe_chn, flag);
	if (ret != 0) {
		K3_FB_ERR("offline_add_virtual_frame failed! ret = %d\n", ret);
		goto err_return;
	}

	cmdlist_frame_valid(&k3fd->offline_cmdlist_head[wbe_chn]);

	cmdlist_add_nop_list(k3fd, &k3fd->offline_cmdlist_head[wbe_chn], FALSE);

#ifdef CONFIG_BUF_SYNC_USED
	for (i = 0; i < pov_req->layer_nums; i++) {
		if (pov_req->layer_infos[i].acquire_fence >= 0){
			k3fb_buf_sync_wait(pov_req->layer_infos[i].acquire_fence);
		}
	}
#endif

	//flush cache before start frame
	cmdlist_flush_cmdlistmemory_cache(&k3fd->offline_cmdlist_head[wbe_chn], k3fd->ion_client);

	cmdlist_start_frame(k3fd, wbe_chn);

	/*unlock for k3fd data*/
	up(&k3fd->ov_wb_sem);

	/*lock if use dpe3 chn0 and chn1*/
	offline_chn_lock(k3fd);

	ret = wait_event_interruptible_timeout(k3fd->offline_writeback_wq[wbe_chn],
			(k3fd->offline_wb_done[wbe_chn] == flag), msecs_to_jiffies(OFFLINE_COMPOSE_TIMEOUT));

	/*unlock if use dpe3 chn0 and chn1*/
	offline_chn_unlock(k3fd);

	/*lock for k3fd data*/
	down(&k3fd->ov_wb_sem);

	cmdlist_prepare_next_frame(k3fd, wbe_chn);
	cmdlist_free_nop(&k3fd->offline_cmdlist_head[wbe_chn], k3fd->ion_client);

	if (ret <= 0) {
		ret = -ETIMEDOUT;

		if(g_debug_ovl_offline_composer > 0)
			offline_dump_fail_reg(dss_base, pov_req, tv.tv_sec);

		offline_fail_proccess(k3fd, wbe_chn, block_num);
		goto err_return;
	}

	ret = 0;

err_return:
	if (ret != 0 && g_debug_ovl_offline_composer > 0) {
		do_gettimeofday(&tv);
		offline_dump_fail_info_to_file(pov_req, tv.tv_sec);
	}
err_nodump:
	cmdlist_free_frame(&k3fd->offline_cmdlist_head[wbe_chn], k3fd->ion_client);

	k3_dss_rptb_handler(k3fd, false, wbe_chn);
	k3_dss_rptb_handler(k3fd, true, wbe_chn);

	if(g_debug_ovl_offline_composer == 3) {
		do_gettimeofday(&tv);
		offline_dump_fail_info_to_file(pov_req, tv.tv_sec);
		g_debug_ovl_offline_composer = 0;
	}

	if(first_valid_block == false)
		k3_dss_scf_coef_unload(k3fd);

	if ((k3fd->offline_wb_status[0] <= e_status_wait) &&
		(k3fd->offline_wb_status[1] <= e_status_wait) &&
		fbi->fbops->fb_blank &&
		!g_debug_dss_adp_sr) {
		fbi->fbops->fb_blank(FB_BLANK_POWERDOWN, fbi);
	}

	/*unlock for k3fd data*/
	up(&k3fd->ov_wb_sem);

	if(g_debug_ovl_offline_composer == 2) {
		struct timeval tv_last;
		u32 use_time = 0;
		do_gettimeofday(&tv_last);
		use_time = (tv_last.tv_sec - tv.tv_sec) * 1000 + (tv_last.tv_usec - tv.tv_usec) /1000;
		printk("--use:%d ms \n",use_time);
	}
	return ret;
}