When panning the frame buffer, window always becomes dirty.

In TX 2, when panning the frame buffer, win-> dirty = 1 is always executed.
The line 137 of the code below is the process.

int tegra_nvdisp_update_windows(struct tegra_dc *dc,
	struct tegra_dc_win *windows[], int n,
	u16 *dirty_rect, bool wait_for_vblank)
{
	int i;
	u32 update_mask = nvdisp_cmd_state_ctrl_general_update_enable_f();
	u32 act_req_mask = nvdisp_cmd_state_ctrl_general_act_req_enable_f();
	u32 act_control = 0;

	mutex_lock(&tegra_nvdisp_lock);

	/* If any of the window updates requires vsync to program the window
	   update safely, vsync all windows in this flip.  Safety overrides both
	   the requested wait_for_vblank, and also the no_vsync global.
	   The HSync Flip has some restrictions on changes from previous frame.
	   The update_is_hsync_safe() call is used to filter out flips to force
	   the VSync instead. */
	for (i = 0; i < n; i++) {
		struct tegra_dc_win *win = windows[i];

		if ((!wait_for_vblank
			&& !update_is_hsync_safe(
				&dc->shadow_windows[win->idx], win))
			/*|| do_partial_update*/)
			wait_for_vblank = true;

		memcpy(&dc->shadow_windows[win->idx], win, sizeof(*win));
	}

	for (i = 0; i < n; i++) {
		struct tegra_dc_win *win = windows[i];
		struct tegra_dc_win *dc_win;

		if (!win) {
			dev_err(&dc->ndev->dev,
				"Invalid window %d to update\n", i);
			mutex_unlock(&tegra_nvdisp_lock);

			return -EINVAL;
		}

		dc_win = tegra_dc_get_window(dc, win->idx);

		if (!dc_win) {
			dev_err(&dc->ndev->dev,
				"Cannot get window %d to update\n", i);
			mutex_unlock(&tegra_nvdisp_lock);

			return -EINVAL;
		}

		if (!WIN_IS_ENABLED(win)) {
			u32 win_options;

			tegra_nvdisp_set_background_color(dc);
			update_mask |=
				nvdisp_cmd_state_ctrl_win_a_update_enable_f()
				<< win->idx;
			act_req_mask |=
				nvdisp_cmd_state_ctrl_a_act_req_enable_f()
				<< win->idx;

			/* detach the window from the head
			 * this must be written before other window regs */
			nvdisp_win_write(win, win_set_control_owner_none_f(),
					win_set_control_r());

			/* disable scaler (bypass mode) */
			nvdisp_win_write(win, win_scaler_usage_hbypass_f(1) |
				win_scaler_usage_vbypass_f(1) |
				win_scaler_usage_use422_disable_f(),
				win_scaler_usage_r());

			/* disable csc */
			tegra_nvdisp_set_csc(win, &win->csc);
			/*
			 * mark csc_dirty so that next time when window is
			 * enabled, CSC can be programmed.
			 */
			win->csc_dirty = true;

			/* disable cde */
			nvdisp_win_write(win, 0, win_cde_ctrl_r());

			/* disable window */
			win_options = win_options_win_enable_disable_f();
			nvdisp_win_write(win, win_options, win_options_r());

			/* disable HSync Flip */
			wait_for_vblank = true;
			nvdisp_win_write(win,
				win_act_control_ctrl_sel_vcounter_f(),
				win_act_control_r());

			dc_win->dirty = no_vsync ? 0 : 1;
		} else {
			/* attach window to the head */
			nvdisp_win_write(win, dc->ctrl_num,
					win_set_control_r());

			update_mask |= nvdisp_cmd_state_ctrl_win_a_update_enable_f()
				<< win->idx;
			act_req_mask |=  nvdisp_cmd_state_ctrl_a_act_req_enable_f()
				<< win->idx;

			if (wait_for_vblank)
				act_control = win_act_control_ctrl_sel_vcounter_f();
			else
				act_control = win_act_control_ctrl_sel_hcounter_f();

			nvdisp_win_write(win, act_control, win_act_control_r());

			tegra_nvdisp_blend(win);
			tegra_nvdisp_scaling(win);
			tegra_nvdisp_enable_cde(win);

			/* if (do_partial_update) { */
				/* /\* calculate the xoff, yoff etc values *\/ */
				/* tegra_dc_win_partial_update(dc, win, xoff, yoff, */
				/* 	width, height); */
			/* } */

			if (tegra_nvdisp_win_attribute(win, wait_for_vblank)) {
				dev_err(&dc->ndev->dev,
					"win_attribute settings failed\n");
				mutex_unlock(&tegra_nvdisp_lock);

				return -EINVAL;
			}

			if (dc_win->csc_dirty) {
				tegra_nvdisp_set_csc(win, &dc_win->csc);
				dc_win->csc_dirty = false;
			}

			dc_win->dirty = 1;
			win->dirty = 1;
		}

		trace_window_update(dc, win);
	}

	/* If new IMP results are pending, go ahead and program them. */
	if (dc->imp_dirty) {
		tegra_nvdisp_program_imp_results(dc);

		/*
		 * The ihub registers live on the COMMON channel. Update the
		 * masks accordingly so that the COMMON channel state is
		 * promoted along with the WINDOW channel state.
		 */
		update_mask |=
			nvdisp_cmd_state_ctrl_common_act_update_enable_f();
		act_req_mask |= nvdisp_cmd_state_ctrl_common_act_req_enable_f();

		/*
		 * We can safely set the pending flag here since we're holding
		 * the global nvdisp lock.
		 */
		tegra_nvdisp_set_common_channel_pending(dc);
		dc->imp_dirty = false;
	}

	if (wait_for_vblank) {
		/* Use the interrupt handler.  ISR will clear the dirty flags
		   when the flip is completed */
		set_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
		tegra_dc_unmask_interrupt(dc,
			(nvdisp_cmd_int_status_frame_end_f(1) |
			nvdisp_cmd_int_status_v_blank_f(1) |
			nvdisp_cmd_int_status_uf_f(1)));
	}

	if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
		schedule_delayed_work(&dc->one_shot_work,
				msecs_to_jiffies(dc->one_shot_delay_ms));
	}
	dc->crc_pending = true;

	tegra_dc_program_bandwidth(dc, false);

	if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
		act_req_mask |= nvdisp_cmd_state_ctrl_host_trig_enable_f();

	/* cannot set fields related to UPDATE and ACT_REQ in the same write */
	tegra_dc_writel(dc, update_mask, nvdisp_cmd_state_ctrl_r());
	tegra_dc_readl(dc, nvdisp_cmd_state_ctrl_r()); /* flush */
	if (act_req_mask) {
		tegra_dc_writel(dc, act_req_mask, nvdisp_cmd_state_ctrl_r());
		tegra_dc_readl(dc, nvdisp_cmd_state_ctrl_r()); /* flush */
	}

	if (!wait_for_vblank) {
		/* Don't use a interrupt handler for the update, but leave
		   vblank interrupts unmasked since they could be used by other
		   windows.  One window could flip on HBLANK while others flip
		   on VBLANK.  Poll HW until this window update is completed
		   which could take up to 16 scan lines for T18x or time out
		   about a frame period. */
		unsigned int  winmask = act_req_mask &
			((0x3f & dc->pdata->win_mask) << 1)/*WIN_ALL_ACT_REQ*/;
		int  i = 17000;  /* 60Hz frame period in uSec */

		while (tegra_dc_windows_are_dirty(dc, winmask) && --i)
			udelay(1);

		if (i) {
			for (i = 0; i < n; i++)
				windows[i]->dirty = 0;
		} else {  /* time out */
			dev_warn(&dc->ndev->dev, "winmask:0x%x: HSync timeout\n",
				winmask);
		}
	}

	mutex_unlock(&tegra_nvdisp_lock);

	return 0;
}

