Example #1
0
static void tegra_dc_dsi_suspend(struct tegra_dc *dc)
{
	struct tegra_dc_dsi_data *dsi;
	int err;

	dsi = tegra_dc_get_outdata(dc);

	tegra_dc_io_start(dc);
	mutex_lock(&dsi->lock);

	if (dsi->ulpm)
		tegra_dsi_exit_ulpm(dsi);

	err = tegra_dsi_send_panel_cmd(dc, dsi, dsi->info.dsi_suspend_cmd,
				dsi->info.n_suspend_cmd);
	if (err < 0) {
		dev_err(&dc->ndev->dev,
			"dsi: error while sending dsi suspend cmd\n");
		return;
	}

	clk_disable(dsi->dsi_clk);

	mutex_unlock(&dsi->lock);
	tegra_dc_io_end(dc);
}
Example #2
0
static bool _tegra_dc_enable(struct tegra_dc *dc)
{
	if (dc->mode.pclk == 0)
		return false;

	tegra_dc_io_start(dc);

	if (dc->out && dc->out->enable)
		dc->out->enable();

	tegra_dc_setup_clk(dc, dc->clk);

	clk_enable(dc->clk);
	clk_enable(dc->emc_clk);
	tegra_periph_reset_deassert(dc->clk);
	msleep(10);

	enable_irq(dc->irq);

	tegra_dc_init(dc);

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

	/* force a full blending update */
	dc->blend.z[0] = -1;

	tegra_dc_ext_enable(dc->ext);

	return true;
}
Example #3
0
static bool _tegra_dc_enable(struct tegra_dc *dc)
{

	if (dc->mode.pclk == 0) {
		switch (dc->out->type) {
		case TEGRA_DC_OUT_HDMI:
		/* DC enable called but no videomode is loaded.
		     Check if HDMI is connected, then set fallback mdoe */
		if (tegra_dc_hpd(dc)) {
			if (_tegra_dc_set_default_videomode(dc))
				return false;
		} else
			return false;

		break;

		/* Do nothing for other outputs for now */
		case TEGRA_DC_OUT_RGB:

		case TEGRA_DC_OUT_DSI:

		default:
			return false;
		}
	}

	if (!dc->out)
		return false;
	tegra_dc_io_start(dc);

	return _tegra_dc_controller_enable(dc);
}
static void tegra_dc_blend_parallel(struct tegra_dc *dc,
				struct tegra_dc_blend *blend)
{
	int win_num = dc->gen1_blend_num;
	unsigned long mask = BIT(win_num) - 1;

	tegra_dc_io_start(dc);
	while (mask) {
		int idx = get_topmost_window(blend->z, &mask, win_num);

		tegra_dc_writel(dc, WINDOW_A_SELECT << idx,
				DC_CMD_DISPLAY_WINDOW_HEADER);
		tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
				DC_WIN_BLEND_NOKEY);
		tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
				DC_WIN_BLEND_1WIN);
		tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0,
				win_num), DC_WIN_BLEND_2WIN_X);
		tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1,
				win_num), DC_WIN_BLEND_2WIN_Y);
		tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags,
				win_num), DC_WIN_BLEND_3WIN_XY);
	}
	tegra_dc_io_end(dc);
}
Example #5
0
static void tegra_dc_rgb_disable(struct tegra_dc *dc)
{
	tegra_dc_io_start(dc);
	tegra_dc_writel(dc, 0x00000000, DC_CMD_DISPLAY_POWER_CONTROL);

	tegra_dc_write_table(dc, tegra_dc_rgb_disable_pintable);
	tegra_dc_io_end(dc);
}
Example #6
0
static void tegra_dc_dsi_enable(struct tegra_dc *dc)
{
	struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
	int err;

	tegra_dc_io_start(dc);
	mutex_lock(&dsi->lock);

	if (dsi->ulpm) {
		tegra_dsi_exit_ulpm(dsi);
		if (dsi->info.panel_reset) {
			err = tegra_dsi_send_panel_cmd(dc, dsi,
							dsi->info.dsi_init_cmd,
							dsi->info.n_init_cmd);
			if (err < 0) {
				dev_err(&dc->ndev->dev,
				"dsi: error while sending dsi init cmd\n");
				return;
			}
		}
	} else {
		err = tegra_dsi_init_hw(dc, dsi);
		if (err < 0) {
			dev_err(&dc->ndev->dev,
				"dsi: not able to init dsi hardware\n");
			return;
		}

		err = tegra_dsi_set_to_lp_mode(dc, dsi);
		if (err < 0) {
			dev_err(&dc->ndev->dev,
				"dsi: not able to set to lp mode\n");
			return;
		}

		err = tegra_dsi_send_panel_cmd(dc, dsi, dsi->info.dsi_init_cmd,
						dsi->info.n_init_cmd);
		if (err < 0) {
			dev_err(&dc->ndev->dev,
				"dsi: error while sending dsi init cmd\n");
			return;
		}

		err = tegra_dsi_set_to_hs_mode(dc, dsi);
		if (err < 0) {
				dev_err(&dc->ndev->dev,
					"dsi: not able to set to hs mode\n");
			return;
		}
	}

	if (dsi->status.driven == DSI_DRIVEN_MODE_DC) {
		tegra_dsi_start_dc_stream(dc, dsi);
	}

	mutex_unlock(&dsi->lock);
	tegra_dc_io_end(dc);
}
static void tegra_dc_blend_sequential(struct tegra_dc *dc,
				struct tegra_dc_blend *blend)
{
	int i;

