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;
}
Example #2
0
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);
}
Example #3
0
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);
	}
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
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;
}
Example #7
0
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);
}
Example #8
0
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);
}
Example #9
0
/* 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);
}
Example #10
0
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;
}
Example #12
0
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;
}
Example #13
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;
}
Example #14
0
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;
}
Example #15
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 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;
}
Example #16
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;
}
Example #19
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;
}
Example #20
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);
}