However, in TX 1 (when TEGRA_NVDISPLAY is invalid), it seems that win-> dirty = 1 is executed only when blending processing is effective.
The following lines 439 to 450 are processing which is executing win-> dirty = 1 only at blend processing.

static int _tegra_dc_program_windows(struct tegra_dc *dc,
	struct tegra_dc_win *windows[], int n, u16 *dirty_rect,
	bool wait_for_vblank)
{
	unsigned long update_mask = GENERAL_ACT_REQ;
	unsigned long act_control = 0;
	unsigned long win_options;
	bool update_blend_par = false;
	bool update_blend_seq = false;
	int i;
	bool do_partial_update = false;
	unsigned int xoff;
	unsigned int yoff;
	unsigned int width;
	unsigned int height;
	u32 val;

	if (dirty_rect) {
		xoff = dirty_rect[0];
		yoff = dirty_rect[1];
		width = dirty_rect[2];
		height = dirty_rect[3];
		do_partial_update = !dc->out_ops->partial_update(dc,
			&xoff, &yoff, &width, &height);

		if (do_partial_update) {
			tegra_dc_writel(dc, width | (height << 16),
				DC_DISP_DISP_ACTIVE);

			dc->disp_active_dirty = true;
		}
	}

	/* If any of the window updates requires vsync to program the window
	   update safely, vsync all windows in this flip.  Safety overrides both
	   the requested wait_for_vblank, and also the no_vsync global. */
	for (i = 0; i < n; i++) {
		struct tegra_dc_win *win = windows[i];
		if ((!wait_for_vblank &&
		    !update_is_hsync_safe(&dc->shadow_windows[win->idx],
					  win)) || do_partial_update)
			wait_for_vblank = 1;

		memcpy(&dc->shadow_windows[win->idx], win,
		       sizeof(struct tegra_dc_win));
	}

	for (i = 0; i < n; i++) {
		struct tegra_dc_win *win = windows[i];
		struct tegra_dc_win *dc_win = tegra_dc_get_window(dc, win->idx);
		bool scan_column = 0;
		fixed20_12 h_offset, v_offset;
		bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
		bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
		bool yuv = tegra_dc_is_yuv(win->fmt);
		bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
		bool yuvsp = tegra_dc_is_yuv_semi_planar(win->fmt);
		unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
		/* Bytes per pixel of bandwidth, used for dda_inc calculation */
		unsigned Bpp_bw = Bpp * ((yuvp || yuvsp) ? 2 : 1);
		bool filter_h;
		bool filter_v;
#if defined(CONFIG_TEGRA_DC_SCAN_COLUMN)
		scan_column = (win->flags & TEGRA_WIN_FLAG_SCAN_COLUMN);
#endif

		tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
				DC_CMD_DISPLAY_WINDOW_HEADER);

		if (!no_vsync)
			update_mask |= WIN_A_ACT_REQ << win->idx;

		if (!WIN_IS_ENABLED(win)) {
		#define RGB_TO_YUV420_8BPC_BLACK_PIX 0x00801010
		#define RGB_TO_YUV422_10BPC_BLACK_PIX 0x00001080
		#define RGB_TO_YUV444_8BPC_BLACK_PIX 0x00801080

			dc_win->dirty = no_vsync ? 0 : 1;
			tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
			if (dc->yuv_bypass) {
				switch(dc->mode.vmode & FB_VMODE_YUV_MASK) {
				case FB_VMODE_Y420 | FB_VMODE_Y24:
				case FB_VMODE_Y420_ONLY | FB_VMODE_Y24:
					tegra_dc_writel(dc,
						RGB_TO_YUV420_8BPC_BLACK_PIX,
						DC_DISP_BLEND_BACKGROUND_COLOR);
					break;
				case FB_VMODE_Y422 | FB_VMODE_Y36:
					tegra_dc_writel(dc,
						RGB_TO_YUV422_10BPC_BLACK_PIX,
						DC_DISP_BLEND_BACKGROUND_COLOR);
					break;
				case FB_VMODE_Y444 | FB_VMODE_Y24:
					tegra_dc_writel(dc,
						RGB_TO_YUV444_8BPC_BLACK_PIX,
						DC_DISP_BLEND_BACKGROUND_COLOR);
					break;
				}
			}
			continue;

		#undef RGB_TO_YUV444_8BPC_BLACK_PIX
		#undef RGB_TO_YUV422_10BPC_BLACK_PIX
		#undef RGB_TO_YUV420_8BPC_BLACK_PIX
		}

		filter_h = win_use_h_filter(dc, win);
		filter_v = win_use_v_filter(dc, win);

		/* Update blender */
		if ((win->z != dc->blend.z[win->idx]) ||
				((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) !=
						dc->blend.flags[win->idx])) {
			dc->blend.z[win->idx] = win->z;
			dc->blend.flags[win->idx] =
					win->flags & TEGRA_WIN_BLEND_FLAGS_MASK;
			if (tegra_dc_feature_is_gen2_blender(dc, win->idx))
				update_blend_seq = true;
			else
				update_blend_par = true;
		}

		tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
				DC_CMD_DISPLAY_WINDOW_HEADER);

		update_mask |= WIN_A_ACT_REQ << win->idx;

		if (wait_for_vblank)
			act_control &= ~WIN_ACT_CNTR_SEL_HCOUNTER(win->idx);
		else
			act_control |= WIN_ACT_CNTR_SEL_HCOUNTER(win->idx);

