static void tegra_overlay_flip_worker(struct work_struct *work) { struct tegra_overlay_flip_data *data = container_of(work, struct tegra_overlay_flip_data, work); struct tegra_overlay_info *overlay = data->overlay; struct tegra_dc_win *win; struct tegra_dc_win *wins[TEGRA_FB_FLIP_N_WINDOWS]; struct nvmap_handle_ref *unpin_handles[TEGRA_FB_FLIP_N_WINDOWS]; int i, nr_win = 0, nr_unpin = 0; data = container_of(work, struct tegra_overlay_flip_data, work); for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) { struct tegra_overlay_flip_win *flip_win = &data->win[i]; int idx = flip_win->attr.index; if (idx == -1) continue; win = tegra_dc_get_window(overlay->dc, idx); if (!win) continue; if (win->flags && win->cur_handle) unpin_handles[nr_unpin++] = win->cur_handle; tegra_overlay_set_windowattr(overlay, win, &data->win[i]); wins[nr_win++] = win; #if 0 if (flip_win->attr.pre_syncpt_id < 0) continue; printk("%08x %08x\n", flip_win->attr.pre_syncpt_id, flip_win->attr.pre_syncpt_val); nvhost_syncpt_wait_timeout(&overlay->ndev->host->syncpt, flip_win->attr.pre_syncpt_id, flip_win->attr.pre_syncpt_val, msecs_to_jiffies(500)); #endif } tegra_dc_update_windows(wins, nr_win); /* TODO: implement swapinterval here */ tegra_dc_sync_windows(wins, nr_win); tegra_dc_incr_syncpt_min(overlay->dc, data->syncpt_max); /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { nvmap_unpin(overlay->overlay_nvmap, unpin_handles[i]); nvmap_free(overlay->overlay_nvmap, unpin_handles[i]); } kfree(data); }
/* make the screen blank by disabling all windows */ void tegra_dc_blank(struct tegra_dc *dc) { struct tegra_dc_win *dcwins[DC_N_WINDOWS]; unsigned i; for (i = 0; i < DC_N_WINDOWS; i++) { dcwins[i] = tegra_dc_get_window(dc, i); dcwins[i]->flags &= ~TEGRA_WIN_FLAG_ENABLED; } tegra_dc_update_windows(dcwins, DC_N_WINDOWS); tegra_dc_sync_windows(dcwins, DC_N_WINDOWS); }
static void tegra_overlay_set_emc_freq(struct tegra_overlay_info *dev) { unsigned long new_rate; int i; struct tegra_dc_win *win; struct tegra_dc_win *wins[DC_N_WINDOWS]; for (i = 0; i < DC_N_WINDOWS; i++) { win = tegra_dc_get_window(dev->dc, i); wins[i] = win; } new_rate = tegra_dc_get_bandwidth(wins, dev->dc->n_windows); new_rate = EMC_BW_TO_FREQ(new_rate); if (tegra_dc_has_multiple_dc()) new_rate = ULONG_MAX; clk_set_rate(dev->dc->emc_clk, new_rate); }
int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx) { struct tegra_dc_win *win = tegra_dc_get_window(dc, win_idx); if (!win) return -EFAULT; mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return -EFAULT; } tegra_dc_get(dc); tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx, DC_CMD_DISPLAY_WINDOW_HEADER); tegra_dc_set_csc(dc, &win->csc); tegra_dc_put(dc); mutex_unlock(&dc->lock); return 0; }
static void tegra_dc_ext_flip_worker(struct work_struct *work) { struct tegra_dc_ext_flip_data *data = container_of(work, struct tegra_dc_ext_flip_data, work); struct tegra_dc_ext *ext = data->ext; struct tegra_dc_win *wins[DC_N_WINDOWS]; struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS * TEGRA_DC_NUM_PLANES]; int i, nr_unpin = 0, nr_win = 0; for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; int index = flip_win->attr.index; struct tegra_dc_win *win; struct tegra_dc_ext_win *ext_win; if (index < 0) continue; win = tegra_dc_get_window(ext->dc, index); ext_win = &ext->win[index]; if (win->flags & TEGRA_WIN_FLAG_ENABLED) { int j; for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) { if (!ext_win->cur_handle[j]) continue; unpin_handles[nr_unpin++] = ext_win->cur_handle[j]; } } tegra_dc_ext_set_windowattr(ext, win, &data->win[i]); wins[nr_win++] = win; } tegra_dc_update_windows(wins, nr_win); /* TODO: implement swapinterval here */ tegra_dc_sync_windows(wins, nr_win); for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; int index = flip_win->attr.index; if (index < 0) continue; tegra_dc_incr_syncpt_min(ext->dc, index, flip_win->syncpt_max); } /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { nvmap_unpin(ext->nvmap, unpin_handles[i]); nvmap_free(ext->nvmap, unpin_handles[i]); } kfree(data); }
static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user, struct tegra_dc_ext_flip *args) { struct tegra_dc_ext *ext = user->ext; struct tegra_dc_ext_flip_data *data; int work_index = -1; int i, ret = 0; #ifdef CONFIG_ANDROID int index_check[DC_N_WINDOWS] = {0, }; int zero_index_id = 0; #endif if (!user->nvmap) return -EFAULT; ret = sanitize_flip_args(user, args); if (ret) return ret; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; INIT_WORK(&data->work, tegra_dc_ext_flip_worker); data->ext = ext; #ifdef CONFIG_ANDROID for (i = 0; i < DC_N_WINDOWS; i++) { index_check[i] = args->win[i].index; if (index_check[i] == 0) zero_index_id = i; } if (index_check[DC_N_WINDOWS - 1] != 0) { struct tegra_dc_ext_flip_windowattr win_temp; win_temp = args->win[DC_N_WINDOWS - 1]; args->win[DC_N_WINDOWS - 1] = args->win[zero_index_id]; args->win[zero_index_id] = win_temp; } #endif for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; int index = args->win[i].index; memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr)); if (index < 0) continue; ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id, &flip_win->handle[TEGRA_DC_Y], &flip_win->phys_addr); if (ret) goto fail_pin; if (flip_win->attr.buff_id_u) { ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id_u, &flip_win->handle[TEGRA_DC_U], &flip_win->phys_addr_u); if (ret) goto fail_pin; } else { flip_win->handle[TEGRA_DC_U] = NULL; flip_win->phys_addr_u = 0; } if (flip_win->attr.buff_id_v) { ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id_v, &flip_win->handle[TEGRA_DC_V], &flip_win->phys_addr_v); if (ret) goto fail_pin; } else { flip_win->handle[TEGRA_DC_V] = NULL; flip_win->phys_addr_v = 0; } } ret = lock_windows_for_flip(user, args); if (ret) goto fail_pin; if (!ext->enabled) { ret = -ENXIO; goto unlock; } for (i = 0; i < DC_N_WINDOWS; i++) { u32 syncpt_max; int index = args->win[i].index; struct tegra_dc_win *win; struct tegra_dc_ext_win *ext_win; if (index < 0) continue; win = tegra_dc_get_window(ext->dc, index); ext_win = &ext->win[index]; syncpt_max = tegra_dc_incr_syncpt_max(ext->dc, index); data->win[i].syncpt_max = syncpt_max; /* * Any of these windows' syncpoints should be equivalent for * the client, so we just send back an arbitrary one of them */ args->post_syncpt_val = syncpt_max; args->post_syncpt_id = tegra_dc_get_syncpt_id(ext->dc, index); work_index = index; atomic_inc(&ext->win[work_index].nr_pending_flips); } if (work_index < 0) { ret = -EINVAL; goto unlock; } queue_work(ext->win[work_index].flip_wq, &data->work); unlock_windows_for_flip(user, args); return 0; unlock: unlock_windows_for_flip(user, args); fail_pin: for (i = 0; i < DC_N_WINDOWS; i++) { int j; for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) { if (!data->win[i].handle[j]) continue; nvmap_unpin(ext->nvmap, data->win[i].handle[j]); nvmap_free(ext->nvmap, data->win[i].handle[j]); } } kfree(data); return ret; }
static void tegra_dc_ext_flip_worker(struct work_struct *work) { struct tegra_dc_ext_flip_data *data = container_of(work, struct tegra_dc_ext_flip_data, work); struct tegra_dc_ext *ext = data->ext; struct tegra_dc_win *wins[DC_N_WINDOWS]; struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS * TEGRA_DC_NUM_PLANES]; struct nvmap_handle_ref *old_handle; int i, nr_unpin = 0, nr_win = 0; bool skip_flip = false; for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; int index = flip_win->attr.index; struct tegra_dc_win *win; struct tegra_dc_ext_win *ext_win; if (index < 0) continue; win = tegra_dc_get_window(ext->dc, index); ext_win = &ext->win[index]; if (!(atomic_dec_and_test(&ext_win->nr_pending_flips)) && (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR)) skip_flip = true; if (skip_flip) old_handle = flip_win->handle[TEGRA_DC_Y]; else old_handle = ext_win->cur_handle[TEGRA_DC_Y]; if (old_handle) { int j; for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) { if (skip_flip) old_handle = flip_win->handle[j]; else old_handle = ext_win->cur_handle[j]; if (!old_handle) continue; unpin_handles[nr_unpin++] = old_handle; } } if (!skip_flip) tegra_dc_ext_set_windowattr(ext, win, &data->win[i]); wins[nr_win++] = win; } if (!skip_flip) { tegra_dc_update_windows(wins, nr_win); /* TODO: implement swapinterval here */ tegra_dc_sync_windows(wins, nr_win); } for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; int index = flip_win->attr.index; if (index < 0) continue; tegra_dc_incr_syncpt_min(ext->dc, index, flip_win->syncpt_max); } /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { nvmap_unpin(ext->nvmap, unpin_handles[i]); nvmap_free(ext->nvmap, unpin_handles[i]); } kfree(data); }
static void tegra_overlay_flip_worker(struct work_struct *work) { struct tegra_overlay_flip_data *data = container_of(work, struct tegra_overlay_flip_data, work); struct tegra_overlay_info *overlay = data->overlay; struct tegra_dc_win *win; struct tegra_dc_win *wins[TEGRA_FB_FLIP_N_WINDOWS]; struct nvmap_handle_ref *unpin_handles[TEGRA_FB_FLIP_N_WINDOWS]; int i, nr_win = 0, nr_unpin = 0; data = container_of(work, struct tegra_overlay_flip_data, work); for (i = 0; i < TEGRA_FB_FLIP_N_WINDOWS; i++) { struct tegra_overlay_flip_win *flip_win = &data->win[i]; int idx = flip_win->attr.index; if (idx == -1) continue; win = tegra_dc_get_window(overlay->dc, idx); if (!win) continue; if (win->flags && win->cur_handle && !data->didim_work) unpin_handles[nr_unpin++] = win->cur_handle; tegra_overlay_set_windowattr(overlay, win, &data->win[i]); wins[nr_win++] = win; #if 0 if (flip_win->attr.pre_syncpt_id < 0) continue; printk("%08x %08x\n", flip_win->attr.pre_syncpt_id, flip_win->attr.pre_syncpt_val); nvhost_syncpt_wait_timeout(&nvhost_get_host(overlay->ndev)->syncpt, flip_win->attr.pre_syncpt_id, flip_win->attr.pre_syncpt_val, msecs_to_jiffies(500)); #endif } if (data->flags & TEGRA_OVERLAY_FLIP_FLAG_BLEND_REORDER) { struct tegra_dc_win *dcwins[DC_N_WINDOWS]; for (i = 0; i < DC_N_WINDOWS; i++) dcwins[i] = tegra_dc_get_window(overlay->dc, i); tegra_overlay_blend_reorder(&overlay->blend, dcwins); tegra_dc_update_windows(dcwins, DC_N_WINDOWS); tegra_dc_sync_windows(dcwins, DC_N_WINDOWS); } else { tegra_dc_update_windows(wins, nr_win); /* TODO: implement swapinterval here */ tegra_dc_sync_windows(wins, nr_win); } if ((overlay->dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) && (overlay->dc->out->flags & TEGRA_DC_OUT_N_SHOT_MODE)) { tegra_overlay_n_shot(data, unpin_handles, &nr_unpin); } else { tegra_dc_incr_syncpt_min(overlay->dc, 0, data->syncpt_max); /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { nvmap_unpin(overlay->overlay_nvmap, unpin_handles[i]); nvmap_free(overlay->overlay_nvmap, unpin_handles[i]); } kfree(data); } }
/* Does not support updating windows on multiple dcs in one call. * Requires a matching sync_windows to avoid leaking ref-count on clocks. */ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) { struct tegra_dc *dc; unsigned long update_mask = GENERAL_ACT_REQ; unsigned long win_options; bool update_blend_par = false; bool update_blend_seq = false; int i; dc = windows[0]->dc; trace_update_windows(dc); if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { /* Acquire one_shot_lock to avoid race condition between * cancellation of old delayed work and schedule of new * delayed work. */ mutex_lock(&dc->one_shot_lock); cancel_delayed_work_sync(&dc->one_shot_work); } mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) mutex_unlock(&dc->one_shot_lock); return -EFAULT; } tegra_dc_io_start(dc); tegra_dc_hold_dc_out(dc); if (no_vsync) tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE, DC_CMD_STATE_ACCESS); else tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, DC_CMD_STATE_ACCESS); 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); unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8; /* Bytes per pixel of bandwidth, used for dda_inc calculation */ unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1); const bool filter_h = win_use_h_filter(dc, win); const bool filter_v = win_use_v_filter(dc, win); #if defined(CONFIG_TEGRA_DC_SCAN_COLUMN) scan_column = (win->flags & TEGRA_WIN_FLAG_SCAN_COLUMN); #endif /* 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); if (!no_vsync) update_mask |= WIN_A_ACT_REQ << win->idx; if (!WIN_IS_ENABLED(win)) { dc_win->dirty = no_vsync ? 0 : 1; tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS); continue; } tegra_dc_writel(dc, win->fmt & 0x1f, DC_WIN_COLOR_DEPTH); tegra_dc_writel(dc, win->fmt >> 6, DC_WIN_BYTE_SWAP); tegra_dc_writel(dc, V_POSITION(win->out_y) | H_POSITION(win->out_x), DC_WIN_POSITION); tegra_dc_writel(dc, V_SIZE(win->out_h) | H_SIZE(win->out_w), DC_WIN_SIZE); /* Check scan_column flag to set window size and scaling. */ win_options = WIN_ENABLE; if (scan_column) { win_options |= WIN_SCAN_COLUMN; win_options |= H_FILTER_ENABLE(filter_v); win_options |= V_FILTER_ENABLE(filter_h); } else { 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 tegra_dc_writel(dc, (unsigned long)win->phys_addr, DC_WINBUF_START_ADDR); if (!yuvp) { tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE); } else { tegra_dc_writel(dc, (unsigned long)win->phys_addr_u, DC_WINBUF_START_ADDR_U); tegra_dc_writel(dc, (unsigned long)win->phys_addr_v, DC_WINBUF_START_ADDR_V); 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 (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 (yuv) win_options |= CSC_ENABLE; else if (tegra_dc_fmt_bpp(win->fmt) < 24) win_options |= COLOR_EXPAND; #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_11x_SOC) 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 (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); tegra_dc_writel(dc, win_options, DC_WIN_WIN_OPTIONS); dc_win->dirty = no_vsync ? 0 : 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 (i = 0; i < DC_N_WINDOWS; i++) { if (!no_vsync) dc->windows[i].dirty = 1; update_mask |= WIN_A_ACT_REQ << i; } } tegra_dc_set_dynamic_emc(windows, n); tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT, DC_CMD_INT_STATUS); if (!no_vsync) { 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 } else { clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); tegra_dc_mask_interrupt(dc, V_BLANK_INT | ALL_UF_INT); #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) && !defined(CONFIG_ARCH_TEGRA_3x_SOC) clear_bit(V_PULSE2_FLIP, &dc->vpulse2_ref_count); tegra_dc_mask_interrupt(dc, V_PULSE2_INT); #endif if (!atomic_read(&frame_end_ref)) tegra_dc_mask_interrupt(dc, FRAME_END_INT); } 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)); /* 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; tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL); tegra_dc_release_dc_out(dc); /* tegra_dc_io_end() is called in tegra_dc_sync_windows() */ mutex_unlock(&dc->lock); if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) mutex_unlock(&dc->one_shot_lock); return 0; }
static void tegra_dc_ext_flip_worker(struct work_struct *work) { struct tegra_dc_ext_flip_data *data = container_of(work, struct tegra_dc_ext_flip_data, work); struct tegra_dc_ext *ext = data->ext; struct tegra_dc_win *wins[DC_N_WINDOWS]; struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS]; int i, nr_unpin = 0, nr_win = 0, nr_disable = 0; for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; int index = flip_win->attr.index; struct tegra_dc_win *win; struct tegra_dc_ext_win *ext_win; bool old_ena, new_ena; if (index < 0) continue; win = tegra_dc_get_window(ext->dc, index); ext_win = &ext->win[index]; old_ena = ext->win[index].enabled; new_ena = flip_win->handle != NULL; if (old_ena != new_ena) { if (new_ena) process_window_change(ext, 1); else nr_disable++; } ext->win[index].enabled = new_ena; if (old_ena && ext_win->cur_handle) unpin_handles[nr_unpin++] = ext_win->cur_handle; tegra_dc_ext_set_windowattr(ext, win, &data->win[i]); wins[nr_win++] = win; } tegra_dc_update_windows(wins, nr_win); /* TODO: implement swapinterval here */ tegra_dc_sync_windows(wins, nr_win); for (i = 0; i < DC_N_WINDOWS; i++) { struct tegra_dc_ext_flip_win *flip_win = &data->win[i]; int index = flip_win->attr.index; if (index < 0) continue; tegra_dc_incr_syncpt_min(ext->dc, index, flip_win->syncpt_max); } /* unpin and deref previous front buffers */ for (i = 0; i < nr_unpin; i++) { nvmap_unpin(ext->nvmap, unpin_handles[i]); nvmap_free(ext->nvmap, unpin_handles[i]); } if (nr_disable) process_window_change(ext, -nr_disable); kfree(data); }