	tegra_dc_io_start(dc);
	for (i = 0; i < DC_N_WINDOWS; i++) {
		if (!tegra_dc_feature_is_gen2_blender(dc, i))
			continue;

		tegra_dc_writel(dc, WINDOW_A_SELECT << i,
				DC_CMD_DISPLAY_WINDOW_HEADER);

		if (blend->flags[i] & TEGRA_WIN_FLAG_BLEND_COVERAGE) {
			tegra_dc_writel(dc,
					WIN_K1(0xff) |
					WIN_K2(0xff) |
					WIN_BLEND_ENABLE,
					DC_WINBUF_BLEND_LAYER_CONTROL);

			tegra_dc_writel(dc,
			WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1_TIMES_SRC |
			WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1_TIMES_SRC |
			WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 |
			WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO,
			DC_WINBUF_BLEND_MATCH_SELECT);

			tegra_dc_writel(dc,
					WIN_ALPHA_1BIT_WEIGHT0(0) |
					WIN_ALPHA_1BIT_WEIGHT1(0xff),
					DC_WINBUF_BLEND_ALPHA_1BIT);
		} else if (blend->flags[i] & TEGRA_WIN_FLAG_BLEND_PREMULT) {
			tegra_dc_writel(dc,
					WIN_K1(0xff) |
					WIN_K2(0xff) |
					WIN_BLEND_ENABLE,
					DC_WINBUF_BLEND_LAYER_CONTROL);

			tegra_dc_writel(dc,
			WIN_BLEND_FACT_SRC_COLOR_MATCH_SEL_K1 |
			WIN_BLEND_FACT_DST_COLOR_MATCH_SEL_NEG_K1 |
			WIN_BLEND_FACT_SRC_ALPHA_MATCH_SEL_K2 |
			WIN_BLEND_FACT_DST_ALPHA_MATCH_SEL_ZERO,
			DC_WINBUF_BLEND_MATCH_SELECT);

			tegra_dc_writel(dc,
					WIN_ALPHA_1BIT_WEIGHT0(0) |
					WIN_ALPHA_1BIT_WEIGHT1(0xff),
					DC_WINBUF_BLEND_ALPHA_1BIT);
		} else {
			tegra_dc_writel(dc,
					WIN_BLEND_BYPASS,
					DC_WINBUF_BLEND_LAYER_CONTROL);
		}
	}
	tegra_dc_io_end(dc);
}
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 #9
0
void tegra_dc_enable_crc(struct tegra_dc *dc)
{
	u32 val;
	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);
}
Example #10
0
static bool nvsd_phase_in_adjustments(struct tegra_dc *dc,
	struct tegra_dc_sd_settings *settings)
{
	u8 step, cur_sd_brightness;
	u16 target_k, cur_k;
	u32 man_k, val;

	cur_sd_brightness = atomic_read(_sd_brightness);