#if defined(CONFIG_TEGRA_DC_CDE)
		if (win->cde.cde_addr) {
			tegra_dc_writel(dc, ENABLESURFACE0,
				DC_WINBUF_CDE_CONTROL);
			tegra_dc_writel(dc, tegra_dc_reg_l32(win->cde.cde_addr),
				DC_WINBUF_CDE_COMPTAG_BASE_0);
			tegra_dc_writel(dc, tegra_dc_reg_h32(win->cde.cde_addr),
				DC_WINBUF_CDE_COMPTAG_BASEHI_0);

			tegra_dc_writel(dc, win->cde.zbc_color,
				DC_WINBUF_CDE_ZBC_COLOR_0);

			tegra_dc_writel(dc, win->cde.offset_x |
				((u32)win->cde.offset_y << 16),
				DC_WINBUF_CDE_SURFACE_OFFSET_0);
			tegra_dc_writel(dc, win->cde.ctb_entry,
				DC_WINBUF_CDE_CTB_ENTRY_0);
			if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA21
				&& ((tegra_revision == TEGRA_REVISION_A01) ||
					(tegra_revision == TEGRA_REVISION_A01q)))
				tegra_dc_writel(dc, 0, DC_WINBUF_CDE_CG_SW_OVR);
		} else {
			tegra_dc_writel(dc, 0, DC_WINBUF_CDE_CONTROL);
			tegra_dc_writel(dc, 0x00000001,
				DC_WINBUF_CDE_CG_SW_OVR);
		}
