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.