	target_k = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES);
	target_k = SD_HW_K_R(target_k);
	cur_k = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES);
	cur_k = SD_HW_K_R(cur_k);

	/* read brightness value */
	val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL);
	val = SD_BLC_BRIGHTNESS(val);

	step = settings->phase_adj_step;
	if (cur_sd_brightness != val || target_k != cur_k) {
		if (!step)
			step = ADJ_PHASE_STEP;

		/* Phase in Backlight and Pixel K
		every ADJ_PHASE_STEP frames*/
		if ((step-- & ADJ_PHASE_STEP) == ADJ_PHASE_STEP) {

			if (val != cur_sd_brightness) {
				val > cur_sd_brightness ?
				(cur_sd_brightness++) :
				(cur_sd_brightness--);
			}

			if (target_k != cur_k) {
				if (target_k > cur_k)
					cur_k += K_STEP;
				else
					cur_k -= K_STEP;
			}

			/* Set manual k value */
			man_k = SD_MAN_K_R(cur_k) |
				SD_MAN_K_G(cur_k) | SD_MAN_K_B(cur_k);
			tegra_dc_io_start(dc);
			tegra_dc_writel(dc, man_k, DC_DISP_SD_MAN_K_VALUES);
			tegra_dc_io_end(dc);
			/* Set manual brightness value */
			atomic_set(_sd_brightness, cur_sd_brightness);
		}
		settings->phase_adj_step = step;
		return true;
	} else
		return false;
}
int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable)
{
	tegra_dc_io_start(dc);
	tegra_dc_writel(dc, FRAME_END_INT, DC_CMD_INT_STATUS);
	if (enable) {
		atomic_inc(&frame_end_ref);
		tegra_dc_unmask_interrupt(dc, FRAME_END_INT);
	} else if (!atomic_dec_return(&frame_end_ref))
		tegra_dc_mask_interrupt(dc, FRAME_END_INT);
	tegra_dc_io_end(dc);
	return 0;
}
Example #12
0
static irqreturn_t tegra_dc_irq(int irq, void *ptr)
{
#ifndef CONFIG_TEGRA_FPGA_PLATFORM
	struct tegra_dc *dc = ptr;
	unsigned long status;
	unsigned long underflow_mask;
	u32 val;

	if (!nvhost_module_powered_ext(nvhost_get_parent(dc->ndev))) {
		WARN(1, "IRQ when DC not powered!\n");
		tegra_dc_io_start(dc);
		status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
		tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
		tegra_dc_io_end(dc);
		return IRQ_HANDLED;
	}

	/* clear all status flags except underflow, save those for the worker */
	status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
	tegra_dc_writel(dc, status & ~ALL_UF_INT, DC_CMD_INT_STATUS);
	val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
	tegra_dc_writel(dc, val & ~ALL_UF_INT, DC_CMD_INT_MASK);

	/*
	 * Overlays can get thier internal state corrupted during and underflow
	 * condition.  The only way to fix this state is to reset the DC.
	 * if we get 4 consecutive frames with underflows, assume we're
	 * hosed and reset.
	 */
	underflow_mask = status & ALL_UF_INT;

	/* Check underflow */
	if (underflow_mask) {
		dc->underflow_mask |= underflow_mask;
		schedule_delayed_work(&dc->underflow_work,
			msecs_to_jiffies(1));
	}

	if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
		tegra_dc_one_shot_irq(dc, status);
	else
		tegra_dc_continuous_irq(dc, status);

	return IRQ_HANDLED;
#else /* CONFIG_TEGRA_FPGA_PLATFORM */
	return IRQ_NONE;
#endif /* !CONFIG_TEGRA_FPGA_PLATFORM */
}
Example #13
0
static bool _tegra_dc_enable(struct tegra_dc *dc)
{
	if (dc->mode.pclk == 0)
		return false;

	if (!dc->out)
		return false;

	tegra_dc_io_start(dc);

	if (!_tegra_dc_controller_enable(dc)) {
		tegra_dc_io_end(dc);
		return false;
	}
	return true;
}
Example #14
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);
}
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 #16
0
static ssize_t nvsd_registers_show(struct kobject *kobj,
	struct kobj_attribute *attr, char *buf)
{
	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);
	ssize_t res = 0;

	clk_enable(dc->clk);
	tegra_dc_io_start(dc);

	mutex_lock(&dc->lock);
	if (!dc->enabled) {
		mutex_unlock(&dc->lock);
		return -ENODEV;
	}

	mutex_unlock(&dc->lock);
	NVSD_PRINT_REG(DC_DISP_SD_CONTROL);
	NVSD_PRINT_REG(DC_DISP_SD_CSC_COEFF);
	NVSD_PRINT_REG_ARRAY(DC_DISP_SD_LUT);
	NVSD_PRINT_REG(DC_DISP_SD_FLICKER_CONTROL);
	NVSD_PRINT_REG(DC_DISP_SD_PIXEL_COUNT);
	NVSD_PRINT_REG_ARRAY(DC_DISP_SD_HISTOGRAM);
	NVSD_PRINT_REG(DC_DISP_SD_BL_PARAMETERS);
	NVSD_PRINT_REG_ARRAY(DC_DISP_SD_BL_TF);
	NVSD_PRINT_REG(DC_DISP_SD_BL_CONTROL);
	NVSD_PRINT_REG(DC_DISP_SD_HW_K_VALUES);
	NVSD_PRINT_REG(DC_DISP_SD_MAN_K_VALUES);
#ifdef CONFIG_TEGRA_SD_GEN2
	NVSD_PRINT_REG(DC_DISP_SD_K_LIMIT);
	NVSD_PRINT_REG(DC_DISP_SD_WINDOW_POSITION);
	NVSD_PRINT_REG(DC_DISP_SD_WINDOW_SIZE);
	NVSD_PRINT_REG(DC_DISP_SD_SOFT_CLIPPING);
	NVSD_PRINT_REG(DC_DISP_SD_SMOOTH_K);