#endif
		tegra_dc_writel(dc, tegra_dc_fmt(win->fmt),
			DC_WIN_COLOR_DEPTH);
		tegra_dc_writel(dc, tegra_dc_fmt_byteorder(win->fmt),
			DC_WIN_BYTE_SWAP);


		if (do_partial_update)
			tegra_dc_win_partial_update(dc, win, xoff, yoff,
				width, height);

		tegra_dc_writel(dc,
			V_POSITION(win->out_y) | H_POSITION(win->out_x),
			DC_WIN_POSITION);

		if (tegra_dc_feature_has_interlace(dc, win->idx) &&
			(dc->mode.vmode == FB_VMODE_INTERLACED)) {
				tegra_dc_writel(dc,
					V_SIZE((win->out_h) >> 1) |
					H_SIZE(win->out_w),
					DC_WIN_SIZE);
		} else {
			tegra_dc_writel(dc,
				V_SIZE(win->out_h) | H_SIZE(win->out_w),
				DC_WIN_SIZE);
		}

		win_options = WIN_ENABLE;
		if (scan_column)
			win_options |= WIN_SCAN_COLUMN;

		win_options |= H_FILTER_ENABLE(filter_h);
		win_options |= V_FILTER_ENABLE(filter_v);

		/* Update scaling registers if window supports scaling. */
		if (likely(tegra_dc_feature_has_scaling(dc, win->idx)))
			tegra_dc_update_scaling(dc, win, Bpp, Bpp_bw,
								scan_column);

