int
nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
	       int *N, int *fN, int *M, int *P)
{
	fixed20_12 fb_div, a, b;

	*P = pll->vco1.maxfreq / clk;
	if (*P > pll->max_p)
		*P = pll->max_p;
	if (*P < pll->min_p)
		*P = pll->min_p;

	/* *M = ceil(refclk / pll->vco.max_inputfreq); */
	a.full = dfixed_const(pll->refclk);
	b.full = dfixed_const(pll->vco1.max_inputfreq);
	a.full = dfixed_div(a, b);
	a.full = dfixed_ceil(a);
	*M = dfixed_trunc(a);

	/* fb_div = (vco * *M) / refclk; */
	fb_div.full = dfixed_const(clk * *P);
	fb_div.full = dfixed_mul(fb_div, a);
	a.full = dfixed_const(pll->refclk);
	fb_div.full = dfixed_div(fb_div, a);

	/* *N = floor(fb_div); */
	a.full = dfixed_floor(fb_div);
	*N = dfixed_trunc(fb_div);

	/* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
	b.full = dfixed_const(8192);
	a.full = dfixed_mul(a, b);
	fb_div.full = dfixed_mul(fb_div, b);
	fb_div.full = fb_div.full - a.full;
	*fN = dfixed_trunc(fb_div) - 4096;
	*fN &= 0xffff;

	return clk;
}
Пример #2
0
/* Estimate the pixel gain of PRISM enhancement and soft-clipping algorithm*/
static u32 nvsd_softclip(fixed20_12 pixel, fixed20_12 k, fixed20_12 th)
{
	fixed20_12 num, f;

	if (pixel.full >= th.full) {
		num.full = pixel.full - th.full;
		f.full = dfixed_const(1) - dfixed_div(num, th);
	} else {
		f.full = dfixed_const(1);
	}

	num.full = dfixed_mul(pixel, f);
	f.full = dfixed_mul(num, k);
	num.full = pixel.full + f.full;

	return min_t(u32, num.full, dfixed_const(255));
}
Пример #3
0
static inline u32 compute_dda_inc(fixed20_12 in, unsigned out_int,
				  bool v, unsigned Bpp)
{
	/*
	 * min(round((prescaled_size_in_pixels - 1) * 0x1000 /
	 *	     (post_scaled_size_in_pixels - 1)), MAX)
	 * Where the value of MAX is as follows:
	 * For V_DDA_INCREMENT: 15.0 (0xF000)
	 * For H_DDA_INCREMENT:  4.0 (0x4000) for 4 Bytes/pix formats.
	 *			 8.0 (0x8000) for 2 Bytes/pix formats.
	 */

	fixed20_12 out = dfixed_init(out_int);
	u32 dda_inc;
	int max;

	if (v) {
		max = 15;
	} else {
		switch (Bpp) {
		default:
			WARN_ON_ONCE(1);
			/* fallthrough */
		case 4:
			max = 4;
			break;
		case 2:
			max = 8;
			break;
		}
	}

	out.full = max_t(u32, out.full - dfixed_const(1), dfixed_const(1));
	in.full -= dfixed_const(1);

	dda_inc = dfixed_div(in, out);

	dda_inc = min_t(u32, dda_inc, dfixed_const(max));

	return dda_inc;
}
Пример #4
0
static int nvsd_set_brightness(struct tegra_dc *dc)
{
	u32 bin_width;
	int i, j;
	int val;
	int pix;
	int bin_idx;

	int incr;
	int base;

	u32 histo[32];
	u32 histo_total = 0;		/* count of pixels */
	fixed20_12 nonhisto_gain;	/* gain of pixels not in histogram */
	fixed20_12 est_achieved_gain;	/* final gain of pixels */
	fixed20_12 histo_gain = dfixed_init(0);	/* gain of pixels */
	fixed20_12 k, threshold;	/* k is the fractional part of HW_K */
	fixed20_12 den, num, out;
	fixed20_12 pix_avg, pix_avg_softclip;

	/* Collet the inputs of the algorithm */
	for (i = 0; i < DC_DISP_SD_HISTOGRAM_NUM; i++) {
		val = tegra_dc_readl(dc, DC_DISP_SD_HISTOGRAM(i));
		for (j = 0; j < 4; j++)
			histo[i * 4 + j] = SD_HISTOGRAM_BIN(val, (j * 8));
	}

	val = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES);
	k.full = dfixed_const(SD_HW_K_R(val));
	den.full = dfixed_const(1024);
	k.full = dfixed_div(k, den);

	val = tegra_dc_readl(dc, DC_DISP_SD_SOFT_CLIPPING);
	threshold.full = dfixed_const(SD_SOFT_CLIPPING_THRESHOLD(val));

	val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);
	bin_width = SD_BIN_WIDTH_VAL(val);
	incr = 1 << bin_width;
	base = 256 - 32 * incr;

	for (pix = base, bin_idx = 0; pix < 256; pix += incr, bin_idx++) {
		num.full = dfixed_const(pix + pix + incr);
		den.full = dfixed_const(2);
		pix_avg.full = dfixed_div(num, den);
		pix_avg_softclip.full = nvsd_softclip(pix_avg, k, threshold);

		num.full = dfixed_const(histo[bin_idx]);
		den.full = dfixed_const(256);
		out.full = dfixed_div(num, den);
		num.full = dfixed_mul(out, pix_avg_softclip);
		out.full = dfixed_div(num, pix_avg);
		histo_gain.full += out.full;
		histo_total += histo[bin_idx];
	}

	out.full = dfixed_const(256 - histo_total);
	den.full = dfixed_const(1) + k.full;
	num.full = dfixed_mul(out, den);
	den.full = dfixed_const(256);
	nonhisto_gain.full = dfixed_div(num, den);

	den.full = nonhisto_gain.full + histo_gain.full;
	num.full = dfixed_const(1);
	out.full = dfixed_div(num, den);
	num.full = dfixed_const(255);
	est_achieved_gain.full = dfixed_mul(num, out);
	val = dfixed_trunc(est_achieved_gain);

	return nvsd_backlght_interplate(val, 128);
}
Пример #5
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);
}