#endif

	tegra_dc_io_end(dc);
	clk_disable(dc->clk);

	return res;
}
Example #17
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_io_start(dc);
	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);
	tegra_dc_io_end(dc);

	mutex_unlock(&dc->lock);

	return 0;
}
static int dbg_dsi_show(struct seq_file *s, void *unused)
{
    struct tegra_dc_dsi_data *dsi = s->private;
    unsigned long i = 0, j = 0;
    u32 col = 0;
    u32 base[MAX_DSI_INSTANCE] = {TEGRA_DSI_BASE, TEGRA_DSIB_BASE};

    if (!dsi->enabled) {
        seq_puts(s, "DSI controller suspended\n");
        return 0;
    }

    tegra_dc_io_start(dsi->dc);
    tegra_dsi_clk_enable(dsi);

    /* mem dd dump */
    for (i = 0; i < dsi->max_instances; i++) {
        for (col = 0, j = 0; j < 0x64; j++) {
            if (col == 0)
                seq_printf(s, "%08lX:", base[i] + 4*j);
            seq_printf(s, "%c%08lX", col == 2 ? '-' : ' ',
                       tegra_dsi_controller_readl(dsi, j, i));
            if (col == 3) {
                seq_puts(s, "\n");
                col = 0;
            } else
                col++;
        }
        seq_puts(s, "\n");
    }

#define DUMP_REG(a)	seq_printf(s, "%-45s | %#05x | %#010lx |\n", \
					#a, a, tegra_dsi_readl(dsi, a));

    DUMP_REG(DSI_INCR_SYNCPT_CNTRL);
    DUMP_REG(DSI_INCR_SYNCPT_ERROR);
    DUMP_REG(DSI_CTXSW);
    DUMP_REG(DSI_POWER_CONTROL);
    DUMP_REG(DSI_INT_ENABLE);
    DUMP_REG(DSI_HOST_DSI_CONTROL);
    DUMP_REG(DSI_CONTROL);
    DUMP_REG(DSI_SOL_DELAY);
    DUMP_REG(DSI_MAX_THRESHOLD);
    DUMP_REG(DSI_TRIGGER);
    DUMP_REG(DSI_TX_CRC);
    DUMP_REG(DSI_STATUS);
    DUMP_REG(DSI_INIT_SEQ_CONTROL);
    DUMP_REG(DSI_INIT_SEQ_DATA_0);
    DUMP_REG(DSI_INIT_SEQ_DATA_1);
    DUMP_REG(DSI_INIT_SEQ_DATA_2);
    DUMP_REG(DSI_INIT_SEQ_DATA_3);
    DUMP_REG(DSI_INIT_SEQ_DATA_4);
    DUMP_REG(DSI_INIT_SEQ_DATA_5);
    DUMP_REG(DSI_INIT_SEQ_DATA_6);
    DUMP_REG(DSI_INIT_SEQ_DATA_7);
    DUMP_REG(DSI_PKT_SEQ_0_LO);
    DUMP_REG(DSI_PKT_SEQ_0_HI);
    DUMP_REG(DSI_PKT_SEQ_1_LO);
    DUMP_REG(DSI_PKT_SEQ_1_HI);
    DUMP_REG(DSI_PKT_SEQ_2_LO);
    DUMP_REG(DSI_PKT_SEQ_2_HI);
    DUMP_REG(DSI_PKT_SEQ_3_LO);
    DUMP_REG(DSI_PKT_SEQ_3_HI);
    DUMP_REG(DSI_PKT_SEQ_4_LO);
    DUMP_REG(DSI_PKT_SEQ_4_HI);
    DUMP_REG(DSI_PKT_SEQ_5_LO);
    DUMP_REG(DSI_PKT_SEQ_5_HI);
    DUMP_REG(DSI_DCS_CMDS);
    DUMP_REG(DSI_PKT_LEN_0_1);
    DUMP_REG(DSI_PKT_LEN_2_3);
    DUMP_REG(DSI_PKT_LEN_4_5);
    DUMP_REG(DSI_PKT_LEN_6_7);
    DUMP_REG(DSI_PHY_TIMING_0);
    DUMP_REG(DSI_PHY_TIMING_1);
    DUMP_REG(DSI_PHY_TIMING_2);
    DUMP_REG(DSI_BTA_TIMING);
    DUMP_REG(DSI_TIMEOUT_0);
    DUMP_REG(DSI_TIMEOUT_1);
    DUMP_REG(DSI_TO_TALLY);
    DUMP_REG(DSI_PAD_CONTROL);
    DUMP_REG(DSI_PAD_CONTROL_CD);
    DUMP_REG(DSI_PAD_CD_STATUS);
    DUMP_REG(DSI_VID_MODE_CONTROL);
    DUMP_REG(DSI_PAD_CONTROL_0_VS1);
    DUMP_REG(DSI_PAD_CONTROL_CD_VS1);
    DUMP_REG(DSI_PAD_CD_STATUS_VS1);
    DUMP_REG(DSI_PAD_CONTROL_1_VS1);
    DUMP_REG(DSI_PAD_CONTROL_2_VS1);
    DUMP_REG(DSI_PAD_CONTROL_3_VS1);
    DUMP_REG(DSI_PAD_CONTROL_4_VS1);
    DUMP_REG(DSI_GANGED_MODE_CONTROL);
    DUMP_REG(DSI_GANGED_MODE_START);
    DUMP_REG(DSI_GANGED_MODE_SIZE);
#undef DUMP_REG

    tegra_dsi_clk_disable(dsi);
    tegra_dc_io_end(dsi->dc);

    return 0;
}
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;
}
Example #20
0
static void handle_check_edid_l(struct tegra_dc_hdmi_data *hdmi)
{
	struct fb_monspecs specs;
#ifdef CONFIG_SWITCH
	int state;
#endif

	memset(&specs, 0, sizeof(specs));
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
	/* Set default videomode on dc before enabling it*/
	tegra_dc_set_default_videomode(hdmi->dc);
#endif

	if (!tegra_dc_hpd(work_state.hdmi->dc)) {
		/* hpd dropped - stop EDID read */
		pr_info("hpd == 0, aborting EDID read\n");
		goto end_disabled;
	}

	if (tegra_edid_get_monspecs(hdmi->edid, &specs)) {
		/* Failed to read EDID.  If we still have retry attempts left,
		 * schedule another attempt.  Otherwise give up and just go to
		 * the disabled state.
		 */
		work_state.edid_reads++;
		if (work_state.edid_reads >= MAX_EDID_READ_ATTEMPTS) {
			pr_info("Failed to read EDID after %d times. Giving up.\n",
				work_state.edid_reads);
			goto end_disabled;
		} else {
			hdmi_state_machine_set_state_l(HDMI_STATE_CHECK_EDID,
						       CHECK_EDID_DELAY_MS);
		}

		return;
	}

	if (tegra_edid_get_eld(hdmi->edid, &hdmi->eld) < 0) {
		pr_err("error populating eld\n");
		goto end_disabled;
	}
	hdmi->eld_retrieved = true;

	pr_info("panel size %d by %d\n", specs.max_x, specs.max_y);

	/* monitors like to lie about these but they are still useful for
	 * detecting aspect ratios
	 */
	hdmi->dc->out->h_size = specs.max_x * 1000;
	hdmi->dc->out->v_size = specs.max_y * 1000;

	hdmi->dvi = !(specs.misc & FB_MISC_HDMI);

#ifdef CONFIG_ADF_TEGRA
	tegra_adf_process_hotplug_connected(hdmi->dc->adf, &specs);
#endif
#ifdef CONFIG_TEGRA_DC_EXTENSIONS
	tegra_fb_update_monspecs(hdmi->dc->fb, &specs,
		tegra_dc_hdmi_mode_filter);
#endif
#ifdef CONFIG_SWITCH
	state = tegra_edid_audio_supported(hdmi->edid) ? 1 : 0;
	switch_set_state(&hdmi->audio_switch, state);
	pr_info("%s: audio_switch %d\n", __func__, state);
	switch_set_state(&hdmi->hpd_switch, 1);
	pr_info("Display connected, hpd_switch 1\n");
#endif
	hdmi->dc->connected = true;

#ifdef CONFIG_TEGRA_DC_EXTENSIONS
	tegra_dc_ext_process_hotplug(hdmi->dc->ndev->id);
#endif

	if (unlikely(tegra_is_clk_enabled(hdmi->clk))) {
		/* the only time this should happen is on boot, where the
		 * sequence is that hdmi is enabled before EDID is read.
		 * hdmi_enable() doesn't have EDID information yet so can't
		 * setup audio and infoframes, so we have to do so here.
		 */
		pr_info("%s: setting audio and infoframes\n", __func__);
		tegra_dc_io_start(hdmi->dc);
		tegra_dc_hdmi_setup_audio_and_infoframes(hdmi->dc);
		tegra_dc_io_end(hdmi->dc);
	}

	hdmi_state_machine_set_state_l(HDMI_STATE_DONE_ENABLED, -1);

	return;

end_disabled:
	hdmi->eld_retrieved = false;
	hdmi_disable_l(hdmi);
	hdmi_state_machine_set_state_l(HDMI_STATE_DONE_DISABLED, -1);
}
Example #21
0
static void _dump_regs(struct tegra_dc *dc, void *data,
		       void (* print)(void *data, const char *str))
{
	int i;
	char buff[256];

	tegra_dc_io_start(dc);
	clk_enable(dc->clk);

	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);
	}

	clk_disable(dc->clk);
	tegra_dc_io_end(dc);
}
/* 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 #23
0
/* Functional initialization */
void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings)
{
	u32 i = 0;
	u32 val = 0;
	u32 bw = 0;
	u32 bw_idx = 0;
	/* TODO: check if HW says SD's available */

	tegra_dc_io_start(dc);
	/* If SD's not present or disabled, clear the register and return. */
	if (!settings || settings->enable == 0) {
		/* clear the brightness val, too. */
		if (_sd_brightness)
			atomic_set(_sd_brightness, 255);

		_sd_brightness = NULL;

		if (settings)
			settings->phase_settings_step = 0;
		tegra_dc_writel(dc, 0, DC_DISP_SD_CONTROL);
		tegra_dc_io_end(dc);
		return;
	}

	dev_dbg(&dc->ndev->dev, "NVSD Init:\n");

	/* init agg_priorities */
	if (!settings->agg_priorities.agg[0])
		settings->agg_priorities.agg[0] = settings->aggressiveness;

	/* WAR: Settings will not be valid until the next flip.
	 * Thus, set manual K to either HW's current value (if
	 * we're already enabled) or a non-effective value (if
	 * we're about to enable). */
	val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);

	if (val & SD_ENABLE_NORMAL)
		if (settings->phase_in_adjustments)
			i = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES);
		else
			i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES);
	else
		i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */

	tegra_dc_writel(dc, i, DC_DISP_SD_MAN_K_VALUES);
	/* Enable manual correction mode here so that changing the
	 * settings won't immediately impact display dehavior. */
	val |= SD_CORRECTION_MODE_MAN;
	tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);

	bw_idx = nvsd_get_bw_idx(settings);
	bw = SD_BIN_WIDTH(bw_idx);

	/* Values of SD LUT & BL TF are different according to bin_width on T30
	 * due to HW bug. Therefore we use bin_width to select the correct table
	 * on T30. On T114, we will use 1st table by default.*/