#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
		tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
		tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
#endif

#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
	defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
		tegra_dc_writel(dc, win->phys_addr, DC_WINBUF_START_ADDR);
#else
		tegra_dc_writel(dc, tegra_dc_reg_l32(win->phys_addr),
			DC_WINBUF_START_ADDR);
		tegra_dc_writel(dc, tegra_dc_reg_h32(win->phys_addr),
			DC_WINBUF_START_ADDR_HI);
#endif
		if (!yuvp && !yuvsp) {
			tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
		} else if (yuvp) {
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
	defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
			tegra_dc_writel(dc, win->phys_addr_u,
				DC_WINBUF_START_ADDR_U);
			tegra_dc_writel(dc, win->phys_addr_v,
				DC_WINBUF_START_ADDR_V);
#else
			tegra_dc_writel(dc, tegra_dc_reg_l32(win->phys_addr_u),
				DC_WINBUF_START_ADDR_U);
			tegra_dc_writel(dc, tegra_dc_reg_h32(win->phys_addr_u),
				DC_WINBUF_START_ADDR_HI_U);
			tegra_dc_writel(dc, tegra_dc_reg_l32(win->phys_addr_v),
				DC_WINBUF_START_ADDR_V);
			tegra_dc_writel(dc, tegra_dc_reg_h32(win->phys_addr_v),
				DC_WINBUF_START_ADDR_HI_V);
#endif
			tegra_dc_writel(dc,
				LINE_STRIDE(win->stride) |
				UV_LINE_STRIDE(win->stride_uv),
				DC_WIN_LINE_STRIDE);
		} else {
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
	defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
			tegra_dc_writel(dc, win->phys_addr_u,
					DC_WINBUF_START_ADDR_U);
#else
			tegra_dc_writel(dc, tegra_dc_reg_l32(win->phys_addr_u),
				DC_WINBUF_START_ADDR_U);
			tegra_dc_writel(dc, tegra_dc_reg_h32(win->phys_addr_u),
				DC_WINBUF_START_ADDR_HI_U);
#endif
			tegra_dc_writel(dc,
					LINE_STRIDE(win->stride) |
					UV_LINE_STRIDE(win->stride_uv),
					DC_WIN_LINE_STRIDE);
		}

		if (invert_h) {
			h_offset.full = win->x.full + win->w.full;
			h_offset.full = dfixed_floor(h_offset) * Bpp;
			h_offset.full -= dfixed_const(1);
		} else {
			h_offset.full = dfixed_floor(win->x) * Bpp;
		}

		v_offset = win->y;
		if (invert_v)
			v_offset.full += win->h.full - dfixed_const(1);

		tegra_dc_writel(dc, dfixed_trunc(h_offset),
				DC_WINBUF_ADDR_H_OFFSET);
		tegra_dc_writel(dc, dfixed_trunc(v_offset),
				DC_WINBUF_ADDR_V_OFFSET);

