int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user, struct tegra_dc_ext_cursor *args) { struct tegra_dc_ext *ext = user->ext; struct tegra_dc *dc = ext->dc; u32 val; bool enable; int ret; mutex_lock(&ext->cursor.lock); if (ext->cursor.user != user) { ret = -EACCES; goto unlock; } if (!ext->enabled) { ret = -ENXIO; goto unlock; } enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE); mutex_lock(&dc->lock); tegra_dc_io_start(dc); tegra_dc_hold_dc_out(dc); val = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); if (!!(val & CURSOR_ENABLE) != enable) { val &= ~CURSOR_ENABLE; if (enable) val |= CURSOR_ENABLE; tegra_dc_writel(dc, val, DC_DISP_DISP_WIN_OPTIONS); } tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y), DC_DISP_CURSOR_POSITION); tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); /* TODO: need to sync here? hopefully can avoid this, but need to * figure out interaction w/ rest of GENERAL_ACT_REQ */ tegra_dc_release_dc_out(dc); tegra_dc_io_end(dc); mutex_unlock(&dc->lock); mutex_unlock(&ext->cursor.lock); return 0; unlock: mutex_unlock(&ext->cursor.lock); return ret; }
void tegra_dc_disable_crc(struct tegra_dc *dc) { mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); tegra_dc_writel(dc, 0x0, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_io_end(dc); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }
static void tegra_dc_vblank(struct work_struct *work) { struct tegra_dc *dc = container_of(work, struct tegra_dc, vblank_work); bool nvsd_updated = false; mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return; } tegra_dc_hold_dc_out(dc); /* use the new frame's bandwidth setting instead of max(current, new), * skip this if we're using tegra_dc_one_shot_worker() */ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)) tegra_dc_program_bandwidth(dc, true); /* Clear the V_BLANK_FLIP bit of vblank ref-count if update is clean. */ if (!tegra_dc_windows_are_dirty(dc)) clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); /* Update the SD brightness */ if (dc->enabled && dc->out->sd_settings) { nvsd_updated = nvsd_update_brightness(dc); /* Ref-count vblank if nvsd is on-going. Otherwise, clean the * V_BLANK_NVSD bit of vblank ref-count. */ if (nvsd_updated) { set_bit(V_BLANK_NVSD, &dc->vblank_ref_count); tegra_dc_unmask_interrupt(dc, V_BLANK_INT); } else { clear_bit(V_BLANK_NVSD, &dc->vblank_ref_count); } } /* Mask vblank interrupt if ref-count is zero. */ if (!dc->vblank_ref_count) tegra_dc_mask_interrupt(dc, V_BLANK_INT); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); /* Do the actual brightness update outside of the mutex */ if (nvsd_updated && dc->out->sd_settings && dc->out->sd_settings->bl_device) { struct platform_device *pdev = dc->out->sd_settings->bl_device; struct backlight_device *bl = platform_get_drvdata(pdev); if (bl) backlight_update_status(bl); } }
void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val) { mutex_lock(&dc->lock); if (dc->enabled) { tegra_dc_hold_dc_out(dc); while (dc->syncpt[i].min < val) { dc->syncpt[i].min++; nvhost_syncpt_cpu_incr_ext(dc->ndev, dc->syncpt[i].id); } tegra_dc_release_dc_out(dc); } mutex_unlock(&dc->lock); }
void tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg) { unsigned int ctrl; unsigned long out_sel; unsigned long cmd_state; mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return; } tegra_dc_hold_dc_out(dc); ctrl = ((cfg->period << PM_PERIOD_SHIFT) | (cfg->clk_div << PM_CLK_DIVIDER_SHIFT) | cfg->clk_select); /* The new value should be effected immediately */ cmd_state = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); tegra_dc_writel(dc, (cmd_state | (1 << 2)), DC_CMD_STATE_ACCESS); switch (cfg->which_pwm) { case TEGRA_PWM_PM0: /* Select the LM0 on PM0 */ out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5); out_sel &= ~(7 << 0); out_sel |= (3 << 0); tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5); tegra_dc_writel(dc, ctrl, DC_COM_PM0_CONTROL); tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM0_DUTY_CYCLE); break; case TEGRA_PWM_PM1: /* Select the LM1 on PM1 */ out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5); out_sel &= ~(7 << 4); out_sel |= (3 << 4); tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5); tegra_dc_writel(dc, ctrl, DC_COM_PM1_CONTROL); tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM1_DUTY_CYCLE); break; default: dev_err(&dc->ndev->dev, "Error: Need which_pwm\n"); break; } tegra_dc_writel(dc, cmd_state, DC_CMD_STATE_ACCESS); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }
u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i) { u32 max; mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); max = nvhost_syncpt_incr_max_ext(dc->ndev, dc->syncpt[i].id, ((dc->enabled) ? 1 : 0)); dc->syncpt[i].max = max; tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); return max; }
static void tegra_dc_underflow_worker(struct work_struct *work) { struct tegra_dc *dc = container_of( to_delayed_work(work), struct tegra_dc, underflow_work); mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); if (dc->enabled) { tegra_dc_underflow_handler(dc); } tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }
void tegra_dc_enable_crc(struct tegra_dc *dc) { u32 val; mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); tegra_dc_io_start(dc); val = CRC_ALWAYS_ENABLE | CRC_INPUT_DATA_ACTIVE_DATA | CRC_ENABLE_ENABLE; tegra_dc_writel(dc, val, DC_COM_CRC_CONTROL); tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }
/* get the stride size of a window. * return: stride size in bytes for window win. or 0 if unavailble. */ int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win) { u32 stride; if (!dc->enabled) return 0; BUG_ON(win > DC_N_WINDOWS); mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); tegra_dc_writel(dc, WINDOW_A_SELECT << win, DC_CMD_DISPLAY_WINDOW_HEADER); stride = tegra_dc_readl(dc, DC_WIN_LINE_STRIDE); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); return GET_LINE_STRIDE(stride); }
static void _tegra_dc_disable(struct tegra_dc *dc) { if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { mutex_lock(&dc->one_shot_lock); cancel_delayed_work_sync(&dc->one_shot_work); } tegra_dc_hold_dc_out(dc); _tegra_dc_controller_disable(dc); tegra_dc_io_end(dc); tegra_dc_release_dc_out(dc); if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) mutex_unlock(&dc->one_shot_lock); }
int tegra_dc_ext_cursor_clip(struct tegra_dc_ext_user *user, int *args) { struct tegra_dc_ext *ext = user->ext; struct tegra_dc *dc = ext->dc; int ret; unsigned long reg_val; mutex_lock(&ext->cursor.lock); if (ext->cursor.user != user) { ret = -EACCES; goto unlock; } if (!ext->enabled) { ret = -ENXIO; goto unlock; } mutex_lock(&dc->lock); tegra_dc_io_start(dc); tegra_dc_hold_dc_out(dc); reg_val = tegra_dc_readl(dc, DC_DISP_CURSOR_START_ADDR); reg_val &= ~CURSOR_CLIP_SHIFT_BITS(3); /* Clear out the old value */ tegra_dc_writel(dc, reg_val | CURSOR_CLIP_SHIFT_BITS(*args), DC_DISP_CURSOR_START_ADDR); tegra_dc_release_dc_out(dc); tegra_dc_io_end(dc); mutex_unlock(&dc->lock); mutex_unlock(&ext->cursor.lock); return 0; unlock: mutex_unlock(&ext->cursor.lock); return ret; }
int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx) { mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return -EFAULT; } tegra_dc_hold_dc_out(dc); tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx, DC_CMD_DISPLAY_WINDOW_HEADER); tegra_dc_set_csc(dc, &dc->windows[win_idx].csc); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); return 0; }
u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc) { int crc = 0; if (!dc) { dev_err(&dc->ndev->dev, "Failed to get dc.\n"); goto crc_error; } /* TODO: Replace mdelay with code to sync VBlANK, since * DC_COM_CRC_CHECKSUM_LATCHED is available after VBLANK */ mdelay(TEGRA_CRC_LATCHED_DELAY); mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); crc = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM_LATCHED); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); crc_error: return crc; }
int tegra_dc_wait_for_vsync(struct tegra_dc *dc) { int ret = -ENOTTY; if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) || !dc->enabled) return ret; /* * Logic is as follows * a) Indicate we need a vblank. * b) Wait for completion to be signalled from isr. * c) Initialize completion for next iteration. */ tegra_dc_hold_dc_out(dc); dc->out->user_needs_vblank = true; ret = wait_for_completion_interruptible(&dc->out->user_vblank_comp); init_completion(&dc->out->user_vblank_comp); tegra_dc_release_dc_out(dc); return ret; }
/* does not support updating windows on multiple dcs in one call */ 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 val; bool update_blend = false; int i; dc = windows[0]->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_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]; unsigned h_dda; unsigned v_dda; 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 (win->z != dc->blend.z[win->idx]) { dc->blend.z[win->idx] = win->z; update_blend = true; } if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) != dc->blend.flags[win->idx]) { dc->blend.flags[win->idx] = win->flags & TEGRA_WIN_BLEND_FLAGS_MASK; update_blend = 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->windows[i].dirty = 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); if (tegra_dc_feature_has_scaling(dc, win->idx)) { tegra_dc_writel(dc, V_PRESCALED_SIZE(dfixed_trunc(win->h)) | H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp), DC_WIN_PRESCALED_SIZE); h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw); v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw); tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda), DC_WIN_DDA_INCREMENT); h_dda = compute_initial_dda(win->x); v_dda = compute_initial_dda(win->y); tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); } tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); 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); } h_offset = win->x; if (invert_h) { h_offset.full += win->w.full - dfixed_const(1); } v_offset = win->y; if (invert_v) { v_offset.full += win->h.full - dfixed_const(1); } tegra_dc_writel(dc, dfixed_trunc(h_offset) * Bpp, 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); } val = WIN_ENABLE; if (yuv) val |= CSC_ENABLE; else if (tegra_dc_fmt_bpp(win->fmt) < 24) val |= COLOR_EXPAND; if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE) val |= CP_ENABLE; if (filter_h) val |= H_FILTER_ENABLE; if (filter_v) val |= V_FILTER_ENABLE; if (invert_h) val |= H_DIRECTION_DECREMENT; if (invert_v) val |= V_DIRECTION_DECREMENT; tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS); #ifdef CONFIG_ARCH_TEGRA_3x_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); #endif win->dirty = no_vsync ? 0 : 1; dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d " "out_x=%u out_y=%u out_w=%u out_h=%u " "fmt=%d yuvp=%d Bpp=%u filter_h=%d filter_v=%d", __func__, win->idx, win->z, dfixed_trunc(win->x), dfixed_trunc(win->y), dfixed_trunc(win->w), dfixed_trunc(win->h), win->out_x, win->out_y, win->out_w, win->out_h, win->fmt, yuvp, Bpp, filter_h, filter_v); trace_printk("%s:win%u in:%ux%u out:%ux%u fmt=%d\n", dc->ndev->name, win->idx, dfixed_trunc(win->w), dfixed_trunc(win->h), win->out_w, win->out_h, win->fmt); } if (update_blend) { tegra_dc_set_blending(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); } else { clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); tegra_dc_mask_interrupt(dc, V_BLANK_INT | ALL_UF_INT); 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); trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) mutex_unlock(&dc->one_shot_lock); return 0; }
static ssize_t nvsd_settings_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct device *dev = container_of((kobj->parent), struct device, kobj); struct nvhost_device *ndev = to_nvhost_device(dev); struct tegra_dc *dc = nvhost_get_drvdata(ndev); struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings; ssize_t res = count; bool settings_updated = false; long int result; int err; if (sd_settings) { if (IS_NVSD_ATTR(enable)) { if (sd_settings->phase_in_settings) { err = strict_strtol(buf, 10, &result); if (err) return err; if (nvsd_update_enable(sd_settings, result)) nvsd_check_and_update(1, 1, enable); } else { nvsd_check_and_update(0, 1, enable); } } else if (IS_NVSD_ATTR(aggressiveness)) { err = strict_strtol(buf, 10, &result); if (err) return err; if (nvsd_update_agg(sd_settings, result) && !sd_settings->phase_in_settings) settings_updated = true; } else if (IS_NVSD_ATTR(phase_in_settings)) { nvsd_check_and_update(0, 1, phase_in_settings); } else if (IS_NVSD_ATTR(phase_in_adjustments)) { nvsd_check_and_update(0, 1, phase_in_adjustments); } else if (IS_NVSD_ATTR(bin_width)) { nvsd_check_and_update(0, 8, bin_width); } else if (IS_NVSD_ATTR(hw_update_delay)) { nvsd_check_and_update(0, 2, hw_update_delay); } else if (IS_NVSD_ATTR(use_vid_luma)) { nvsd_check_and_update(0, 1, use_vid_luma); } else if (IS_NVSD_ATTR(coeff)) { int ele[3], i = 0, num = 3; nvsd_get_multi(ele, num, i, 0, 15); if (i == num) { sd_settings->coeff.r = ele[0]; sd_settings->coeff.g = ele[1]; sd_settings->coeff.b = ele[2]; settings_updated = true; } else { res = -EINVAL; } } else if (IS_NVSD_ATTR(blp_time_constant)) { nvsd_check_and_update(0, 1024, blp.time_constant); } else if (IS_NVSD_ATTR(blp_step)) { nvsd_check_and_update(0, 255, blp.step); } else if (IS_NVSD_ATTR(fc_time_limit)) { nvsd_check_and_update(0, 255, fc.time_limit); } else if (IS_NVSD_ATTR(fc_threshold)) { nvsd_check_and_update(0, 255, fc.threshold); #ifdef CONFIG_TEGRA_SD_GEN2 } else if (IS_NVSD_ATTR(k_limit_enable)) { nvsd_check_and_update(0, 1, k_limit_enable); } else if (IS_NVSD_ATTR(k_limit)) { nvsd_check_and_update(128, 255, k_limit); } else if (IS_NVSD_ATTR(sd_window_enable)) { nvsd_check_and_update(0, 1, sd_window_enable); } else if (IS_NVSD_ATTR(sd_window)) { int ele[4], i = 0, num = 4; nvsd_get_multi(ele, num, i, 0, LONG_MAX); if (i == num) { sd_settings->sd_window.h_position = ele[0]; sd_settings->sd_window.v_position = ele[1]; sd_settings->sd_window.h_size = ele[2]; sd_settings->sd_window.v_size = ele[3]; settings_updated = true; } else { res = -EINVAL; } } else if (IS_NVSD_ATTR(soft_clipping_enable)) { nvsd_check_and_update(0, 1, soft_clipping_enable); } else if (IS_NVSD_ATTR(soft_clipping_threshold)) { nvsd_check_and_update(0, 255, soft_clipping_threshold); } else if (IS_NVSD_ATTR(smooth_k_enable)) { nvsd_check_and_update(0, 1, smooth_k_enable); } else if (IS_NVSD_ATTR(smooth_k_incr)) { nvsd_check_and_update(0, 16320, smooth_k_incr); } else if (IS_NVSD_ATTR(use_vpulse2)) { nvsd_check_and_update(0, 1, use_vpulse2); #endif } else if (IS_NVSD_ATTR(lut)) { if (nvsd_lut_store(sd_settings, buf)) res = -EINVAL; else settings_updated = true; } else if (IS_NVSD_ATTR(bltf)) { if (nvsd_bltf_store(sd_settings, buf)) res = -EINVAL; else settings_updated = true; } else { res = -EINVAL; } /* Re-init if our settings were updated. */ if (settings_updated) { mutex_lock(&dc->lock); if (!dc->enabled) { mutex_unlock(&dc->lock); return -ENODEV; } tegra_dc_hold_dc_out(dc); nvsd_init(dc, sd_settings); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); /* Update backlight state IFF we're disabling! */ if (!sd_settings->enable && sd_settings->bl_device) { /* Do the actual brightness update outside of * the mutex */ struct platform_device *pdev = sd_settings->bl_device; struct backlight_device *bl = platform_get_drvdata(pdev); if (bl) backlight_update_status(bl); } } } else { /* This shouldn't be reachable. But just in case... */ res = -EINVAL; } return res; }
int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user, struct tegra_dc_ext_cursor_image *args) { struct tegra_dc_ext *ext = user->ext; struct tegra_dc *dc = ext->dc; struct nvmap_handle_ref *handle, *old_handle; dma_addr_t phys_addr; u32 size; int ret; if (!user->nvmap) return -EFAULT; size = TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(args->flags); #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 && size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) return -EINVAL; #else if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 && size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64 && size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128 && size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256) return -EINVAL; #endif #if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC) if (args->flags && TEGRA_DC_EXT_CURSOR_FLAGS_RGBA_NORMAL) return -EINVAL; #endif mutex_lock(&ext->cursor.lock); if (ext->cursor.user != user) { ret = -EACCES; goto unlock; } if (!ext->enabled) { ret = -ENXIO; goto unlock; } old_handle = ext->cursor.cur_handle; ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr); if (ret) goto unlock; ext->cursor.cur_handle = handle; mutex_lock(&dc->lock); tegra_dc_io_start(dc); tegra_dc_hold_dc_out(dc); set_cursor_image_hw(dc, args, phys_addr); tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_release_dc_out(dc); tegra_dc_io_end(dc); /* XXX sync here? */ mutex_unlock(&dc->lock); mutex_unlock(&ext->cursor.lock); if (old_handle) { nvmap_unpin(ext->nvmap, old_handle); nvmap_free(ext->nvmap, old_handle); } return 0; unlock: mutex_unlock(&ext->cursor.lock); return ret; }
/* 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; }
/* does not support updating windows on multiple dcs in one call */ 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 = false; int i; dc = windows[0]->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_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]; 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 if (win->z != dc->blend.z[win->idx]) { dc->blend.z[win->idx] = win->z; update_blend = true; } if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) != dc->blend.flags[win->idx]) { dc->blend.flags[win->idx] = win->flags & TEGRA_WIN_BLEND_FLAGS_MASK; update_blend = 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->windows[i].dirty = 1; NV patch, but Now we do not use it */ 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); tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); 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) 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); win->dirty = no_vsync ? 0 : 1; dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d " "out_x=%u out_y=%u out_w=%u out_h=%u " "fmt=%d yuvp=%d Bpp=%u filter_h=%d filter_v=%d", __func__, win->idx, win->z, dfixed_trunc(win->x), dfixed_trunc(win->y), dfixed_trunc(win->w), dfixed_trunc(win->h), win->out_x, win->out_y, win->out_w, win->out_h, win->fmt, yuvp, Bpp, filter_h, filter_v); trace_printk("%s:win%u in:%ux%u out:%ux%u fmt=%d\n", dc->ndev->name, win->idx, dfixed_trunc(win->w), dfixed_trunc(win->h), win->out_w, win->out_h, win->fmt); } if (update_blend) { tegra_dc_set_blending(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); } else { clear_bit(V_BLANK_FLIP, &dc->vblank_ref_count); tegra_dc_mask_interrupt(dc, FRAME_END_INT | V_BLANK_INT | ALL_UF_INT); } if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) { atomic_set(&update_frame,1); 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); trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) mutex_unlock(&dc->one_shot_lock); bool is_yuvp = 0; for (i = 0; i < n; i++) { struct tegra_dc_win *win = windows[i]; bool yuvp = tegra_dc_is_yuv_planar(win->fmt); is_yuvp |= yuvp; } if (dc->ndev->id == 0) { struct tegra_dc_out *out = dc->out; struct tegra_dsi_out *dsi = out->dsi; struct tegra_dsi_cmd *cur = NULL; int n = dsi->n_cabc_cmd; if (out && dsi && dc->out_ops && dc->out_ops->send_cmd) { if (is_yuvp && !dc->isyuv_lasttime) { printk(KERN_INFO "[DISP] YUV\r\n"); cur = dsi->dsi_cabc_still_mode; dc->isyuv_lasttime = is_yuvp; } else if (!is_yuvp && dc->isyuv_lasttime) { printk(KERN_INFO "[DISP] RGB\r\n"); cur = dsi->dsi_cabc_moving_mode; dc->isyuv_lasttime = is_yuvp; } if (cur) { dc->out_ops->send_cmd(dc, cur, n); } } } return 0; }
static void _dump_regs(struct tegra_dc *dc, void *data, void (* print)(void *data, const char *str)) { int i; char buff[256]; mutex_lock(&dc->lock); tegra_dc_hold_dc_out(dc); tegra_dc_io_start(dc); DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); DUMP_REG(DC_CMD_DISPLAY_COMMAND); DUMP_REG(DC_CMD_SIGNAL_RAISE); DUMP_REG(DC_CMD_INT_STATUS); DUMP_REG(DC_CMD_INT_MASK); DUMP_REG(DC_CMD_INT_ENABLE); DUMP_REG(DC_CMD_INT_TYPE); DUMP_REG(DC_CMD_INT_POLARITY); DUMP_REG(DC_CMD_SIGNAL_RAISE1); DUMP_REG(DC_CMD_SIGNAL_RAISE2); DUMP_REG(DC_CMD_SIGNAL_RAISE3); DUMP_REG(DC_CMD_STATE_ACCESS); DUMP_REG(DC_CMD_STATE_CONTROL); DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER); DUMP_REG(DC_CMD_REG_ACT_CONTROL); DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0); DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1); DUMP_REG(DC_DISP_DISP_WIN_OPTIONS); DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY); DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY_TIMER); DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS); DUMP_REG(DC_DISP_REF_TO_SYNC); DUMP_REG(DC_DISP_SYNC_WIDTH); DUMP_REG(DC_DISP_BACK_PORCH); DUMP_REG(DC_DISP_DISP_ACTIVE); DUMP_REG(DC_DISP_FRONT_PORCH); DUMP_REG(DC_DISP_H_PULSE0_CONTROL); DUMP_REG(DC_DISP_H_PULSE0_POSITION_A); DUMP_REG(DC_DISP_H_PULSE0_POSITION_B); DUMP_REG(DC_DISP_H_PULSE0_POSITION_C); DUMP_REG(DC_DISP_H_PULSE0_POSITION_D); DUMP_REG(DC_DISP_H_PULSE1_CONTROL); DUMP_REG(DC_DISP_H_PULSE1_POSITION_A); DUMP_REG(DC_DISP_H_PULSE1_POSITION_B); DUMP_REG(DC_DISP_H_PULSE1_POSITION_C); DUMP_REG(DC_DISP_H_PULSE1_POSITION_D); DUMP_REG(DC_DISP_H_PULSE2_CONTROL); DUMP_REG(DC_DISP_H_PULSE2_POSITION_A); DUMP_REG(DC_DISP_H_PULSE2_POSITION_B); DUMP_REG(DC_DISP_H_PULSE2_POSITION_C); DUMP_REG(DC_DISP_H_PULSE2_POSITION_D); DUMP_REG(DC_DISP_V_PULSE0_CONTROL); DUMP_REG(DC_DISP_V_PULSE0_POSITION_A); DUMP_REG(DC_DISP_V_PULSE0_POSITION_B); DUMP_REG(DC_DISP_V_PULSE0_POSITION_C); DUMP_REG(DC_DISP_V_PULSE1_CONTROL); DUMP_REG(DC_DISP_V_PULSE1_POSITION_A); DUMP_REG(DC_DISP_V_PULSE1_POSITION_B); DUMP_REG(DC_DISP_V_PULSE1_POSITION_C); DUMP_REG(DC_DISP_V_PULSE2_CONTROL); DUMP_REG(DC_DISP_V_PULSE2_POSITION_A); DUMP_REG(DC_DISP_V_PULSE3_CONTROL); DUMP_REG(DC_DISP_V_PULSE3_POSITION_A); DUMP_REG(DC_DISP_M0_CONTROL); DUMP_REG(DC_DISP_M1_CONTROL); DUMP_REG(DC_DISP_DI_CONTROL); DUMP_REG(DC_DISP_PP_CONTROL); DUMP_REG(DC_DISP_PP_SELECT_A); DUMP_REG(DC_DISP_PP_SELECT_B); DUMP_REG(DC_DISP_PP_SELECT_C); DUMP_REG(DC_DISP_PP_SELECT_D); DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL); DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL); DUMP_REG(DC_DISP_DISP_COLOR_CONTROL); DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS); DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS); DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS); DUMP_REG(DC_DISP_LCD_SPI_OPTIONS); DUMP_REG(DC_DISP_BORDER_COLOR); DUMP_REG(DC_DISP_COLOR_KEY0_LOWER); DUMP_REG(DC_DISP_COLOR_KEY0_UPPER); DUMP_REG(DC_DISP_COLOR_KEY1_LOWER); DUMP_REG(DC_DISP_COLOR_KEY1_UPPER); DUMP_REG(DC_DISP_CURSOR_FOREGROUND); DUMP_REG(DC_DISP_CURSOR_BACKGROUND); DUMP_REG(DC_DISP_CURSOR_START_ADDR); DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS); DUMP_REG(DC_DISP_CURSOR_POSITION); DUMP_REG(DC_DISP_CURSOR_POSITION_NS); DUMP_REG(DC_DISP_INIT_SEQ_CONTROL); DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A); DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B); DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C); DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D); DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL); DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST); DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST); DUMP_REG(DC_DISP_MCCIF_DISPLAY0C_HYST); DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST); DUMP_REG(DC_DISP_DAC_CRT_CTRL); DUMP_REG(DC_DISP_DISP_MISC_CONTROL); for (i = 0; i < 3; i++) { print(data, "\n"); snprintf(buff, sizeof(buff), "WINDOW %c:\n", 'A' + i); print(data, buff); tegra_dc_writel(dc, WINDOW_A_SELECT << i, DC_CMD_DISPLAY_WINDOW_HEADER); DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER); DUMP_REG(DC_WIN_WIN_OPTIONS); DUMP_REG(DC_WIN_BYTE_SWAP); DUMP_REG(DC_WIN_BUFFER_CONTROL); DUMP_REG(DC_WIN_COLOR_DEPTH); DUMP_REG(DC_WIN_POSITION); DUMP_REG(DC_WIN_SIZE); DUMP_REG(DC_WIN_PRESCALED_SIZE); DUMP_REG(DC_WIN_H_INITIAL_DDA); DUMP_REG(DC_WIN_V_INITIAL_DDA); DUMP_REG(DC_WIN_DDA_INCREMENT); DUMP_REG(DC_WIN_LINE_STRIDE); DUMP_REG(DC_WIN_BUF_STRIDE); DUMP_REG(DC_WIN_UV_BUF_STRIDE); DUMP_REG(DC_WIN_BLEND_NOKEY); DUMP_REG(DC_WIN_BLEND_1WIN); DUMP_REG(DC_WIN_BLEND_2WIN_X); DUMP_REG(DC_WIN_BLEND_2WIN_Y); DUMP_REG(DC_WIN_BLEND_3WIN_XY); DUMP_REG(DC_WINBUF_START_ADDR); DUMP_REG(DC_WINBUF_START_ADDR_U); DUMP_REG(DC_WINBUF_START_ADDR_V); DUMP_REG(DC_WINBUF_ADDR_H_OFFSET); DUMP_REG(DC_WINBUF_ADDR_V_OFFSET); DUMP_REG(DC_WINBUF_UFLOW_STATUS); DUMP_REG(DC_WIN_CSC_YOF); DUMP_REG(DC_WIN_CSC_KYRGB); DUMP_REG(DC_WIN_CSC_KUR); DUMP_REG(DC_WIN_CSC_KVR); DUMP_REG(DC_WIN_CSC_KUG); DUMP_REG(DC_WIN_CSC_KVG); DUMP_REG(DC_WIN_CSC_KUB); DUMP_REG(DC_WIN_CSC_KVB); } DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL); DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE2); DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY2); DUMP_REG(DC_COM_PIN_OUTPUT_DATA2); DUMP_REG(DC_COM_PIN_INPUT_ENABLE2); DUMP_REG(DC_COM_PIN_OUTPUT_SELECT5); DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0); DUMP_REG(DC_DISP_M1_CONTROL); DUMP_REG(DC_COM_PM1_CONTROL); DUMP_REG(DC_COM_PM1_DUTY_CYCLE); DUMP_REG(DC_DISP_SD_CONTROL); tegra_dc_io_end(dc); tegra_dc_release_dc_out(dc); mutex_unlock(&dc->lock); }