#ifdef CONFIG_TEGRA_SD_GEN2
	bw_idx = 0;
#endif
	/* Write LUT */
	if (!settings->cmd) {
		dev_dbg(&dc->ndev->dev, "  LUT:\n");

		for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) {
			val = SD_LUT_R(settings->lut[bw_idx][i].r) |
				SD_LUT_G(settings->lut[bw_idx][i].g) |
				SD_LUT_B(settings->lut[bw_idx][i].b);
			tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i));

			dev_dbg(&dc->ndev->dev, "    %d: 0x%08x\n", i, val);
		}
	}

	/* Write BL TF */
	if (!settings->cmd) {
		dev_dbg(&dc->ndev->dev, "  BL_TF:\n");

		for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
			val = SD_BL_TF_POINT_0(settings->bltf[bw_idx][i][0]) |
				SD_BL_TF_POINT_1(settings->bltf[bw_idx][i][1]) |
				SD_BL_TF_POINT_2(settings->bltf[bw_idx][i][2]) |
				SD_BL_TF_POINT_3(settings->bltf[bw_idx][i][3]);

			tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));

			dev_dbg(&dc->ndev->dev, "    %d: 0x%08x\n", i, val);
		}
	} else if ((settings->cmd & PHASE_IN)) {
		settings->cmd &= ~PHASE_IN;
		/* Write NO_OP values for BLTF */
		for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
			val = SD_BL_TF_POINT_0(0xFF) |
				SD_BL_TF_POINT_1(0xFF) |
				SD_BL_TF_POINT_2(0xFF) |
				SD_BL_TF_POINT_3(0xFF);

			tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));

			dev_dbg(&dc->ndev->dev, "    %d: 0x%08x\n", i, val);
		}
	}

	/* Set step correctly on init */
	if (!settings->cmd && settings->phase_in_settings) {
		settings->num_phase_in_steps = STEPS_PER_AGG_LVL *
			settings->aggressiveness;
		settings->phase_settings_step = settings->enable ?
			settings->num_phase_in_steps : 0;
	}

	/* Write Coeff */
	val = SD_CSC_COEFF_R(settings->coeff.r) |
		SD_CSC_COEFF_G(settings->coeff.g) |
		SD_CSC_COEFF_B(settings->coeff.b);
	tegra_dc_writel(dc, val, DC_DISP_SD_CSC_COEFF);
	dev_dbg(&dc->ndev->dev, "  COEFF: 0x%08x\n", val);

	/* Write BL Params */
	val = SD_BLP_TIME_CONSTANT(settings->blp.time_constant) |
		SD_BLP_STEP(settings->blp.step);
	tegra_dc_writel(dc, val, DC_DISP_SD_BL_PARAMETERS);
	dev_dbg(&dc->ndev->dev, "  BLP: 0x%08x\n", val);

	/* Write Auto/Manual PWM */
	val = (settings->use_auto_pwm) ? SD_BLC_MODE_AUTO : SD_BLC_MODE_MAN;
	tegra_dc_writel(dc, val, DC_DISP_SD_BL_CONTROL);
	dev_dbg(&dc->ndev->dev, "  BL_CONTROL: 0x%08x\n", val);

	/* Write Flicker Control */
	val = SD_FC_TIME_LIMIT(settings->fc.time_limit) |
		SD_FC_THRESHOLD(settings->fc.threshold);
	tegra_dc_writel(dc, val, DC_DISP_SD_FLICKER_CONTROL);
	dev_dbg(&dc->ndev->dev, "  FLICKER_CONTROL: 0x%08x\n", val);