#if defined(CONFIG_TEGRA_DC_INTERLACE)
	if ((dc->mode.vmode == FB_VMODE_INTERLACED) && WIN_IS_FB(win)) {
		if (!WIN_IS_INTERLACE(win))
			win->phys_addr2 = win->phys_addr;
	}

	if (tegra_dc_feature_has_interlace(dc, win->idx) &&
		(dc->mode.vmode == FB_VMODE_INTERLACED)) {

#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
			tegra_dc_writel(dc, tegra_dc_reg_l32
				(win->phys_addr2),
				DC_WINBUF_START_ADDR_FIELD2);
			tegra_dc_writel(dc, tegra_dc_reg_h32
				(win->phys_addr2),
				DC_WINBUF_START_ADDR_FIELD2_HI);
#else
			tegra_dc_writel(dc,
				win->phys_addr2,
				DC_WINBUF_START_ADDR_FIELD2);
#endif
		if (yuvp) {
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
	defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
			tegra_dc_writel(dc, win->phys_addr_u2,
				DC_WINBUF_START_ADDR_FIELD2_U);

			tegra_dc_writel(dc, win->phys_addr_v2,
				DC_WINBUF_START_ADDR_FIELD2_V);
#else
			tegra_dc_writel(dc, tegra_dc_reg_l32(win->phys_addr_u2),
				DC_WINBUF_START_ADDR_FIELD2_U);
			tegra_dc_writel(dc, tegra_dc_reg_h32(win->phys_addr_u2),
				DC_WINBUF_START_ADDR_FIELD2_HI_U);

			tegra_dc_writel(dc, tegra_dc_reg_l32(win->phys_addr_v2),
				DC_WINBUF_START_ADDR_FIELD2_V);
			tegra_dc_writel(dc, tegra_dc_reg_h32(win->phys_addr_v2),
				DC_WINBUF_START_ADDR_FIELD2_HI_V);
#endif
		} else if (yuvsp) {
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) || \
	defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
			tegra_dc_writel(dc, win->phys_addr_u2,
				DC_WINBUF_START_ADDR_FIELD2_U);
#else
			tegra_dc_writel(dc, tegra_dc_reg_l32(win->phys_addr_u2),
				DC_WINBUF_START_ADDR_FIELD2_U);
			tegra_dc_writel(dc, tegra_dc_reg_h32(win->phys_addr_u2),
				DC_WINBUF_START_ADDR_FIELD2_HI_U);
#endif
		}
		tegra_dc_writel(dc, dfixed_trunc(h_offset),
			DC_WINBUF_ADDR_H_OFFSET_FIELD2);

		if (WIN_IS_INTERLACE(win)) {
			tegra_dc_writel(dc, dfixed_trunc(v_offset),
					DC_WINBUF_ADDR_V_OFFSET_FIELD2);
		} else {
			v_offset.full += dfixed_const(1);
			tegra_dc_writel(dc, dfixed_trunc(v_offset),
					DC_WINBUF_ADDR_V_OFFSET_FIELD2);
		}
	}
#endif

		if (tegra_dc_feature_has_tiling(dc, win->idx)) {
			if (WIN_IS_TILED(win))
				tegra_dc_writel(dc,
					DC_WIN_BUFFER_ADDR_MODE_TILE |
					DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
					DC_WIN_BUFFER_ADDR_MODE);
			else
				tegra_dc_writel(dc,
					DC_WIN_BUFFER_ADDR_MODE_LINEAR |
					DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
					DC_WIN_BUFFER_ADDR_MODE);
		}

#if defined(CONFIG_TEGRA_DC_BLOCK_LINEAR)
		if (tegra_dc_feature_has_blocklinear(dc, win->idx) ||
			tegra_dc_feature_has_tiling(dc, win->idx)) {
				if (WIN_IS_BLOCKLINEAR(win)) {
					tegra_dc_writel(dc,
						DC_WIN_BUFFER_SURFACE_BL_16B2 |
						(win->block_height_log2
							<< BLOCK_HEIGHT_SHIFT),
						DC_WIN_BUFFER_SURFACE_KIND);
				} else if (WIN_IS_TILED(win)) {
					tegra_dc_writel(dc,
						DC_WIN_BUFFER_SURFACE_TILED,
						DC_WIN_BUFFER_SURFACE_KIND);
				} else {
					tegra_dc_writel(dc,
						DC_WIN_BUFFER_SURFACE_PITCH,
						DC_WIN_BUFFER_SURFACE_KIND);
				}
		}