#ifdef CONFIG_TEGRA_SD_GEN2
	/* Write K limit */
	if (settings->k_limit_enable) {
		val = settings->k_limit;
		if (val < 128)
			val = 128;
		else if (val > 255)
			val = 255;
		val = SD_K_LIMIT(val);
		tegra_dc_writel(dc, val, DC_DISP_SD_K_LIMIT);
		dev_dbg(&dc->ndev->dev, "  K_LIMIT: 0x%08x\n", val);
	}

	if (settings->sd_window_enable) {
		/* Write sd window */
		val = SD_WIN_H_POSITION(settings->sd_window.h_position) |
			SD_WIN_V_POSITION(settings->sd_window.v_position);
		tegra_dc_writel(dc, val, DC_DISP_SD_WINDOW_POSITION);
		dev_dbg(&dc->ndev->dev, "  SD_WINDOW_POSITION: 0x%08x\n", val);

		val = SD_WIN_H_POSITION(settings->sd_window.h_size) |
			SD_WIN_V_POSITION(settings->sd_window.v_size);
		tegra_dc_writel(dc, val, DC_DISP_SD_WINDOW_SIZE);
		dev_dbg(&dc->ndev->dev, "  SD_WINDOW_SIZE: 0x%08x\n", val);
	}

	if (settings->soft_clipping_enable) {
		/* Write soft clipping */
		val = (64 * 1024) / (256 - settings->soft_clipping_threshold);
		val = SD_SOFT_CLIPPING_RECIP(val) |
		SD_SOFT_CLIPPING_THRESHOLD(settings->soft_clipping_threshold);
		tegra_dc_writel(dc, val, DC_DISP_SD_SOFT_CLIPPING);
		dev_dbg(&dc->ndev->dev, "  SOFT_CLIPPING: 0x%08x\n", val);
	}

	if (settings->smooth_k_enable) {
		fixed20_12 smooth_k_incr;
		fixed20_12 num;

		/* Write K incr value */
		val = SD_SMOOTH_K_INCR(settings->smooth_k_incr);
		tegra_dc_writel(dc, val, DC_DISP_SD_SMOOTH_K);
		dev_dbg(&dc->ndev->dev, "  SMOOTH_K: 0x%08x\n", val);

		/* Convert 8.6 fixed-point to 20.12 fixed-point */
		smooth_k_incr.full = val << 6;

		/* In the BL_TF LUT, raw K is specified in steps of 8 */
		num.full = dfixed_const(8);

		num.full = dfixed_div(num, smooth_k_incr);
		num.full = dfixed_ceil(num);
		smooth_k_frames_left = dfixed_trunc(num);
		smooth_k_duration_frames = smooth_k_frames_left;
		dev_dbg(&dc->ndev->dev, "  Smooth K duration (frames): %d\n",
			smooth_k_frames_left);
	}