#endif
		if (yuv)
			win_options |= CSC_ENABLE;
		else if (tegra_dc_fmt_bpp(win->fmt) < 24)
			win_options |= COLOR_EXPAND;

		/*
		 * For gen2 blending, change in the global alpha needs rewrite
		 * to blending regs.
		 */
		if ((dc->blend.alpha[win->idx] != win->global_alpha) &&
		    (tegra_dc_feature_is_gen2_blender(dc, win->idx)))
			update_blend_seq = true;

		/* Cache the global alpha of each window here. It is necessary
		 * for in-order blending settings. */
		dc->blend.alpha[win->idx] = win->global_alpha;
		if (!tegra_dc_feature_is_gen2_blender(dc, win->idx)) {
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
			/* Update global alpha if blender is gen1. */
			if (win->global_alpha == 255) {
				tegra_dc_writel(dc, 0, DC_WIN_GLOBAL_ALPHA);
			} else {
				tegra_dc_writel(dc, GLOBAL_ALPHA_ENABLE |
					win->global_alpha, DC_WIN_GLOBAL_ALPHA);
				win_options |= CP_ENABLE;
			}
#endif

#if !defined(CONFIG_TEGRA_DC_BLENDER_GEN2)
			if (win->flags &
					TEGRA_WIN_FLAG_BLEND_COVERAGE) {
				tegra_dc_writel(dc,
					BLEND(NOKEY, ALPHA, 0xff, 0xff),
					DC_WIN_BLEND_1WIN);
			} else {
				/* global_alpha is 255 if not in use */
				tegra_dc_writel(dc,
					BLEND(NOKEY, FIX, win->global_alpha,
						win->global_alpha),
					DC_WIN_BLEND_1WIN);
			}
#endif
		}

		if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
			win_options |= CP_ENABLE;

		win_options |= H_DIRECTION_DECREMENT(invert_h);
		win_options |= V_DIRECTION_DECREMENT(invert_v);
#if defined(CONFIG_TEGRA_DC_INTERLACE)
		if (tegra_dc_feature_has_interlace(dc, win->idx)) {
			if (dc->mode.vmode == FB_VMODE_INTERLACED)
				win_options |= INTERLACE_ENABLE;
		}
#endif
		if (dc_win->csc_dirty) {
			tegra_dc_set_csc(dc, &dc_win->csc);
			dc_win->csc_dirty = false;
		}

		if (dc->yuv_bypass)
			win_options &= ~CP_ENABLE;

		tegra_dc_writel(dc, win_options, DC_WIN_WIN_OPTIONS);

		dc_win->dirty = 1;

		trace_window_update(dc, win);
	}

	if (update_blend_par || update_blend_seq) {
		if (update_blend_par)
			tegra_dc_blend_parallel(dc, &dc->blend);
		if (update_blend_seq)
			tegra_dc_blend_sequential(dc, &dc->blend);

		for_each_set_bit(i, &dc->valid_windows, DC_N_WINDOWS) {
			struct tegra_dc_win *win = tegra_dc_get_window(dc, i);
			win->dirty = 1;
			update_mask |= WIN_A_ACT_REQ << i;
		}
	}

	tegra_dc_set_dynamic_emc(dc);

#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_12x_SOC) \
	|| defined(CONFIG_ARCH_TEGRA_14x_SOC) \
	|| defined(CONFIG_ARCH_TEGRA_21x_SOC)
	/* prevent FIFO from taking in stale data after a reset */
	tegra_dc_writel(dc, MEMFETCH_RESET, DC_WINBUF_MEMFETCH_CONTROL);
#endif

	/* WIN_x_UPDATE is the same as WIN_x_ACT_REQ << 8 */
	tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);

	if (tegra_cpu_is_asim())
		tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT,
						DC_CMD_INT_STATUS);

	tegra_dc_writel(dc, act_control, DC_CMD_REG_ACT_CONTROL);

	if (wait_for_vblank) {
		/* Use the interrupt handler.  ISR will clear the dirty flags
		   when the flip is completed */
		set_bit(V_BLANK_FLIP, &dc->vblank_ref_count);
		tegra_dc_unmask_interrupt(dc,
			FRAME_END_INT | V_BLANK_INT | ALL_UF_INT());
#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC)
		set_bit(V_PULSE2_FLIP, &dc->vpulse2_ref_count);
		tegra_dc_unmask_interrupt(dc, V_PULSE2_INT);
#endif
	}

	if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
		schedule_delayed_work(&dc->one_shot_work,
				msecs_to_jiffies(dc->one_shot_delay_ms));
	}
	dc->crc_pending = true;

	/* update EMC clock if calculated bandwidth has changed */
	tegra_dc_program_bandwidth(dc, false);

	if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
		update_mask |= NC_HOST_TRIG;

	val = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL);
	if (!!(val & CMU_ENABLE) != (!dc->yuv_bypass && dc->cmu_enabled)) {
		val ^= CMU_ENABLE;
		tegra_dc_writel(dc, val, DC_DISP_DISP_COLOR_CONTROL);
		update_mask |= GENERAL_ACT_REQ;
	}

	tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);

	if (!wait_for_vblank) {
		/* Don't use a interrupt handler for the update, but leave
		   vblank interrupts unmasked since they could be used by other
		   windows.  One window could flip on HBLANK while others flip
		   on VBLANK.  Poll HW until this window update is completed
		   which could block for as long as it takes to display one
		   scanline. */

		unsigned int winmask = update_mask & WIN_ALL_ACT_REQ;
		while (tegra_dc_windows_are_dirty(dc, winmask))
			udelay(1);

		for_each_set_bit(i, &dc->valid_windows, n)
			tegra_dc_get_window(dc, windows[i]->idx)->dirty = 0;
	}
	return 0;
}

For TX 2 code, I fixed that win-> dirty = 1 will not be executed when blend processing is bypassed.
Is this an appropriate modification that does not affect the other?

Also, I want to know what it means for the differences between these implementations of TX1 and TX2.

thanks.

k.doi,

Does this flag of dirty affect your usecase?

It prevents this dirty flag from leaving ___ wait_event in window.c.
This is a bottleneck, and I can not pan the frame buffer smoothly.

The dirty flag is monitored in the tegra_dc_ windows_are_clean function. (Line 25)

/* does not support syncing windows on multiple dcs in one call */
int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
{
    int ret = 0;
    struct tegra_dc *dc = windows[0]->dc;

    if (dc == NULL)
        return -EFAULT;

    if (n < 1 || n > tegra_dc_get_numof_dispwindows())
        return -EINVAL;

    if (!dc->enabled)
        return -EFAULT;

    trace_sync_windows(dc);
    mutex_lock(&dc->lock);

    /*
     * Putting the task state as TASK_UINTERRUPTIBLE makes
     * task wait till windows status promoted or timeout occurred
     * and wont be interrupted by signal or any other reason.
     */
    ret = ___wait_event(dc->wq,
        ___wait_cond_timeout(tegra_dc_windows_are_clean(windows, n)),
        TASK_UNINTERRUPTIBLE, 0, HZ,
        mutex_unlock(&dc->lock);
        __ret = schedule_timeout(__ret);
        mutex_lock(&dc->lock));

    mutex_unlock(&dc->lock);

    if (dc->out_ops && dc->out_ops->release)
        dc->out_ops->release(dc);

    return ret;
}
EXPORT_SYMBOL(tegra_dc_sync_windows);

I will also post the code for tegra_dc_ windows_are_clean.

static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
                         int n)
{
    int i;

    for (i = 0; i < n; i++) {
        if (windows[i]->dirty) {
            return false;
        }
    }

    return true;
}

k.doi,

I need to check with internal team with this. Not sure if we support fast fb panning.

I want to know as soon as possible whether it supports fast frame buffer panning.

Thank you very much for your kind support.

k.doi,

It turns out there seems a bug in tx2 display driver(and only happens when panning buffer) and we are looking into it.

Are bug fix patches for this issue will be released?