#endif

	/* Manage SD Control */
	val = 0;
	/* Stay in manual correction mode until the next flip. */
	val |= SD_CORRECTION_MODE_MAN;
	/* Enable / One-Shot */
	val |= (settings->enable == 2) ?
		(SD_ENABLE_ONESHOT | SD_ONESHOT_ENABLE) :
		SD_ENABLE_NORMAL;
	/* HW Update Delay */
	val |= SD_HW_UPDATE_DLY(settings->hw_update_delay);
	/* Video Luma */
	val |= (settings->use_vid_luma) ? SD_USE_VID_LUMA : 0;
	/* Aggressiveness */
	val |= SD_AGGRESSIVENESS(settings->aggressiveness);
	/* Bin Width (value derived above) */
	val |= bw;
#ifdef CONFIG_TEGRA_SD_GEN2
	/* K limit enable */
	val |= (settings->k_limit_enable) ? SD_K_LIMIT_ENABLE : 0;
	/* Programmable sd window enable */
	val |= (settings->sd_window_enable) ? SD_WINDOW_ENABLE : 0;
	/* Soft clipping enable */
	val |= (settings->soft_clipping_enable) ? SD_SOFT_CLIPPING_ENABLE : 0;
	/* Smooth K enable */
	val |= (settings->smooth_k_enable) ? SD_SMOOTH_K_ENABLE : 0;
	/* SD proc control */
	val |= (settings->use_vpulse2) ? SD_VPULSE2 : SD_VSYNC;
#endif
	/* Finally, Write SD Control */
	tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
	dev_dbg(&dc->ndev->dev, "  SD_CONTROL: 0x%08x\n", val);
	tegra_dc_io_end(dc);

	/* set the brightness pointer */
	_sd_brightness = settings->sd_brightness;

	/* note that we're in manual K until the next flip */
	atomic_set(&man_k_until_blank, 1);
}
Example #24
0
static void tegra_dc_rgb_enable(struct tegra_dc *dc)
{
	int i;
	u32 out_sel_pintable[ARRAY_SIZE(tegra_dc_rgb_enable_out_sel_pintable)];

	tegra_dc_io_start(dc);
	tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
			PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
			DC_CMD_DISPLAY_POWER_CONTROL);

	tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);

	if (dc->out->out_pins) {
		tegra_dc_set_out_pin_polars(dc, dc->out->out_pins,
			dc->out->n_out_pins);
		tegra_dc_write_table(dc, tegra_dc_rgb_enable_partial_pintable);
	} else {
		tegra_dc_write_table(dc, tegra_dc_rgb_enable_pintable);
	}

	memcpy(out_sel_pintable, tegra_dc_rgb_enable_out_sel_pintable,
		sizeof(tegra_dc_rgb_enable_out_sel_pintable));

	/* The display panel sub-board used on FPGA platforms (panel 86)
	   is non-standard. It expects the Data Enable signal on the WR
	   pin instead of the DE pin. */
	if (tegra_platform_is_fpga())
		out_sel_pintable[3*2+1] = 0x00200000;

	if (dc->out && dc->out->out_sel_configs) {
		u8 *out_sels = dc->out->out_sel_configs;
		for (i = 0; i < dc->out->n_out_sel_configs; i++) {
			switch (out_sels[i]) {
			case TEGRA_PIN_OUT_CONFIG_SEL_LM1_M1:
				out_sel_pintable[5*2+1] =
					(out_sel_pintable[5*2+1] &
					~PIN5_LM1_LCD_M1_OUTPUT_MASK) |
					PIN5_LM1_LCD_M1_OUTPUT_M1;
				break;
			case TEGRA_PIN_OUT_CONFIG_SEL_LM1_LD21:
				out_sel_pintable[5*2+1] =
					(out_sel_pintable[5*2+1] &
					~PIN5_LM1_LCD_M1_OUTPUT_MASK) |
					PIN5_LM1_LCD_M1_OUTPUT_LD21;
				break;
			case TEGRA_PIN_OUT_CONFIG_SEL_LM1_PM1:
				out_sel_pintable[5*2+1] =
					(out_sel_pintable[5*2+1] &
					~PIN5_LM1_LCD_M1_OUTPUT_MASK) |
					PIN5_LM1_LCD_M1_OUTPUT_PM1;
				break;
			default:
				dev_err(&dc->ndev->dev,
					"Invalid pin config[%d]: %d\n",
					 i, out_sels[i]);
				break;
			}
		}
	}

	tegra_dc_write_table(dc, out_sel_pintable);

	/* Inform DC register updated */
	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
	tegra_dc_io_end(dc);
}
int esc_mods_tegra_dc_setup_sd(struct file *fp,
	struct MODS_TEGRA_DC_SETUP_SD *args)
{
	int i;
	struct tegra_dc *dc = tegra_dc_get_dc(args->head);
	struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings;
#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
	u32 val;
#endif
	u32 bw_idx;
	LOG_ENT();

	BUG_ON(args->head > TEGRA_MAX_DC);

	sd_settings->enable = args->enable ? 1 : 0;
	sd_settings->use_auto_pwm = false;
	sd_settings->hw_update_delay = 0;

	sd_settings->aggressiveness = args->aggressiveness;
	sd_settings->bin_width = (1 << args->bin_width_log2);

	sd_settings->phase_in_settings = 0;
	sd_settings->phase_in_adjustments = 0;
	sd_settings->cmd = 0;
	sd_settings->final_agg = args->aggressiveness;
	sd_settings->cur_agg_step = 0;
	sd_settings->phase_settings_step = 0;
	sd_settings->phase_adj_step = 0;
	sd_settings->num_phase_in_steps = 0;

	sd_settings->agg_priorities.agg[0] = args->aggressiveness;

	sd_settings->use_vid_luma = args->use_vid_luma;
	sd_settings->coeff.r = args->csc_r;
	sd_settings->coeff.g = args->csc_g;
	sd_settings->coeff.b = args->csc_b;

	sd_settings->k_limit_enable = (args->klimit != 0);
	sd_settings->k_limit = args->klimit;
	sd_settings->sd_window_enable = true;

	sd_settings->sd_window.h_position = args->win_x;
	sd_settings->sd_window.v_position = args->win_y;
	sd_settings->sd_window.h_size     = args->win_w;
	sd_settings->sd_window.v_size     = args->win_h;

	sd_settings->soft_clipping_enable    = true;
	sd_settings->soft_clipping_threshold = args->soft_clipping_threshold;


	sd_settings->smooth_k_enable = (args->smooth_k_inc != 0);
	sd_settings->smooth_k_incr   = args->smooth_k_inc;

	sd_settings->sd_proc_control = false;
	sd_settings->soft_clipping_correction = false;
	sd_settings->use_vpulse2 = false;

	sd_settings->fc.time_limit = 0;
	sd_settings->fc.threshold  = 0;

	sd_settings->blp.time_constant = 1024;
	sd_settings->blp.step          = 0;


#ifdef CONFIG_TEGRA_SD_GEN2
	bw_idx = 0;
#else
	bw_idx = args->bin_width_log2;
#endif
	for (i = 0; i < MODS_TEGRA_DC_SETUP_BLTF_SIZE; i++) {
		sd_settings->bltf[bw_idx][i/4][i%4] =
			args->bltf[i];
	}

	for (i = 0; i < MODS_TEGRA_DC_SETUP_SD_LUT_SIZE; i++) {
		sd_settings->lut[bw_idx][i].r =
			args->lut[i] & 0xff;
		sd_settings->lut[bw_idx][i].g =
			(args->lut[i] >> 8) & 0xff;
		sd_settings->lut[bw_idx][i].b =
			(args->lut[i] >> 16) & 0xff;
	}

#if defined(CONFIG_TEGRA_NVSD)
	nvsd_init(dc, sd_settings);
#endif
#if defined(CONFIG_ARCH_TEGRA_12x_SOC)
	tegra_dc_io_start(dc);
	val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);
	val &= ~SD_KINIT_BIAS(0);
	val &= ~SD_CORRECTION_MODE_MAN;
	tegra_dc_writel(dc, val | SD_KINIT_BIAS(args->k_init_bias),
		DC_DISP_SD_CONTROL);
	tegra_dc_io_end(dc);
#endif

	if (dc->enabled) {
		mutex_lock(&dc->lock);
		tegra_dc_get(dc);
		tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
		tegra_dc_put(dc);
		mutex_unlock(&dc->lock);
	}

	LOG_EXT();
	return 0;
}