194b49d53SJani Nikula // SPDX-License-Identifier: MIT
294b49d53SJani Nikula /*
394b49d53SJani Nikula  * Copyright © 2023 Intel Corporation
494b49d53SJani Nikula  */
594b49d53SJani Nikula 
694b49d53SJani Nikula #include "i915_drv.h"
7*476f62b8SJani Nikula #include "i915_reg.h"
894b49d53SJani Nikula #include "i9xx_wm.h"
93dadb4a1SJani Nikula #include "intel_atomic.h"
1094b49d53SJani Nikula #include "intel_display.h"
1194b49d53SJani Nikula #include "intel_display_trace.h"
1294b49d53SJani Nikula #include "intel_mchbar_regs.h"
1394b49d53SJani Nikula #include "intel_wm.h"
1494b49d53SJani Nikula #include "skl_watermark.h"
1594b49d53SJani Nikula #include "vlv_sideband.h"
1694b49d53SJani Nikula 
1794b49d53SJani Nikula /* used in computing the new watermarks state */
1894b49d53SJani Nikula struct intel_wm_config {
1994b49d53SJani Nikula 	unsigned int num_pipes_active;
2094b49d53SJani Nikula 	bool sprites_enabled;
2194b49d53SJani Nikula 	bool sprites_scaled;
2294b49d53SJani Nikula };
2394b49d53SJani Nikula 
2494b49d53SJani Nikula struct cxsr_latency {
2594b49d53SJani Nikula 	bool is_desktop : 1;
2694b49d53SJani Nikula 	bool is_ddr3 : 1;
2794b49d53SJani Nikula 	u16 fsb_freq;
2894b49d53SJani Nikula 	u16 mem_freq;
2994b49d53SJani Nikula 	u16 display_sr;
3094b49d53SJani Nikula 	u16 display_hpll_disable;
3194b49d53SJani Nikula 	u16 cursor_sr;
3294b49d53SJani Nikula 	u16 cursor_hpll_disable;
3394b49d53SJani Nikula };
3494b49d53SJani Nikula 
3594b49d53SJani Nikula static const struct cxsr_latency cxsr_latency_table[] = {
3694b49d53SJani Nikula 	{1, 0, 800, 400, 3382, 33382, 3983, 33983},    /* DDR2-400 SC */
3794b49d53SJani Nikula 	{1, 0, 800, 667, 3354, 33354, 3807, 33807},    /* DDR2-667 SC */
3894b49d53SJani Nikula 	{1, 0, 800, 800, 3347, 33347, 3763, 33763},    /* DDR2-800 SC */
3994b49d53SJani Nikula 	{1, 1, 800, 667, 6420, 36420, 6873, 36873},    /* DDR3-667 SC */
4094b49d53SJani Nikula 	{1, 1, 800, 800, 5902, 35902, 6318, 36318},    /* DDR3-800 SC */
4194b49d53SJani Nikula 
4294b49d53SJani Nikula 	{1, 0, 667, 400, 3400, 33400, 4021, 34021},    /* DDR2-400 SC */
4394b49d53SJani Nikula 	{1, 0, 667, 667, 3372, 33372, 3845, 33845},    /* DDR2-667 SC */
4494b49d53SJani Nikula 	{1, 0, 667, 800, 3386, 33386, 3822, 33822},    /* DDR2-800 SC */
4594b49d53SJani Nikula 	{1, 1, 667, 667, 6438, 36438, 6911, 36911},    /* DDR3-667 SC */
4694b49d53SJani Nikula 	{1, 1, 667, 800, 5941, 35941, 6377, 36377},    /* DDR3-800 SC */
4794b49d53SJani Nikula 
4894b49d53SJani Nikula 	{1, 0, 400, 400, 3472, 33472, 4173, 34173},    /* DDR2-400 SC */
4994b49d53SJani Nikula 	{1, 0, 400, 667, 3443, 33443, 3996, 33996},    /* DDR2-667 SC */
5094b49d53SJani Nikula 	{1, 0, 400, 800, 3430, 33430, 3946, 33946},    /* DDR2-800 SC */
5194b49d53SJani Nikula 	{1, 1, 400, 667, 6509, 36509, 7062, 37062},    /* DDR3-667 SC */
5294b49d53SJani Nikula 	{1, 1, 400, 800, 5985, 35985, 6501, 36501},    /* DDR3-800 SC */
5394b49d53SJani Nikula 
5494b49d53SJani Nikula 	{0, 0, 800, 400, 3438, 33438, 4065, 34065},    /* DDR2-400 SC */
5594b49d53SJani Nikula 	{0, 0, 800, 667, 3410, 33410, 3889, 33889},    /* DDR2-667 SC */
5694b49d53SJani Nikula 	{0, 0, 800, 800, 3403, 33403, 3845, 33845},    /* DDR2-800 SC */
5794b49d53SJani Nikula 	{0, 1, 800, 667, 6476, 36476, 6955, 36955},    /* DDR3-667 SC */
5894b49d53SJani Nikula 	{0, 1, 800, 800, 5958, 35958, 6400, 36400},    /* DDR3-800 SC */
5994b49d53SJani Nikula 
6094b49d53SJani Nikula 	{0, 0, 667, 400, 3456, 33456, 4103, 34106},    /* DDR2-400 SC */
6194b49d53SJani Nikula 	{0, 0, 667, 667, 3428, 33428, 3927, 33927},    /* DDR2-667 SC */
6294b49d53SJani Nikula 	{0, 0, 667, 800, 3443, 33443, 3905, 33905},    /* DDR2-800 SC */
6394b49d53SJani Nikula 	{0, 1, 667, 667, 6494, 36494, 6993, 36993},    /* DDR3-667 SC */
6494b49d53SJani Nikula 	{0, 1, 667, 800, 5998, 35998, 6460, 36460},    /* DDR3-800 SC */
6594b49d53SJani Nikula 
6694b49d53SJani Nikula 	{0, 0, 400, 400, 3528, 33528, 4255, 34255},    /* DDR2-400 SC */
6794b49d53SJani Nikula 	{0, 0, 400, 667, 3500, 33500, 4079, 34079},    /* DDR2-667 SC */
6894b49d53SJani Nikula 	{0, 0, 400, 800, 3487, 33487, 4029, 34029},    /* DDR2-800 SC */
6994b49d53SJani Nikula 	{0, 1, 400, 667, 6566, 36566, 7145, 37145},    /* DDR3-667 SC */
7094b49d53SJani Nikula 	{0, 1, 400, 800, 6042, 36042, 6584, 36584},    /* DDR3-800 SC */
7194b49d53SJani Nikula };
7294b49d53SJani Nikula 
intel_get_cxsr_latency(bool is_desktop,bool is_ddr3,int fsb,int mem)7394b49d53SJani Nikula static const struct cxsr_latency *intel_get_cxsr_latency(bool is_desktop,
7494b49d53SJani Nikula 							 bool is_ddr3,
7594b49d53SJani Nikula 							 int fsb,
7694b49d53SJani Nikula 							 int mem)
7794b49d53SJani Nikula {
7894b49d53SJani Nikula 	const struct cxsr_latency *latency;
7994b49d53SJani Nikula 	int i;
8094b49d53SJani Nikula 
8194b49d53SJani Nikula 	if (fsb == 0 || mem == 0)
8294b49d53SJani Nikula 		return NULL;
8394b49d53SJani Nikula 
8494b49d53SJani Nikula 	for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
8594b49d53SJani Nikula 		latency = &cxsr_latency_table[i];
8694b49d53SJani Nikula 		if (is_desktop == latency->is_desktop &&
8794b49d53SJani Nikula 		    is_ddr3 == latency->is_ddr3 &&
8894b49d53SJani Nikula 		    fsb == latency->fsb_freq && mem == latency->mem_freq)
8994b49d53SJani Nikula 			return latency;
9094b49d53SJani Nikula 	}
9194b49d53SJani Nikula 
9294b49d53SJani Nikula 	DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
9394b49d53SJani Nikula 
9494b49d53SJani Nikula 	return NULL;
9594b49d53SJani Nikula }
9694b49d53SJani Nikula 
chv_set_memory_dvfs(struct drm_i915_private * dev_priv,bool enable)9794b49d53SJani Nikula static void chv_set_memory_dvfs(struct drm_i915_private *dev_priv, bool enable)
9894b49d53SJani Nikula {
9994b49d53SJani Nikula 	u32 val;
10094b49d53SJani Nikula 
10194b49d53SJani Nikula 	vlv_punit_get(dev_priv);
10294b49d53SJani Nikula 
10394b49d53SJani Nikula 	val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
10494b49d53SJani Nikula 	if (enable)
10594b49d53SJani Nikula 		val &= ~FORCE_DDR_HIGH_FREQ;
10694b49d53SJani Nikula 	else
10794b49d53SJani Nikula 		val |= FORCE_DDR_HIGH_FREQ;
10894b49d53SJani Nikula 	val &= ~FORCE_DDR_LOW_FREQ;
10994b49d53SJani Nikula 	val |= FORCE_DDR_FREQ_REQ_ACK;
11094b49d53SJani Nikula 	vlv_punit_write(dev_priv, PUNIT_REG_DDR_SETUP2, val);
11194b49d53SJani Nikula 
11294b49d53SJani Nikula 	if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2) &
11394b49d53SJani Nikula 		      FORCE_DDR_FREQ_REQ_ACK) == 0, 3))
11494b49d53SJani Nikula 		drm_err(&dev_priv->drm,
11594b49d53SJani Nikula 			"timed out waiting for Punit DDR DVFS request\n");
11694b49d53SJani Nikula 
11794b49d53SJani Nikula 	vlv_punit_put(dev_priv);
11894b49d53SJani Nikula }
11994b49d53SJani Nikula 
chv_set_memory_pm5(struct drm_i915_private * dev_priv,bool enable)12094b49d53SJani Nikula static void chv_set_memory_pm5(struct drm_i915_private *dev_priv, bool enable)
12194b49d53SJani Nikula {
12294b49d53SJani Nikula 	u32 val;
12394b49d53SJani Nikula 
12494b49d53SJani Nikula 	vlv_punit_get(dev_priv);
12594b49d53SJani Nikula 
12694b49d53SJani Nikula 	val = vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM);
12794b49d53SJani Nikula 	if (enable)
12894b49d53SJani Nikula 		val |= DSP_MAXFIFO_PM5_ENABLE;
12994b49d53SJani Nikula 	else
13094b49d53SJani Nikula 		val &= ~DSP_MAXFIFO_PM5_ENABLE;
13194b49d53SJani Nikula 	vlv_punit_write(dev_priv, PUNIT_REG_DSPSSPM, val);
13294b49d53SJani Nikula 
13394b49d53SJani Nikula 	vlv_punit_put(dev_priv);
13494b49d53SJani Nikula }
13594b49d53SJani Nikula 
13694b49d53SJani Nikula #define FW_WM(value, plane) \
13794b49d53SJani Nikula 	(((value) << DSPFW_ ## plane ## _SHIFT) & DSPFW_ ## plane ## _MASK)
13894b49d53SJani Nikula 
_intel_set_memory_cxsr(struct drm_i915_private * dev_priv,bool enable)13994b49d53SJani Nikula static bool _intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
14094b49d53SJani Nikula {
14194b49d53SJani Nikula 	bool was_enabled;
14294b49d53SJani Nikula 	u32 val;
14394b49d53SJani Nikula 
14494b49d53SJani Nikula 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
14594b49d53SJani Nikula 		was_enabled = intel_uncore_read(&dev_priv->uncore, FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
14694b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0);
14794b49d53SJani Nikula 		intel_uncore_posting_read(&dev_priv->uncore, FW_BLC_SELF_VLV);
14894b49d53SJani Nikula 	} else if (IS_G4X(dev_priv) || IS_I965GM(dev_priv)) {
14994b49d53SJani Nikula 		was_enabled = intel_uncore_read(&dev_priv->uncore, FW_BLC_SELF) & FW_BLC_SELF_EN;
15094b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0);
15194b49d53SJani Nikula 		intel_uncore_posting_read(&dev_priv->uncore, FW_BLC_SELF);
15294b49d53SJani Nikula 	} else if (IS_PINEVIEW(dev_priv)) {
15394b49d53SJani Nikula 		val = intel_uncore_read(&dev_priv->uncore, DSPFW3);
15494b49d53SJani Nikula 		was_enabled = val & PINEVIEW_SELF_REFRESH_EN;
15594b49d53SJani Nikula 		if (enable)
15694b49d53SJani Nikula 			val |= PINEVIEW_SELF_REFRESH_EN;
15794b49d53SJani Nikula 		else
15894b49d53SJani Nikula 			val &= ~PINEVIEW_SELF_REFRESH_EN;
15994b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPFW3, val);
16094b49d53SJani Nikula 		intel_uncore_posting_read(&dev_priv->uncore, DSPFW3);
16194b49d53SJani Nikula 	} else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv)) {
16294b49d53SJani Nikula 		was_enabled = intel_uncore_read(&dev_priv->uncore, FW_BLC_SELF) & FW_BLC_SELF_EN;
16394b49d53SJani Nikula 		val = enable ? _MASKED_BIT_ENABLE(FW_BLC_SELF_EN) :
16494b49d53SJani Nikula 			       _MASKED_BIT_DISABLE(FW_BLC_SELF_EN);
16594b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, FW_BLC_SELF, val);
16694b49d53SJani Nikula 		intel_uncore_posting_read(&dev_priv->uncore, FW_BLC_SELF);
16794b49d53SJani Nikula 	} else if (IS_I915GM(dev_priv)) {
16894b49d53SJani Nikula 		/*
16994b49d53SJani Nikula 		 * FIXME can't find a bit like this for 915G, and
17094b49d53SJani Nikula 		 * yet it does have the related watermark in
17194b49d53SJani Nikula 		 * FW_BLC_SELF. What's going on?
17294b49d53SJani Nikula 		 */
17394b49d53SJani Nikula 		was_enabled = intel_uncore_read(&dev_priv->uncore, INSTPM) & INSTPM_SELF_EN;
17494b49d53SJani Nikula 		val = enable ? _MASKED_BIT_ENABLE(INSTPM_SELF_EN) :
17594b49d53SJani Nikula 			       _MASKED_BIT_DISABLE(INSTPM_SELF_EN);
17694b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, INSTPM, val);
17794b49d53SJani Nikula 		intel_uncore_posting_read(&dev_priv->uncore, INSTPM);
17894b49d53SJani Nikula 	} else {
17994b49d53SJani Nikula 		return false;
18094b49d53SJani Nikula 	}
18194b49d53SJani Nikula 
18294b49d53SJani Nikula 	trace_intel_memory_cxsr(dev_priv, was_enabled, enable);
18394b49d53SJani Nikula 
18494b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm, "memory self-refresh is %s (was %s)\n",
18594b49d53SJani Nikula 		    str_enabled_disabled(enable),
18694b49d53SJani Nikula 		    str_enabled_disabled(was_enabled));
18794b49d53SJani Nikula 
18894b49d53SJani Nikula 	return was_enabled;
18994b49d53SJani Nikula }
19094b49d53SJani Nikula 
19194b49d53SJani Nikula /**
19294b49d53SJani Nikula  * intel_set_memory_cxsr - Configure CxSR state
19394b49d53SJani Nikula  * @dev_priv: i915 device
19494b49d53SJani Nikula  * @enable: Allow vs. disallow CxSR
19594b49d53SJani Nikula  *
19694b49d53SJani Nikula  * Allow or disallow the system to enter a special CxSR
19794b49d53SJani Nikula  * (C-state self refresh) state. What typically happens in CxSR mode
19894b49d53SJani Nikula  * is that several display FIFOs may get combined into a single larger
19994b49d53SJani Nikula  * FIFO for a particular plane (so called max FIFO mode) to allow the
20094b49d53SJani Nikula  * system to defer memory fetches longer, and the memory will enter
20194b49d53SJani Nikula  * self refresh.
20294b49d53SJani Nikula  *
20394b49d53SJani Nikula  * Note that enabling CxSR does not guarantee that the system enter
20494b49d53SJani Nikula  * this special mode, nor does it guarantee that the system stays
20594b49d53SJani Nikula  * in that mode once entered. So this just allows/disallows the system
20694b49d53SJani Nikula  * to autonomously utilize the CxSR mode. Other factors such as core
20794b49d53SJani Nikula  * C-states will affect when/if the system actually enters/exits the
20894b49d53SJani Nikula  * CxSR mode.
20994b49d53SJani Nikula  *
21094b49d53SJani Nikula  * Note that on VLV/CHV this actually only controls the max FIFO mode,
21194b49d53SJani Nikula  * and the system is free to enter/exit memory self refresh at any time
21294b49d53SJani Nikula  * even when the use of CxSR has been disallowed.
21394b49d53SJani Nikula  *
21494b49d53SJani Nikula  * While the system is actually in the CxSR/max FIFO mode, some plane
21594b49d53SJani Nikula  * control registers will not get latched on vblank. Thus in order to
21694b49d53SJani Nikula  * guarantee the system will respond to changes in the plane registers
21794b49d53SJani Nikula  * we must always disallow CxSR prior to making changes to those registers.
21894b49d53SJani Nikula  * Unfortunately the system will re-evaluate the CxSR conditions at
21994b49d53SJani Nikula  * frame start which happens after vblank start (which is when the plane
22094b49d53SJani Nikula  * registers would get latched), so we can't proceed with the plane update
22194b49d53SJani Nikula  * during the same frame where we disallowed CxSR.
22294b49d53SJani Nikula  *
22394b49d53SJani Nikula  * Certain platforms also have a deeper HPLL SR mode. Fortunately the
22494b49d53SJani Nikula  * HPLL SR mode depends on CxSR itself, so we don't have to hand hold
22594b49d53SJani Nikula  * the hardware w.r.t. HPLL SR when writing to plane registers.
22694b49d53SJani Nikula  * Disallowing just CxSR is sufficient.
22794b49d53SJani Nikula  */
intel_set_memory_cxsr(struct drm_i915_private * dev_priv,bool enable)22894b49d53SJani Nikula bool intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
22994b49d53SJani Nikula {
23094b49d53SJani Nikula 	bool ret;
23194b49d53SJani Nikula 
23294b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
23394b49d53SJani Nikula 	ret = _intel_set_memory_cxsr(dev_priv, enable);
23494b49d53SJani Nikula 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
23594b49d53SJani Nikula 		dev_priv->display.wm.vlv.cxsr = enable;
23694b49d53SJani Nikula 	else if (IS_G4X(dev_priv))
23794b49d53SJani Nikula 		dev_priv->display.wm.g4x.cxsr = enable;
23894b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
23994b49d53SJani Nikula 
24094b49d53SJani Nikula 	return ret;
24194b49d53SJani Nikula }
24294b49d53SJani Nikula 
24394b49d53SJani Nikula /*
24494b49d53SJani Nikula  * Latency for FIFO fetches is dependent on several factors:
24594b49d53SJani Nikula  *   - memory configuration (speed, channels)
24694b49d53SJani Nikula  *   - chipset
24794b49d53SJani Nikula  *   - current MCH state
24894b49d53SJani Nikula  * It can be fairly high in some situations, so here we assume a fairly
24994b49d53SJani Nikula  * pessimal value.  It's a tradeoff between extra memory fetches (if we
25094b49d53SJani Nikula  * set this value too high, the FIFO will fetch frequently to stay full)
25194b49d53SJani Nikula  * and power consumption (set it too low to save power and we might see
25294b49d53SJani Nikula  * FIFO underruns and display "flicker").
25394b49d53SJani Nikula  *
25494b49d53SJani Nikula  * A value of 5us seems to be a good balance; safe for very low end
25594b49d53SJani Nikula  * platforms but not overly aggressive on lower latency configs.
25694b49d53SJani Nikula  */
25794b49d53SJani Nikula static const int pessimal_latency_ns = 5000;
25894b49d53SJani Nikula 
25994b49d53SJani Nikula #define VLV_FIFO_START(dsparb, dsparb2, lo_shift, hi_shift) \
26094b49d53SJani Nikula 	((((dsparb) >> (lo_shift)) & 0xff) | ((((dsparb2) >> (hi_shift)) & 0x1) << 8))
26194b49d53SJani Nikula 
vlv_get_fifo_size(struct intel_crtc_state * crtc_state)26294b49d53SJani Nikula static void vlv_get_fifo_size(struct intel_crtc_state *crtc_state)
26394b49d53SJani Nikula {
26494b49d53SJani Nikula 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
26594b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
26694b49d53SJani Nikula 	struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state;
26794b49d53SJani Nikula 	enum pipe pipe = crtc->pipe;
26894b49d53SJani Nikula 	int sprite0_start, sprite1_start;
26994b49d53SJani Nikula 	u32 dsparb, dsparb2, dsparb3;
27094b49d53SJani Nikula 
27194b49d53SJani Nikula 	switch (pipe) {
27294b49d53SJani Nikula 	case PIPE_A:
27394b49d53SJani Nikula 		dsparb = intel_uncore_read(&dev_priv->uncore, DSPARB);
27494b49d53SJani Nikula 		dsparb2 = intel_uncore_read(&dev_priv->uncore, DSPARB2);
27594b49d53SJani Nikula 		sprite0_start = VLV_FIFO_START(dsparb, dsparb2, 0, 0);
27694b49d53SJani Nikula 		sprite1_start = VLV_FIFO_START(dsparb, dsparb2, 8, 4);
27794b49d53SJani Nikula 		break;
27894b49d53SJani Nikula 	case PIPE_B:
27994b49d53SJani Nikula 		dsparb = intel_uncore_read(&dev_priv->uncore, DSPARB);
28094b49d53SJani Nikula 		dsparb2 = intel_uncore_read(&dev_priv->uncore, DSPARB2);
28194b49d53SJani Nikula 		sprite0_start = VLV_FIFO_START(dsparb, dsparb2, 16, 8);
28294b49d53SJani Nikula 		sprite1_start = VLV_FIFO_START(dsparb, dsparb2, 24, 12);
28394b49d53SJani Nikula 		break;
28494b49d53SJani Nikula 	case PIPE_C:
28594b49d53SJani Nikula 		dsparb2 = intel_uncore_read(&dev_priv->uncore, DSPARB2);
28694b49d53SJani Nikula 		dsparb3 = intel_uncore_read(&dev_priv->uncore, DSPARB3);
28794b49d53SJani Nikula 		sprite0_start = VLV_FIFO_START(dsparb3, dsparb2, 0, 16);
28894b49d53SJani Nikula 		sprite1_start = VLV_FIFO_START(dsparb3, dsparb2, 8, 20);
28994b49d53SJani Nikula 		break;
29094b49d53SJani Nikula 	default:
29194b49d53SJani Nikula 		MISSING_CASE(pipe);
29294b49d53SJani Nikula 		return;
29394b49d53SJani Nikula 	}
29494b49d53SJani Nikula 
29594b49d53SJani Nikula 	fifo_state->plane[PLANE_PRIMARY] = sprite0_start;
29694b49d53SJani Nikula 	fifo_state->plane[PLANE_SPRITE0] = sprite1_start - sprite0_start;
29794b49d53SJani Nikula 	fifo_state->plane[PLANE_SPRITE1] = 511 - sprite1_start;
29894b49d53SJani Nikula 	fifo_state->plane[PLANE_CURSOR] = 63;
29994b49d53SJani Nikula }
30094b49d53SJani Nikula 
i9xx_get_fifo_size(struct drm_i915_private * dev_priv,enum i9xx_plane_id i9xx_plane)30194b49d53SJani Nikula static int i9xx_get_fifo_size(struct drm_i915_private *dev_priv,
30294b49d53SJani Nikula 			      enum i9xx_plane_id i9xx_plane)
30394b49d53SJani Nikula {
30494b49d53SJani Nikula 	u32 dsparb = intel_uncore_read(&dev_priv->uncore, DSPARB);
30594b49d53SJani Nikula 	int size;
30694b49d53SJani Nikula 
30794b49d53SJani Nikula 	size = dsparb & 0x7f;
30894b49d53SJani Nikula 	if (i9xx_plane == PLANE_B)
30994b49d53SJani Nikula 		size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
31094b49d53SJani Nikula 
31194b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm, "FIFO size - (0x%08x) %c: %d\n",
31294b49d53SJani Nikula 		    dsparb, plane_name(i9xx_plane), size);
31394b49d53SJani Nikula 
31494b49d53SJani Nikula 	return size;
31594b49d53SJani Nikula }
31694b49d53SJani Nikula 
i830_get_fifo_size(struct drm_i915_private * dev_priv,enum i9xx_plane_id i9xx_plane)31794b49d53SJani Nikula static int i830_get_fifo_size(struct drm_i915_private *dev_priv,
31894b49d53SJani Nikula 			      enum i9xx_plane_id i9xx_plane)
31994b49d53SJani Nikula {
32094b49d53SJani Nikula 	u32 dsparb = intel_uncore_read(&dev_priv->uncore, DSPARB);
32194b49d53SJani Nikula 	int size;
32294b49d53SJani Nikula 
32394b49d53SJani Nikula 	size = dsparb & 0x1ff;
32494b49d53SJani Nikula 	if (i9xx_plane == PLANE_B)
32594b49d53SJani Nikula 		size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size;
32694b49d53SJani Nikula 	size >>= 1; /* Convert to cachelines */
32794b49d53SJani Nikula 
32894b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm, "FIFO size - (0x%08x) %c: %d\n",
32994b49d53SJani Nikula 		    dsparb, plane_name(i9xx_plane), size);
33094b49d53SJani Nikula 
33194b49d53SJani Nikula 	return size;
33294b49d53SJani Nikula }
33394b49d53SJani Nikula 
i845_get_fifo_size(struct drm_i915_private * dev_priv,enum i9xx_plane_id i9xx_plane)33494b49d53SJani Nikula static int i845_get_fifo_size(struct drm_i915_private *dev_priv,
33594b49d53SJani Nikula 			      enum i9xx_plane_id i9xx_plane)
33694b49d53SJani Nikula {
33794b49d53SJani Nikula 	u32 dsparb = intel_uncore_read(&dev_priv->uncore, DSPARB);
33894b49d53SJani Nikula 	int size;
33994b49d53SJani Nikula 
34094b49d53SJani Nikula 	size = dsparb & 0x7f;
34194b49d53SJani Nikula 	size >>= 2; /* Convert to cachelines */
34294b49d53SJani Nikula 
34394b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm, "FIFO size - (0x%08x) %c: %d\n",
34494b49d53SJani Nikula 		    dsparb, plane_name(i9xx_plane), size);
34594b49d53SJani Nikula 
34694b49d53SJani Nikula 	return size;
34794b49d53SJani Nikula }
34894b49d53SJani Nikula 
34994b49d53SJani Nikula /* Pineview has different values for various configs */
35094b49d53SJani Nikula static const struct intel_watermark_params pnv_display_wm = {
35194b49d53SJani Nikula 	.fifo_size = PINEVIEW_DISPLAY_FIFO,
35294b49d53SJani Nikula 	.max_wm = PINEVIEW_MAX_WM,
35394b49d53SJani Nikula 	.default_wm = PINEVIEW_DFT_WM,
35494b49d53SJani Nikula 	.guard_size = PINEVIEW_GUARD_WM,
35594b49d53SJani Nikula 	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
35694b49d53SJani Nikula };
35794b49d53SJani Nikula 
35894b49d53SJani Nikula static const struct intel_watermark_params pnv_display_hplloff_wm = {
35994b49d53SJani Nikula 	.fifo_size = PINEVIEW_DISPLAY_FIFO,
36094b49d53SJani Nikula 	.max_wm = PINEVIEW_MAX_WM,
36194b49d53SJani Nikula 	.default_wm = PINEVIEW_DFT_HPLLOFF_WM,
36294b49d53SJani Nikula 	.guard_size = PINEVIEW_GUARD_WM,
36394b49d53SJani Nikula 	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
36494b49d53SJani Nikula };
36594b49d53SJani Nikula 
36694b49d53SJani Nikula static const struct intel_watermark_params pnv_cursor_wm = {
36794b49d53SJani Nikula 	.fifo_size = PINEVIEW_CURSOR_FIFO,
36894b49d53SJani Nikula 	.max_wm = PINEVIEW_CURSOR_MAX_WM,
36994b49d53SJani Nikula 	.default_wm = PINEVIEW_CURSOR_DFT_WM,
37094b49d53SJani Nikula 	.guard_size = PINEVIEW_CURSOR_GUARD_WM,
37194b49d53SJani Nikula 	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
37294b49d53SJani Nikula };
37394b49d53SJani Nikula 
37494b49d53SJani Nikula static const struct intel_watermark_params pnv_cursor_hplloff_wm = {
37594b49d53SJani Nikula 	.fifo_size = PINEVIEW_CURSOR_FIFO,
37694b49d53SJani Nikula 	.max_wm = PINEVIEW_CURSOR_MAX_WM,
37794b49d53SJani Nikula 	.default_wm = PINEVIEW_CURSOR_DFT_WM,
37894b49d53SJani Nikula 	.guard_size = PINEVIEW_CURSOR_GUARD_WM,
37994b49d53SJani Nikula 	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
38094b49d53SJani Nikula };
38194b49d53SJani Nikula 
38294b49d53SJani Nikula static const struct intel_watermark_params i965_cursor_wm_info = {
38394b49d53SJani Nikula 	.fifo_size = I965_CURSOR_FIFO,
38494b49d53SJani Nikula 	.max_wm = I965_CURSOR_MAX_WM,
38594b49d53SJani Nikula 	.default_wm = I965_CURSOR_DFT_WM,
38694b49d53SJani Nikula 	.guard_size = 2,
38794b49d53SJani Nikula 	.cacheline_size = I915_FIFO_LINE_SIZE,
38894b49d53SJani Nikula };
38994b49d53SJani Nikula 
39094b49d53SJani Nikula static const struct intel_watermark_params i945_wm_info = {
39194b49d53SJani Nikula 	.fifo_size = I945_FIFO_SIZE,
39294b49d53SJani Nikula 	.max_wm = I915_MAX_WM,
39394b49d53SJani Nikula 	.default_wm = 1,
39494b49d53SJani Nikula 	.guard_size = 2,
39594b49d53SJani Nikula 	.cacheline_size = I915_FIFO_LINE_SIZE,
39694b49d53SJani Nikula };
39794b49d53SJani Nikula 
39894b49d53SJani Nikula static const struct intel_watermark_params i915_wm_info = {
39994b49d53SJani Nikula 	.fifo_size = I915_FIFO_SIZE,
40094b49d53SJani Nikula 	.max_wm = I915_MAX_WM,
40194b49d53SJani Nikula 	.default_wm = 1,
40294b49d53SJani Nikula 	.guard_size = 2,
40394b49d53SJani Nikula 	.cacheline_size = I915_FIFO_LINE_SIZE,
40494b49d53SJani Nikula };
40594b49d53SJani Nikula 
40694b49d53SJani Nikula static const struct intel_watermark_params i830_a_wm_info = {
40794b49d53SJani Nikula 	.fifo_size = I855GM_FIFO_SIZE,
40894b49d53SJani Nikula 	.max_wm = I915_MAX_WM,
40994b49d53SJani Nikula 	.default_wm = 1,
41094b49d53SJani Nikula 	.guard_size = 2,
41194b49d53SJani Nikula 	.cacheline_size = I830_FIFO_LINE_SIZE,
41294b49d53SJani Nikula };
41394b49d53SJani Nikula 
41494b49d53SJani Nikula static const struct intel_watermark_params i830_bc_wm_info = {
41594b49d53SJani Nikula 	.fifo_size = I855GM_FIFO_SIZE,
41694b49d53SJani Nikula 	.max_wm = I915_MAX_WM / 2,
41794b49d53SJani Nikula 	.default_wm = 1,
41894b49d53SJani Nikula 	.guard_size = 2,
41994b49d53SJani Nikula 	.cacheline_size = I830_FIFO_LINE_SIZE,
42094b49d53SJani Nikula };
42194b49d53SJani Nikula 
42294b49d53SJani Nikula static const struct intel_watermark_params i845_wm_info = {
42394b49d53SJani Nikula 	.fifo_size = I830_FIFO_SIZE,
42494b49d53SJani Nikula 	.max_wm = I915_MAX_WM,
42594b49d53SJani Nikula 	.default_wm = 1,
42694b49d53SJani Nikula 	.guard_size = 2,
42794b49d53SJani Nikula 	.cacheline_size = I830_FIFO_LINE_SIZE,
42894b49d53SJani Nikula };
42994b49d53SJani Nikula 
43094b49d53SJani Nikula /**
43194b49d53SJani Nikula  * intel_wm_method1 - Method 1 / "small buffer" watermark formula
43294b49d53SJani Nikula  * @pixel_rate: Pipe pixel rate in kHz
43394b49d53SJani Nikula  * @cpp: Plane bytes per pixel
43494b49d53SJani Nikula  * @latency: Memory wakeup latency in 0.1us units
43594b49d53SJani Nikula  *
43694b49d53SJani Nikula  * Compute the watermark using the method 1 or "small buffer"
43794b49d53SJani Nikula  * formula. The caller may additonally add extra cachelines
43894b49d53SJani Nikula  * to account for TLB misses and clock crossings.
43994b49d53SJani Nikula  *
44094b49d53SJani Nikula  * This method is concerned with the short term drain rate
44194b49d53SJani Nikula  * of the FIFO, ie. it does not account for blanking periods
44294b49d53SJani Nikula  * which would effectively reduce the average drain rate across
44394b49d53SJani Nikula  * a longer period. The name "small" refers to the fact the
44494b49d53SJani Nikula  * FIFO is relatively small compared to the amount of data
44594b49d53SJani Nikula  * fetched.
44694b49d53SJani Nikula  *
44794b49d53SJani Nikula  * The FIFO level vs. time graph might look something like:
44894b49d53SJani Nikula  *
44994b49d53SJani Nikula  *   |\   |\
45094b49d53SJani Nikula  *   | \  | \
45194b49d53SJani Nikula  * __---__---__ (- plane active, _ blanking)
45294b49d53SJani Nikula  * -> time
45394b49d53SJani Nikula  *
45494b49d53SJani Nikula  * or perhaps like this:
45594b49d53SJani Nikula  *
45694b49d53SJani Nikula  *   |\|\  |\|\
45794b49d53SJani Nikula  * __----__----__ (- plane active, _ blanking)
45894b49d53SJani Nikula  * -> time
45994b49d53SJani Nikula  *
46094b49d53SJani Nikula  * Returns:
46194b49d53SJani Nikula  * The watermark in bytes
46294b49d53SJani Nikula  */
intel_wm_method1(unsigned int pixel_rate,unsigned int cpp,unsigned int latency)46394b49d53SJani Nikula static unsigned int intel_wm_method1(unsigned int pixel_rate,
46494b49d53SJani Nikula 				     unsigned int cpp,
46594b49d53SJani Nikula 				     unsigned int latency)
46694b49d53SJani Nikula {
46794b49d53SJani Nikula 	u64 ret;
46894b49d53SJani Nikula 
46994b49d53SJani Nikula 	ret = mul_u32_u32(pixel_rate, cpp * latency);
47094b49d53SJani Nikula 	ret = DIV_ROUND_UP_ULL(ret, 10000);
47194b49d53SJani Nikula 
47294b49d53SJani Nikula 	return ret;
47394b49d53SJani Nikula }
47494b49d53SJani Nikula 
47594b49d53SJani Nikula /**
47694b49d53SJani Nikula  * intel_wm_method2 - Method 2 / "large buffer" watermark formula
47794b49d53SJani Nikula  * @pixel_rate: Pipe pixel rate in kHz
47894b49d53SJani Nikula  * @htotal: Pipe horizontal total
47994b49d53SJani Nikula  * @width: Plane width in pixels
48094b49d53SJani Nikula  * @cpp: Plane bytes per pixel
48194b49d53SJani Nikula  * @latency: Memory wakeup latency in 0.1us units
48294b49d53SJani Nikula  *
48394b49d53SJani Nikula  * Compute the watermark using the method 2 or "large buffer"
48494b49d53SJani Nikula  * formula. The caller may additonally add extra cachelines
48594b49d53SJani Nikula  * to account for TLB misses and clock crossings.
48694b49d53SJani Nikula  *
48794b49d53SJani Nikula  * This method is concerned with the long term drain rate
48894b49d53SJani Nikula  * of the FIFO, ie. it does account for blanking periods
48994b49d53SJani Nikula  * which effectively reduce the average drain rate across
49094b49d53SJani Nikula  * a longer period. The name "large" refers to the fact the
49194b49d53SJani Nikula  * FIFO is relatively large compared to the amount of data
49294b49d53SJani Nikula  * fetched.
49394b49d53SJani Nikula  *
49494b49d53SJani Nikula  * The FIFO level vs. time graph might look something like:
49594b49d53SJani Nikula  *
49694b49d53SJani Nikula  *    |\___       |\___
49794b49d53SJani Nikula  *    |    \___   |    \___
49894b49d53SJani Nikula  *    |        \  |        \
49994b49d53SJani Nikula  * __ --__--__--__--__--__--__ (- plane active, _ blanking)
50094b49d53SJani Nikula  * -> time
50194b49d53SJani Nikula  *
50294b49d53SJani Nikula  * Returns:
50394b49d53SJani Nikula  * The watermark in bytes
50494b49d53SJani Nikula  */
intel_wm_method2(unsigned int pixel_rate,unsigned int htotal,unsigned int width,unsigned int cpp,unsigned int latency)50594b49d53SJani Nikula static unsigned int intel_wm_method2(unsigned int pixel_rate,
50694b49d53SJani Nikula 				     unsigned int htotal,
50794b49d53SJani Nikula 				     unsigned int width,
50894b49d53SJani Nikula 				     unsigned int cpp,
50994b49d53SJani Nikula 				     unsigned int latency)
51094b49d53SJani Nikula {
51194b49d53SJani Nikula 	unsigned int ret;
51294b49d53SJani Nikula 
51394b49d53SJani Nikula 	/*
51494b49d53SJani Nikula 	 * FIXME remove once all users are computing
51594b49d53SJani Nikula 	 * watermarks in the correct place.
51694b49d53SJani Nikula 	 */
51794b49d53SJani Nikula 	if (WARN_ON_ONCE(htotal == 0))
51894b49d53SJani Nikula 		htotal = 1;
51994b49d53SJani Nikula 
52094b49d53SJani Nikula 	ret = (latency * pixel_rate) / (htotal * 10000);
52194b49d53SJani Nikula 	ret = (ret + 1) * width * cpp;
52294b49d53SJani Nikula 
52394b49d53SJani Nikula 	return ret;
52494b49d53SJani Nikula }
52594b49d53SJani Nikula 
52694b49d53SJani Nikula /**
52794b49d53SJani Nikula  * intel_calculate_wm - calculate watermark level
52894b49d53SJani Nikula  * @pixel_rate: pixel clock
52994b49d53SJani Nikula  * @wm: chip FIFO params
53094b49d53SJani Nikula  * @fifo_size: size of the FIFO buffer
53194b49d53SJani Nikula  * @cpp: bytes per pixel
53294b49d53SJani Nikula  * @latency_ns: memory latency for the platform
53394b49d53SJani Nikula  *
53494b49d53SJani Nikula  * Calculate the watermark level (the level at which the display plane will
53594b49d53SJani Nikula  * start fetching from memory again).  Each chip has a different display
53694b49d53SJani Nikula  * FIFO size and allocation, so the caller needs to figure that out and pass
53794b49d53SJani Nikula  * in the correct intel_watermark_params structure.
53894b49d53SJani Nikula  *
53994b49d53SJani Nikula  * As the pixel clock runs, the FIFO will be drained at a rate that depends
54094b49d53SJani Nikula  * on the pixel size.  When it reaches the watermark level, it'll start
54194b49d53SJani Nikula  * fetching FIFO line sized based chunks from memory until the FIFO fills
54294b49d53SJani Nikula  * past the watermark point.  If the FIFO drains completely, a FIFO underrun
54394b49d53SJani Nikula  * will occur, and a display engine hang could result.
54494b49d53SJani Nikula  */
intel_calculate_wm(int pixel_rate,const struct intel_watermark_params * wm,int fifo_size,int cpp,unsigned int latency_ns)54594b49d53SJani Nikula static unsigned int intel_calculate_wm(int pixel_rate,
54694b49d53SJani Nikula 				       const struct intel_watermark_params *wm,
54794b49d53SJani Nikula 				       int fifo_size, int cpp,
54894b49d53SJani Nikula 				       unsigned int latency_ns)
54994b49d53SJani Nikula {
55094b49d53SJani Nikula 	int entries, wm_size;
55194b49d53SJani Nikula 
55294b49d53SJani Nikula 	/*
55394b49d53SJani Nikula 	 * Note: we need to make sure we don't overflow for various clock &
55494b49d53SJani Nikula 	 * latency values.
55594b49d53SJani Nikula 	 * clocks go from a few thousand to several hundred thousand.
55694b49d53SJani Nikula 	 * latency is usually a few thousand
55794b49d53SJani Nikula 	 */
55894b49d53SJani Nikula 	entries = intel_wm_method1(pixel_rate, cpp,
55994b49d53SJani Nikula 				   latency_ns / 100);
56094b49d53SJani Nikula 	entries = DIV_ROUND_UP(entries, wm->cacheline_size) +
56194b49d53SJani Nikula 		wm->guard_size;
56294b49d53SJani Nikula 	DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries);
56394b49d53SJani Nikula 
56494b49d53SJani Nikula 	wm_size = fifo_size - entries;
56594b49d53SJani Nikula 	DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
56694b49d53SJani Nikula 
56794b49d53SJani Nikula 	/* Don't promote wm_size to unsigned... */
56894b49d53SJani Nikula 	if (wm_size > wm->max_wm)
56994b49d53SJani Nikula 		wm_size = wm->max_wm;
57094b49d53SJani Nikula 	if (wm_size <= 0)
57194b49d53SJani Nikula 		wm_size = wm->default_wm;
57294b49d53SJani Nikula 
57394b49d53SJani Nikula 	/*
57494b49d53SJani Nikula 	 * Bspec seems to indicate that the value shouldn't be lower than
57594b49d53SJani Nikula 	 * 'burst size + 1'. Certainly 830 is quite unhappy with low values.
57694b49d53SJani Nikula 	 * Lets go for 8 which is the burst size since certain platforms
57794b49d53SJani Nikula 	 * already use a hardcoded 8 (which is what the spec says should be
57894b49d53SJani Nikula 	 * done).
57994b49d53SJani Nikula 	 */
58094b49d53SJani Nikula 	if (wm_size <= 8)
58194b49d53SJani Nikula 		wm_size = 8;
58294b49d53SJani Nikula 
58394b49d53SJani Nikula 	return wm_size;
58494b49d53SJani Nikula }
58594b49d53SJani Nikula 
is_disabling(int old,int new,int threshold)58694b49d53SJani Nikula static bool is_disabling(int old, int new, int threshold)
58794b49d53SJani Nikula {
58894b49d53SJani Nikula 	return old >= threshold && new < threshold;
58994b49d53SJani Nikula }
59094b49d53SJani Nikula 
is_enabling(int old,int new,int threshold)59194b49d53SJani Nikula static bool is_enabling(int old, int new, int threshold)
59294b49d53SJani Nikula {
59394b49d53SJani Nikula 	return old < threshold && new >= threshold;
59494b49d53SJani Nikula }
59594b49d53SJani Nikula 
intel_crtc_active(struct intel_crtc * crtc)59694b49d53SJani Nikula static bool intel_crtc_active(struct intel_crtc *crtc)
59794b49d53SJani Nikula {
59894b49d53SJani Nikula 	/* Be paranoid as we can arrive here with only partial
59994b49d53SJani Nikula 	 * state retrieved from the hardware during setup.
60094b49d53SJani Nikula 	 *
60194b49d53SJani Nikula 	 * We can ditch the adjusted_mode.crtc_clock check as soon
60294b49d53SJani Nikula 	 * as Haswell has gained clock readout/fastboot support.
60394b49d53SJani Nikula 	 *
60494b49d53SJani Nikula 	 * We can ditch the crtc->primary->state->fb check as soon as we can
60594b49d53SJani Nikula 	 * properly reconstruct framebuffers.
60694b49d53SJani Nikula 	 *
60794b49d53SJani Nikula 	 * FIXME: The intel_crtc->active here should be switched to
60894b49d53SJani Nikula 	 * crtc->state->active once we have proper CRTC states wired up
60994b49d53SJani Nikula 	 * for atomic.
61094b49d53SJani Nikula 	 */
61194b49d53SJani Nikula 	return crtc && crtc->active && crtc->base.primary->state->fb &&
61294b49d53SJani Nikula 		crtc->config->hw.adjusted_mode.crtc_clock;
61394b49d53SJani Nikula }
61494b49d53SJani Nikula 
single_enabled_crtc(struct drm_i915_private * dev_priv)61594b49d53SJani Nikula static struct intel_crtc *single_enabled_crtc(struct drm_i915_private *dev_priv)
61694b49d53SJani Nikula {
61794b49d53SJani Nikula 	struct intel_crtc *crtc, *enabled = NULL;
61894b49d53SJani Nikula 
61994b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
62094b49d53SJani Nikula 		if (intel_crtc_active(crtc)) {
62194b49d53SJani Nikula 			if (enabled)
62294b49d53SJani Nikula 				return NULL;
62394b49d53SJani Nikula 			enabled = crtc;
62494b49d53SJani Nikula 		}
62594b49d53SJani Nikula 	}
62694b49d53SJani Nikula 
62794b49d53SJani Nikula 	return enabled;
62894b49d53SJani Nikula }
62994b49d53SJani Nikula 
pnv_update_wm(struct drm_i915_private * dev_priv)63094b49d53SJani Nikula static void pnv_update_wm(struct drm_i915_private *dev_priv)
63194b49d53SJani Nikula {
63294b49d53SJani Nikula 	struct intel_crtc *crtc;
63394b49d53SJani Nikula 	const struct cxsr_latency *latency;
63494b49d53SJani Nikula 	u32 reg;
63594b49d53SJani Nikula 	unsigned int wm;
63694b49d53SJani Nikula 
63794b49d53SJani Nikula 	latency = intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
63894b49d53SJani Nikula 					 dev_priv->is_ddr3,
63994b49d53SJani Nikula 					 dev_priv->fsb_freq,
64094b49d53SJani Nikula 					 dev_priv->mem_freq);
64194b49d53SJani Nikula 	if (!latency) {
64294b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
64394b49d53SJani Nikula 			    "Unknown FSB/MEM found, disable CxSR\n");
64494b49d53SJani Nikula 		intel_set_memory_cxsr(dev_priv, false);
64594b49d53SJani Nikula 		return;
64694b49d53SJani Nikula 	}
64794b49d53SJani Nikula 
64894b49d53SJani Nikula 	crtc = single_enabled_crtc(dev_priv);
64994b49d53SJani Nikula 	if (crtc) {
65094b49d53SJani Nikula 		const struct drm_framebuffer *fb =
65194b49d53SJani Nikula 			crtc->base.primary->state->fb;
65294b49d53SJani Nikula 		int pixel_rate = crtc->config->pixel_rate;
65394b49d53SJani Nikula 		int cpp = fb->format->cpp[0];
65494b49d53SJani Nikula 
65594b49d53SJani Nikula 		/* Display SR */
65694b49d53SJani Nikula 		wm = intel_calculate_wm(pixel_rate, &pnv_display_wm,
65794b49d53SJani Nikula 					pnv_display_wm.fifo_size,
65894b49d53SJani Nikula 					cpp, latency->display_sr);
65994b49d53SJani Nikula 		reg = intel_uncore_read(&dev_priv->uncore, DSPFW1);
66094b49d53SJani Nikula 		reg &= ~DSPFW_SR_MASK;
66194b49d53SJani Nikula 		reg |= FW_WM(wm, SR);
66294b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPFW1, reg);
66394b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm, "DSPFW1 register is %x\n", reg);
66494b49d53SJani Nikula 
66594b49d53SJani Nikula 		/* cursor SR */
66694b49d53SJani Nikula 		wm = intel_calculate_wm(pixel_rate, &pnv_cursor_wm,
66794b49d53SJani Nikula 					pnv_display_wm.fifo_size,
66894b49d53SJani Nikula 					4, latency->cursor_sr);
66994b49d53SJani Nikula 		intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_CURSOR_SR_MASK,
67094b49d53SJani Nikula 				 FW_WM(wm, CURSOR_SR));
67194b49d53SJani Nikula 
67294b49d53SJani Nikula 		/* Display HPLL off SR */
67394b49d53SJani Nikula 		wm = intel_calculate_wm(pixel_rate, &pnv_display_hplloff_wm,
67494b49d53SJani Nikula 					pnv_display_hplloff_wm.fifo_size,
67594b49d53SJani Nikula 					cpp, latency->display_hpll_disable);
67694b49d53SJani Nikula 		intel_uncore_rmw(&dev_priv->uncore, DSPFW3, DSPFW_HPLL_SR_MASK, FW_WM(wm, HPLL_SR));
67794b49d53SJani Nikula 
67894b49d53SJani Nikula 		/* cursor HPLL off SR */
67994b49d53SJani Nikula 		wm = intel_calculate_wm(pixel_rate, &pnv_cursor_hplloff_wm,
68094b49d53SJani Nikula 					pnv_display_hplloff_wm.fifo_size,
68194b49d53SJani Nikula 					4, latency->cursor_hpll_disable);
68294b49d53SJani Nikula 		reg = intel_uncore_read(&dev_priv->uncore, DSPFW3);
68394b49d53SJani Nikula 		reg &= ~DSPFW_HPLL_CURSOR_MASK;
68494b49d53SJani Nikula 		reg |= FW_WM(wm, HPLL_CURSOR);
68594b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPFW3, reg);
68694b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm, "DSPFW3 register is %x\n", reg);
68794b49d53SJani Nikula 
68894b49d53SJani Nikula 		intel_set_memory_cxsr(dev_priv, true);
68994b49d53SJani Nikula 	} else {
69094b49d53SJani Nikula 		intel_set_memory_cxsr(dev_priv, false);
69194b49d53SJani Nikula 	}
69294b49d53SJani Nikula }
69394b49d53SJani Nikula 
69494b49d53SJani Nikula /*
69594b49d53SJani Nikula  * Documentation says:
69694b49d53SJani Nikula  * "If the line size is small, the TLB fetches can get in the way of the
69794b49d53SJani Nikula  *  data fetches, causing some lag in the pixel data return which is not
69894b49d53SJani Nikula  *  accounted for in the above formulas. The following adjustment only
69994b49d53SJani Nikula  *  needs to be applied if eight whole lines fit in the buffer at once.
70094b49d53SJani Nikula  *  The WM is adjusted upwards by the difference between the FIFO size
70194b49d53SJani Nikula  *  and the size of 8 whole lines. This adjustment is always performed
70294b49d53SJani Nikula  *  in the actual pixel depth regardless of whether FBC is enabled or not."
70394b49d53SJani Nikula  */
g4x_tlb_miss_wa(int fifo_size,int width,int cpp)70494b49d53SJani Nikula static unsigned int g4x_tlb_miss_wa(int fifo_size, int width, int cpp)
70594b49d53SJani Nikula {
70694b49d53SJani Nikula 	int tlb_miss = fifo_size * 64 - width * cpp * 8;
70794b49d53SJani Nikula 
70894b49d53SJani Nikula 	return max(0, tlb_miss);
70994b49d53SJani Nikula }
71094b49d53SJani Nikula 
g4x_write_wm_values(struct drm_i915_private * dev_priv,const struct g4x_wm_values * wm)71194b49d53SJani Nikula static void g4x_write_wm_values(struct drm_i915_private *dev_priv,
71294b49d53SJani Nikula 				const struct g4x_wm_values *wm)
71394b49d53SJani Nikula {
71494b49d53SJani Nikula 	enum pipe pipe;
71594b49d53SJani Nikula 
71694b49d53SJani Nikula 	for_each_pipe(dev_priv, pipe)
71794b49d53SJani Nikula 		trace_g4x_wm(intel_crtc_for_pipe(dev_priv, pipe), wm);
71894b49d53SJani Nikula 
71994b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW1,
72094b49d53SJani Nikula 			   FW_WM(wm->sr.plane, SR) |
72194b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_CURSOR], CURSORB) |
72294b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_PRIMARY], PLANEB) |
72394b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_PRIMARY], PLANEA));
72494b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW2,
72594b49d53SJani Nikula 			   (wm->fbc_en ? DSPFW_FBC_SR_EN : 0) |
72694b49d53SJani Nikula 			   FW_WM(wm->sr.fbc, FBC_SR) |
72794b49d53SJani Nikula 			   FW_WM(wm->hpll.fbc, FBC_HPLL_SR) |
72894b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE0], SPRITEB) |
72994b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_CURSOR], CURSORA) |
73094b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE0], SPRITEA));
73194b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW3,
73294b49d53SJani Nikula 			   (wm->hpll_en ? DSPFW_HPLL_SR_EN : 0) |
73394b49d53SJani Nikula 			   FW_WM(wm->sr.cursor, CURSOR_SR) |
73494b49d53SJani Nikula 			   FW_WM(wm->hpll.cursor, HPLL_CURSOR) |
73594b49d53SJani Nikula 			   FW_WM(wm->hpll.plane, HPLL_SR));
73694b49d53SJani Nikula 
73794b49d53SJani Nikula 	intel_uncore_posting_read(&dev_priv->uncore, DSPFW1);
73894b49d53SJani Nikula }
73994b49d53SJani Nikula 
74094b49d53SJani Nikula #define FW_WM_VLV(value, plane) \
74194b49d53SJani Nikula 	(((value) << DSPFW_ ## plane ## _SHIFT) & DSPFW_ ## plane ## _MASK_VLV)
74294b49d53SJani Nikula 
vlv_write_wm_values(struct drm_i915_private * dev_priv,const struct vlv_wm_values * wm)74394b49d53SJani Nikula static void vlv_write_wm_values(struct drm_i915_private *dev_priv,
74494b49d53SJani Nikula 				const struct vlv_wm_values *wm)
74594b49d53SJani Nikula {
74694b49d53SJani Nikula 	enum pipe pipe;
74794b49d53SJani Nikula 
74894b49d53SJani Nikula 	for_each_pipe(dev_priv, pipe) {
74994b49d53SJani Nikula 		trace_vlv_wm(intel_crtc_for_pipe(dev_priv, pipe), wm);
75094b49d53SJani Nikula 
75194b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, VLV_DDL(pipe),
75294b49d53SJani Nikula 				   (wm->ddl[pipe].plane[PLANE_CURSOR] << DDL_CURSOR_SHIFT) |
75394b49d53SJani Nikula 				   (wm->ddl[pipe].plane[PLANE_SPRITE1] << DDL_SPRITE_SHIFT(1)) |
75494b49d53SJani Nikula 				   (wm->ddl[pipe].plane[PLANE_SPRITE0] << DDL_SPRITE_SHIFT(0)) |
75594b49d53SJani Nikula 				   (wm->ddl[pipe].plane[PLANE_PRIMARY] << DDL_PLANE_SHIFT));
75694b49d53SJani Nikula 	}
75794b49d53SJani Nikula 
75894b49d53SJani Nikula 	/*
75994b49d53SJani Nikula 	 * Zero the (unused) WM1 watermarks, and also clear all the
76094b49d53SJani Nikula 	 * high order bits so that there are no out of bounds values
76194b49d53SJani Nikula 	 * present in the registers during the reprogramming.
76294b49d53SJani Nikula 	 */
76394b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPHOWM, 0);
76494b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPHOWM1, 0);
76594b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW4, 0);
76694b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW5, 0);
76794b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW6, 0);
76894b49d53SJani Nikula 
76994b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW1,
77094b49d53SJani Nikula 			   FW_WM(wm->sr.plane, SR) |
77194b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_CURSOR], CURSORB) |
77294b49d53SJani Nikula 			   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_PRIMARY], PLANEB) |
77394b49d53SJani Nikula 			   FW_WM_VLV(wm->pipe[PIPE_A].plane[PLANE_PRIMARY], PLANEA));
77494b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW2,
77594b49d53SJani Nikula 			   FW_WM_VLV(wm->pipe[PIPE_A].plane[PLANE_SPRITE1], SPRITEB) |
77694b49d53SJani Nikula 			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_CURSOR], CURSORA) |
77794b49d53SJani Nikula 			   FW_WM_VLV(wm->pipe[PIPE_A].plane[PLANE_SPRITE0], SPRITEA));
77894b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW3,
77994b49d53SJani Nikula 			   FW_WM(wm->sr.cursor, CURSOR_SR));
78094b49d53SJani Nikula 
78194b49d53SJani Nikula 	if (IS_CHERRYVIEW(dev_priv)) {
78294b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPFW7_CHV,
78394b49d53SJani Nikula 				   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE1], SPRITED) |
78494b49d53SJani Nikula 				   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE0], SPRITEC));
78594b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPFW8_CHV,
78694b49d53SJani Nikula 				   FW_WM_VLV(wm->pipe[PIPE_C].plane[PLANE_SPRITE1], SPRITEF) |
78794b49d53SJani Nikula 				   FW_WM_VLV(wm->pipe[PIPE_C].plane[PLANE_SPRITE0], SPRITEE));
78894b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPFW9_CHV,
78994b49d53SJani Nikula 				   FW_WM_VLV(wm->pipe[PIPE_C].plane[PLANE_PRIMARY], PLANEC) |
79094b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_C].plane[PLANE_CURSOR], CURSORC));
79194b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPHOWM,
79294b49d53SJani Nikula 				   FW_WM(wm->sr.plane >> 9, SR_HI) |
79394b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_C].plane[PLANE_SPRITE1] >> 8, SPRITEF_HI) |
79494b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_C].plane[PLANE_SPRITE0] >> 8, SPRITEE_HI) |
79594b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_C].plane[PLANE_PRIMARY] >> 8, PLANEC_HI) |
79694b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE1] >> 8, SPRITED_HI) |
79794b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE0] >> 8, SPRITEC_HI) |
79894b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_B].plane[PLANE_PRIMARY] >> 8, PLANEB_HI) |
79994b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE1] >> 8, SPRITEB_HI) |
80094b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE0] >> 8, SPRITEA_HI) |
80194b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_A].plane[PLANE_PRIMARY] >> 8, PLANEA_HI));
80294b49d53SJani Nikula 	} else {
80394b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPFW7,
80494b49d53SJani Nikula 				   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE1], SPRITED) |
80594b49d53SJani Nikula 				   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE0], SPRITEC));
80694b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, DSPHOWM,
80794b49d53SJani Nikula 				   FW_WM(wm->sr.plane >> 9, SR_HI) |
80894b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE1] >> 8, SPRITED_HI) |
80994b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE0] >> 8, SPRITEC_HI) |
81094b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_B].plane[PLANE_PRIMARY] >> 8, PLANEB_HI) |
81194b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE1] >> 8, SPRITEB_HI) |
81294b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE0] >> 8, SPRITEA_HI) |
81394b49d53SJani Nikula 				   FW_WM(wm->pipe[PIPE_A].plane[PLANE_PRIMARY] >> 8, PLANEA_HI));
81494b49d53SJani Nikula 	}
81594b49d53SJani Nikula 
81694b49d53SJani Nikula 	intel_uncore_posting_read(&dev_priv->uncore, DSPFW1);
81794b49d53SJani Nikula }
81894b49d53SJani Nikula 
81994b49d53SJani Nikula #undef FW_WM_VLV
82094b49d53SJani Nikula 
g4x_setup_wm_latency(struct drm_i915_private * dev_priv)82194b49d53SJani Nikula static void g4x_setup_wm_latency(struct drm_i915_private *dev_priv)
82294b49d53SJani Nikula {
82394b49d53SJani Nikula 	/* all latencies in usec */
82494b49d53SJani Nikula 	dev_priv->display.wm.pri_latency[G4X_WM_LEVEL_NORMAL] = 5;
82594b49d53SJani Nikula 	dev_priv->display.wm.pri_latency[G4X_WM_LEVEL_SR] = 12;
82694b49d53SJani Nikula 	dev_priv->display.wm.pri_latency[G4X_WM_LEVEL_HPLL] = 35;
82794b49d53SJani Nikula 
82894b49d53SJani Nikula 	dev_priv->display.wm.num_levels = G4X_WM_LEVEL_HPLL + 1;
82994b49d53SJani Nikula }
83094b49d53SJani Nikula 
g4x_plane_fifo_size(enum plane_id plane_id,int level)83194b49d53SJani Nikula static int g4x_plane_fifo_size(enum plane_id plane_id, int level)
83294b49d53SJani Nikula {
83394b49d53SJani Nikula 	/*
83494b49d53SJani Nikula 	 * DSPCNTR[13] supposedly controls whether the
83594b49d53SJani Nikula 	 * primary plane can use the FIFO space otherwise
83694b49d53SJani Nikula 	 * reserved for the sprite plane. It's not 100% clear
83794b49d53SJani Nikula 	 * what the actual FIFO size is, but it looks like we
83894b49d53SJani Nikula 	 * can happily set both primary and sprite watermarks
83994b49d53SJani Nikula 	 * up to 127 cachelines. So that would seem to mean
84094b49d53SJani Nikula 	 * that either DSPCNTR[13] doesn't do anything, or that
84194b49d53SJani Nikula 	 * the total FIFO is >= 256 cachelines in size. Either
84294b49d53SJani Nikula 	 * way, we don't seem to have to worry about this
84394b49d53SJani Nikula 	 * repartitioning as the maximum watermark value the
84494b49d53SJani Nikula 	 * register can hold for each plane is lower than the
84594b49d53SJani Nikula 	 * minimum FIFO size.
84694b49d53SJani Nikula 	 */
84794b49d53SJani Nikula 	switch (plane_id) {
84894b49d53SJani Nikula 	case PLANE_CURSOR:
84994b49d53SJani Nikula 		return 63;
85094b49d53SJani Nikula 	case PLANE_PRIMARY:
85194b49d53SJani Nikula 		return level == G4X_WM_LEVEL_NORMAL ? 127 : 511;
85294b49d53SJani Nikula 	case PLANE_SPRITE0:
85394b49d53SJani Nikula 		return level == G4X_WM_LEVEL_NORMAL ? 127 : 0;
85494b49d53SJani Nikula 	default:
85594b49d53SJani Nikula 		MISSING_CASE(plane_id);
85694b49d53SJani Nikula 		return 0;
85794b49d53SJani Nikula 	}
85894b49d53SJani Nikula }
85994b49d53SJani Nikula 
g4x_fbc_fifo_size(int level)86094b49d53SJani Nikula static int g4x_fbc_fifo_size(int level)
86194b49d53SJani Nikula {
86294b49d53SJani Nikula 	switch (level) {
86394b49d53SJani Nikula 	case G4X_WM_LEVEL_SR:
86494b49d53SJani Nikula 		return 7;
86594b49d53SJani Nikula 	case G4X_WM_LEVEL_HPLL:
86694b49d53SJani Nikula 		return 15;
86794b49d53SJani Nikula 	default:
86894b49d53SJani Nikula 		MISSING_CASE(level);
86994b49d53SJani Nikula 		return 0;
87094b49d53SJani Nikula 	}
87194b49d53SJani Nikula }
87294b49d53SJani Nikula 
g4x_compute_wm(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,int level)87394b49d53SJani Nikula static u16 g4x_compute_wm(const struct intel_crtc_state *crtc_state,
87494b49d53SJani Nikula 			  const struct intel_plane_state *plane_state,
87594b49d53SJani Nikula 			  int level)
87694b49d53SJani Nikula {
87794b49d53SJani Nikula 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
87894b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
87994b49d53SJani Nikula 	const struct drm_display_mode *pipe_mode =
88094b49d53SJani Nikula 		&crtc_state->hw.pipe_mode;
88194b49d53SJani Nikula 	unsigned int latency = dev_priv->display.wm.pri_latency[level] * 10;
88294b49d53SJani Nikula 	unsigned int pixel_rate, htotal, cpp, width, wm;
88394b49d53SJani Nikula 
88494b49d53SJani Nikula 	if (latency == 0)
88594b49d53SJani Nikula 		return USHRT_MAX;
88694b49d53SJani Nikula 
88794b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state))
88894b49d53SJani Nikula 		return 0;
88994b49d53SJani Nikula 
89094b49d53SJani Nikula 	cpp = plane_state->hw.fb->format->cpp[0];
89194b49d53SJani Nikula 
89294b49d53SJani Nikula 	/*
89394b49d53SJani Nikula 	 * WaUse32BppForSRWM:ctg,elk
89494b49d53SJani Nikula 	 *
89594b49d53SJani Nikula 	 * The spec fails to list this restriction for the
89694b49d53SJani Nikula 	 * HPLL watermark, which seems a little strange.
89794b49d53SJani Nikula 	 * Let's use 32bpp for the HPLL watermark as well.
89894b49d53SJani Nikula 	 */
89994b49d53SJani Nikula 	if (plane->id == PLANE_PRIMARY &&
90094b49d53SJani Nikula 	    level != G4X_WM_LEVEL_NORMAL)
90194b49d53SJani Nikula 		cpp = max(cpp, 4u);
90294b49d53SJani Nikula 
90394b49d53SJani Nikula 	pixel_rate = crtc_state->pixel_rate;
90494b49d53SJani Nikula 	htotal = pipe_mode->crtc_htotal;
90594b49d53SJani Nikula 	width = drm_rect_width(&plane_state->uapi.src) >> 16;
90694b49d53SJani Nikula 
90794b49d53SJani Nikula 	if (plane->id == PLANE_CURSOR) {
90894b49d53SJani Nikula 		wm = intel_wm_method2(pixel_rate, htotal, width, cpp, latency);
90994b49d53SJani Nikula 	} else if (plane->id == PLANE_PRIMARY &&
91094b49d53SJani Nikula 		   level == G4X_WM_LEVEL_NORMAL) {
91194b49d53SJani Nikula 		wm = intel_wm_method1(pixel_rate, cpp, latency);
91294b49d53SJani Nikula 	} else {
91394b49d53SJani Nikula 		unsigned int small, large;
91494b49d53SJani Nikula 
91594b49d53SJani Nikula 		small = intel_wm_method1(pixel_rate, cpp, latency);
91694b49d53SJani Nikula 		large = intel_wm_method2(pixel_rate, htotal, width, cpp, latency);
91794b49d53SJani Nikula 
91894b49d53SJani Nikula 		wm = min(small, large);
91994b49d53SJani Nikula 	}
92094b49d53SJani Nikula 
92194b49d53SJani Nikula 	wm += g4x_tlb_miss_wa(g4x_plane_fifo_size(plane->id, level),
92294b49d53SJani Nikula 			      width, cpp);
92394b49d53SJani Nikula 
92494b49d53SJani Nikula 	wm = DIV_ROUND_UP(wm, 64) + 2;
92594b49d53SJani Nikula 
92694b49d53SJani Nikula 	return min_t(unsigned int, wm, USHRT_MAX);
92794b49d53SJani Nikula }
92894b49d53SJani Nikula 
g4x_raw_plane_wm_set(struct intel_crtc_state * crtc_state,int level,enum plane_id plane_id,u16 value)92994b49d53SJani Nikula static bool g4x_raw_plane_wm_set(struct intel_crtc_state *crtc_state,
93094b49d53SJani Nikula 				 int level, enum plane_id plane_id, u16 value)
93194b49d53SJani Nikula {
93294b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
93394b49d53SJani Nikula 	bool dirty = false;
93494b49d53SJani Nikula 
93594b49d53SJani Nikula 	for (; level < dev_priv->display.wm.num_levels; level++) {
93694b49d53SJani Nikula 		struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
93794b49d53SJani Nikula 
93894b49d53SJani Nikula 		dirty |= raw->plane[plane_id] != value;
93994b49d53SJani Nikula 		raw->plane[plane_id] = value;
94094b49d53SJani Nikula 	}
94194b49d53SJani Nikula 
94294b49d53SJani Nikula 	return dirty;
94394b49d53SJani Nikula }
94494b49d53SJani Nikula 
g4x_raw_fbc_wm_set(struct intel_crtc_state * crtc_state,int level,u16 value)94594b49d53SJani Nikula static bool g4x_raw_fbc_wm_set(struct intel_crtc_state *crtc_state,
94694b49d53SJani Nikula 			       int level, u16 value)
94794b49d53SJani Nikula {
94894b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
94994b49d53SJani Nikula 	bool dirty = false;
95094b49d53SJani Nikula 
95194b49d53SJani Nikula 	/* NORMAL level doesn't have an FBC watermark */
95294b49d53SJani Nikula 	level = max(level, G4X_WM_LEVEL_SR);
95394b49d53SJani Nikula 
95494b49d53SJani Nikula 	for (; level < dev_priv->display.wm.num_levels; level++) {
95594b49d53SJani Nikula 		struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
95694b49d53SJani Nikula 
95794b49d53SJani Nikula 		dirty |= raw->fbc != value;
95894b49d53SJani Nikula 		raw->fbc = value;
95994b49d53SJani Nikula 	}
96094b49d53SJani Nikula 
96194b49d53SJani Nikula 	return dirty;
96294b49d53SJani Nikula }
96394b49d53SJani Nikula 
96494b49d53SJani Nikula static u32 ilk_compute_fbc_wm(const struct intel_crtc_state *crtc_state,
96594b49d53SJani Nikula 			      const struct intel_plane_state *plane_state,
96694b49d53SJani Nikula 			      u32 pri_val);
96794b49d53SJani Nikula 
g4x_raw_plane_wm_compute(struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)96894b49d53SJani Nikula static bool g4x_raw_plane_wm_compute(struct intel_crtc_state *crtc_state,
96994b49d53SJani Nikula 				     const struct intel_plane_state *plane_state)
97094b49d53SJani Nikula {
97194b49d53SJani Nikula 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
97294b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
97394b49d53SJani Nikula 	enum plane_id plane_id = plane->id;
97494b49d53SJani Nikula 	bool dirty = false;
97594b49d53SJani Nikula 	int level;
97694b49d53SJani Nikula 
97794b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state)) {
97894b49d53SJani Nikula 		dirty |= g4x_raw_plane_wm_set(crtc_state, 0, plane_id, 0);
97994b49d53SJani Nikula 		if (plane_id == PLANE_PRIMARY)
98094b49d53SJani Nikula 			dirty |= g4x_raw_fbc_wm_set(crtc_state, 0, 0);
98194b49d53SJani Nikula 		goto out;
98294b49d53SJani Nikula 	}
98394b49d53SJani Nikula 
98494b49d53SJani Nikula 	for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
98594b49d53SJani Nikula 		struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
98694b49d53SJani Nikula 		int wm, max_wm;
98794b49d53SJani Nikula 
98894b49d53SJani Nikula 		wm = g4x_compute_wm(crtc_state, plane_state, level);
98994b49d53SJani Nikula 		max_wm = g4x_plane_fifo_size(plane_id, level);
99094b49d53SJani Nikula 
99194b49d53SJani Nikula 		if (wm > max_wm)
99294b49d53SJani Nikula 			break;
99394b49d53SJani Nikula 
99494b49d53SJani Nikula 		dirty |= raw->plane[plane_id] != wm;
99594b49d53SJani Nikula 		raw->plane[plane_id] = wm;
99694b49d53SJani Nikula 
99794b49d53SJani Nikula 		if (plane_id != PLANE_PRIMARY ||
99894b49d53SJani Nikula 		    level == G4X_WM_LEVEL_NORMAL)
99994b49d53SJani Nikula 			continue;
100094b49d53SJani Nikula 
100194b49d53SJani Nikula 		wm = ilk_compute_fbc_wm(crtc_state, plane_state,
100294b49d53SJani Nikula 					raw->plane[plane_id]);
100394b49d53SJani Nikula 		max_wm = g4x_fbc_fifo_size(level);
100494b49d53SJani Nikula 
100594b49d53SJani Nikula 		/*
100694b49d53SJani Nikula 		 * FBC wm is not mandatory as we
100794b49d53SJani Nikula 		 * can always just disable its use.
100894b49d53SJani Nikula 		 */
100994b49d53SJani Nikula 		if (wm > max_wm)
101094b49d53SJani Nikula 			wm = USHRT_MAX;
101194b49d53SJani Nikula 
101294b49d53SJani Nikula 		dirty |= raw->fbc != wm;
101394b49d53SJani Nikula 		raw->fbc = wm;
101494b49d53SJani Nikula 	}
101594b49d53SJani Nikula 
101694b49d53SJani Nikula 	/* mark watermarks as invalid */
101794b49d53SJani Nikula 	dirty |= g4x_raw_plane_wm_set(crtc_state, level, plane_id, USHRT_MAX);
101894b49d53SJani Nikula 
101994b49d53SJani Nikula 	if (plane_id == PLANE_PRIMARY)
102094b49d53SJani Nikula 		dirty |= g4x_raw_fbc_wm_set(crtc_state, level, USHRT_MAX);
102194b49d53SJani Nikula 
102294b49d53SJani Nikula  out:
102394b49d53SJani Nikula 	if (dirty) {
102494b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
102594b49d53SJani Nikula 			    "%s watermarks: normal=%d, SR=%d, HPLL=%d\n",
102694b49d53SJani Nikula 			    plane->base.name,
102794b49d53SJani Nikula 			    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_NORMAL].plane[plane_id],
102894b49d53SJani Nikula 			    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_SR].plane[plane_id],
102994b49d53SJani Nikula 			    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_HPLL].plane[plane_id]);
103094b49d53SJani Nikula 
103194b49d53SJani Nikula 		if (plane_id == PLANE_PRIMARY)
103294b49d53SJani Nikula 			drm_dbg_kms(&dev_priv->drm,
103394b49d53SJani Nikula 				    "FBC watermarks: SR=%d, HPLL=%d\n",
103494b49d53SJani Nikula 				    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_SR].fbc,
103594b49d53SJani Nikula 				    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_HPLL].fbc);
103694b49d53SJani Nikula 	}
103794b49d53SJani Nikula 
103894b49d53SJani Nikula 	return dirty;
103994b49d53SJani Nikula }
104094b49d53SJani Nikula 
g4x_raw_plane_wm_is_valid(const struct intel_crtc_state * crtc_state,enum plane_id plane_id,int level)104194b49d53SJani Nikula static bool g4x_raw_plane_wm_is_valid(const struct intel_crtc_state *crtc_state,
104294b49d53SJani Nikula 				      enum plane_id plane_id, int level)
104394b49d53SJani Nikula {
104494b49d53SJani Nikula 	const struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
104594b49d53SJani Nikula 
104694b49d53SJani Nikula 	return raw->plane[plane_id] <= g4x_plane_fifo_size(plane_id, level);
104794b49d53SJani Nikula }
104894b49d53SJani Nikula 
g4x_raw_crtc_wm_is_valid(const struct intel_crtc_state * crtc_state,int level)104994b49d53SJani Nikula static bool g4x_raw_crtc_wm_is_valid(const struct intel_crtc_state *crtc_state,
105094b49d53SJani Nikula 				     int level)
105194b49d53SJani Nikula {
105294b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
105394b49d53SJani Nikula 
105494b49d53SJani Nikula 	if (level >= dev_priv->display.wm.num_levels)
105594b49d53SJani Nikula 		return false;
105694b49d53SJani Nikula 
105794b49d53SJani Nikula 	return g4x_raw_plane_wm_is_valid(crtc_state, PLANE_PRIMARY, level) &&
105894b49d53SJani Nikula 		g4x_raw_plane_wm_is_valid(crtc_state, PLANE_SPRITE0, level) &&
105994b49d53SJani Nikula 		g4x_raw_plane_wm_is_valid(crtc_state, PLANE_CURSOR, level);
106094b49d53SJani Nikula }
106194b49d53SJani Nikula 
106294b49d53SJani Nikula /* mark all levels starting from 'level' as invalid */
g4x_invalidate_wms(struct intel_crtc * crtc,struct g4x_wm_state * wm_state,int level)106394b49d53SJani Nikula static void g4x_invalidate_wms(struct intel_crtc *crtc,
106494b49d53SJani Nikula 			       struct g4x_wm_state *wm_state, int level)
106594b49d53SJani Nikula {
106694b49d53SJani Nikula 	if (level <= G4X_WM_LEVEL_NORMAL) {
106794b49d53SJani Nikula 		enum plane_id plane_id;
106894b49d53SJani Nikula 
106994b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id)
107094b49d53SJani Nikula 			wm_state->wm.plane[plane_id] = USHRT_MAX;
107194b49d53SJani Nikula 	}
107294b49d53SJani Nikula 
107394b49d53SJani Nikula 	if (level <= G4X_WM_LEVEL_SR) {
107494b49d53SJani Nikula 		wm_state->cxsr = false;
107594b49d53SJani Nikula 		wm_state->sr.cursor = USHRT_MAX;
107694b49d53SJani Nikula 		wm_state->sr.plane = USHRT_MAX;
107794b49d53SJani Nikula 		wm_state->sr.fbc = USHRT_MAX;
107894b49d53SJani Nikula 	}
107994b49d53SJani Nikula 
108094b49d53SJani Nikula 	if (level <= G4X_WM_LEVEL_HPLL) {
108194b49d53SJani Nikula 		wm_state->hpll_en = false;
108294b49d53SJani Nikula 		wm_state->hpll.cursor = USHRT_MAX;
108394b49d53SJani Nikula 		wm_state->hpll.plane = USHRT_MAX;
108494b49d53SJani Nikula 		wm_state->hpll.fbc = USHRT_MAX;
108594b49d53SJani Nikula 	}
108694b49d53SJani Nikula }
108794b49d53SJani Nikula 
g4x_compute_fbc_en(const struct g4x_wm_state * wm_state,int level)108894b49d53SJani Nikula static bool g4x_compute_fbc_en(const struct g4x_wm_state *wm_state,
108994b49d53SJani Nikula 			       int level)
109094b49d53SJani Nikula {
109194b49d53SJani Nikula 	if (level < G4X_WM_LEVEL_SR)
109294b49d53SJani Nikula 		return false;
109394b49d53SJani Nikula 
109494b49d53SJani Nikula 	if (level >= G4X_WM_LEVEL_SR &&
109594b49d53SJani Nikula 	    wm_state->sr.fbc > g4x_fbc_fifo_size(G4X_WM_LEVEL_SR))
109694b49d53SJani Nikula 		return false;
109794b49d53SJani Nikula 
109894b49d53SJani Nikula 	if (level >= G4X_WM_LEVEL_HPLL &&
109994b49d53SJani Nikula 	    wm_state->hpll.fbc > g4x_fbc_fifo_size(G4X_WM_LEVEL_HPLL))
110094b49d53SJani Nikula 		return false;
110194b49d53SJani Nikula 
110294b49d53SJani Nikula 	return true;
110394b49d53SJani Nikula }
110494b49d53SJani Nikula 
_g4x_compute_pipe_wm(struct intel_crtc_state * crtc_state)110594b49d53SJani Nikula static int _g4x_compute_pipe_wm(struct intel_crtc_state *crtc_state)
110694b49d53SJani Nikula {
110794b49d53SJani Nikula 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
110894b49d53SJani Nikula 	struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal;
110994b49d53SJani Nikula 	u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
111094b49d53SJani Nikula 	const struct g4x_pipe_wm *raw;
111194b49d53SJani Nikula 	enum plane_id plane_id;
111294b49d53SJani Nikula 	int level;
111394b49d53SJani Nikula 
111494b49d53SJani Nikula 	level = G4X_WM_LEVEL_NORMAL;
111594b49d53SJani Nikula 	if (!g4x_raw_crtc_wm_is_valid(crtc_state, level))
111694b49d53SJani Nikula 		goto out;
111794b49d53SJani Nikula 
111894b49d53SJani Nikula 	raw = &crtc_state->wm.g4x.raw[level];
111994b49d53SJani Nikula 	for_each_plane_id_on_crtc(crtc, plane_id)
112094b49d53SJani Nikula 		wm_state->wm.plane[plane_id] = raw->plane[plane_id];
112194b49d53SJani Nikula 
112294b49d53SJani Nikula 	level = G4X_WM_LEVEL_SR;
112394b49d53SJani Nikula 	if (!g4x_raw_crtc_wm_is_valid(crtc_state, level))
112494b49d53SJani Nikula 		goto out;
112594b49d53SJani Nikula 
112694b49d53SJani Nikula 	raw = &crtc_state->wm.g4x.raw[level];
112794b49d53SJani Nikula 	wm_state->sr.plane = raw->plane[PLANE_PRIMARY];
112894b49d53SJani Nikula 	wm_state->sr.cursor = raw->plane[PLANE_CURSOR];
112994b49d53SJani Nikula 	wm_state->sr.fbc = raw->fbc;
113094b49d53SJani Nikula 
113194b49d53SJani Nikula 	wm_state->cxsr = active_planes == BIT(PLANE_PRIMARY);
113294b49d53SJani Nikula 
113394b49d53SJani Nikula 	level = G4X_WM_LEVEL_HPLL;
113494b49d53SJani Nikula 	if (!g4x_raw_crtc_wm_is_valid(crtc_state, level))
113594b49d53SJani Nikula 		goto out;
113694b49d53SJani Nikula 
113794b49d53SJani Nikula 	raw = &crtc_state->wm.g4x.raw[level];
113894b49d53SJani Nikula 	wm_state->hpll.plane = raw->plane[PLANE_PRIMARY];
113994b49d53SJani Nikula 	wm_state->hpll.cursor = raw->plane[PLANE_CURSOR];
114094b49d53SJani Nikula 	wm_state->hpll.fbc = raw->fbc;
114194b49d53SJani Nikula 
114294b49d53SJani Nikula 	wm_state->hpll_en = wm_state->cxsr;
114394b49d53SJani Nikula 
114494b49d53SJani Nikula 	level++;
114594b49d53SJani Nikula 
114694b49d53SJani Nikula  out:
114794b49d53SJani Nikula 	if (level == G4X_WM_LEVEL_NORMAL)
114894b49d53SJani Nikula 		return -EINVAL;
114994b49d53SJani Nikula 
115094b49d53SJani Nikula 	/* invalidate the higher levels */
115194b49d53SJani Nikula 	g4x_invalidate_wms(crtc, wm_state, level);
115294b49d53SJani Nikula 
115394b49d53SJani Nikula 	/*
115494b49d53SJani Nikula 	 * Determine if the FBC watermark(s) can be used. IF
115594b49d53SJani Nikula 	 * this isn't the case we prefer to disable the FBC
115694b49d53SJani Nikula 	 * watermark(s) rather than disable the SR/HPLL
115794b49d53SJani Nikula 	 * level(s) entirely. 'level-1' is the highest valid
115894b49d53SJani Nikula 	 * level here.
115994b49d53SJani Nikula 	 */
116094b49d53SJani Nikula 	wm_state->fbc_en = g4x_compute_fbc_en(wm_state, level - 1);
116194b49d53SJani Nikula 
116294b49d53SJani Nikula 	return 0;
116394b49d53SJani Nikula }
116494b49d53SJani Nikula 
g4x_compute_pipe_wm(struct intel_atomic_state * state,struct intel_crtc * crtc)116594b49d53SJani Nikula static int g4x_compute_pipe_wm(struct intel_atomic_state *state,
116694b49d53SJani Nikula 			       struct intel_crtc *crtc)
116794b49d53SJani Nikula {
116894b49d53SJani Nikula 	struct intel_crtc_state *crtc_state =
116994b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
117094b49d53SJani Nikula 	const struct intel_plane_state *old_plane_state;
117194b49d53SJani Nikula 	const struct intel_plane_state *new_plane_state;
117294b49d53SJani Nikula 	struct intel_plane *plane;
117394b49d53SJani Nikula 	unsigned int dirty = 0;
117494b49d53SJani Nikula 	int i;
117594b49d53SJani Nikula 
117694b49d53SJani Nikula 	for_each_oldnew_intel_plane_in_state(state, plane,
117794b49d53SJani Nikula 					     old_plane_state,
117894b49d53SJani Nikula 					     new_plane_state, i) {
117994b49d53SJani Nikula 		if (new_plane_state->hw.crtc != &crtc->base &&
118094b49d53SJani Nikula 		    old_plane_state->hw.crtc != &crtc->base)
118194b49d53SJani Nikula 			continue;
118294b49d53SJani Nikula 
118394b49d53SJani Nikula 		if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state))
118494b49d53SJani Nikula 			dirty |= BIT(plane->id);
118594b49d53SJani Nikula 	}
118694b49d53SJani Nikula 
118794b49d53SJani Nikula 	if (!dirty)
118894b49d53SJani Nikula 		return 0;
118994b49d53SJani Nikula 
119094b49d53SJani Nikula 	return _g4x_compute_pipe_wm(crtc_state);
119194b49d53SJani Nikula }
119294b49d53SJani Nikula 
g4x_compute_intermediate_wm(struct intel_atomic_state * state,struct intel_crtc * crtc)119394b49d53SJani Nikula static int g4x_compute_intermediate_wm(struct intel_atomic_state *state,
119494b49d53SJani Nikula 				       struct intel_crtc *crtc)
119594b49d53SJani Nikula {
119694b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
119794b49d53SJani Nikula 	struct intel_crtc_state *new_crtc_state =
119894b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
119994b49d53SJani Nikula 	const struct intel_crtc_state *old_crtc_state =
120094b49d53SJani Nikula 		intel_atomic_get_old_crtc_state(state, crtc);
120194b49d53SJani Nikula 	struct g4x_wm_state *intermediate = &new_crtc_state->wm.g4x.intermediate;
120294b49d53SJani Nikula 	const struct g4x_wm_state *optimal = &new_crtc_state->wm.g4x.optimal;
120394b49d53SJani Nikula 	const struct g4x_wm_state *active = &old_crtc_state->wm.g4x.optimal;
120494b49d53SJani Nikula 	enum plane_id plane_id;
120594b49d53SJani Nikula 
120694b49d53SJani Nikula 	if (!new_crtc_state->hw.active ||
120794b49d53SJani Nikula 	    intel_crtc_needs_modeset(new_crtc_state)) {
120894b49d53SJani Nikula 		*intermediate = *optimal;
120994b49d53SJani Nikula 
121094b49d53SJani Nikula 		intermediate->cxsr = false;
121194b49d53SJani Nikula 		intermediate->hpll_en = false;
121294b49d53SJani Nikula 		goto out;
121394b49d53SJani Nikula 	}
121494b49d53SJani Nikula 
121594b49d53SJani Nikula 	intermediate->cxsr = optimal->cxsr && active->cxsr &&
121694b49d53SJani Nikula 		!new_crtc_state->disable_cxsr;
121794b49d53SJani Nikula 	intermediate->hpll_en = optimal->hpll_en && active->hpll_en &&
121894b49d53SJani Nikula 		!new_crtc_state->disable_cxsr;
121994b49d53SJani Nikula 	intermediate->fbc_en = optimal->fbc_en && active->fbc_en;
122094b49d53SJani Nikula 
122194b49d53SJani Nikula 	for_each_plane_id_on_crtc(crtc, plane_id) {
122294b49d53SJani Nikula 		intermediate->wm.plane[plane_id] =
122394b49d53SJani Nikula 			max(optimal->wm.plane[plane_id],
122494b49d53SJani Nikula 			    active->wm.plane[plane_id]);
122594b49d53SJani Nikula 
122694b49d53SJani Nikula 		drm_WARN_ON(&dev_priv->drm, intermediate->wm.plane[plane_id] >
122794b49d53SJani Nikula 			    g4x_plane_fifo_size(plane_id, G4X_WM_LEVEL_NORMAL));
122894b49d53SJani Nikula 	}
122994b49d53SJani Nikula 
123094b49d53SJani Nikula 	intermediate->sr.plane = max(optimal->sr.plane,
123194b49d53SJani Nikula 				     active->sr.plane);
123294b49d53SJani Nikula 	intermediate->sr.cursor = max(optimal->sr.cursor,
123394b49d53SJani Nikula 				      active->sr.cursor);
123494b49d53SJani Nikula 	intermediate->sr.fbc = max(optimal->sr.fbc,
123594b49d53SJani Nikula 				   active->sr.fbc);
123694b49d53SJani Nikula 
123794b49d53SJani Nikula 	intermediate->hpll.plane = max(optimal->hpll.plane,
123894b49d53SJani Nikula 				       active->hpll.plane);
123994b49d53SJani Nikula 	intermediate->hpll.cursor = max(optimal->hpll.cursor,
124094b49d53SJani Nikula 					active->hpll.cursor);
124194b49d53SJani Nikula 	intermediate->hpll.fbc = max(optimal->hpll.fbc,
124294b49d53SJani Nikula 				     active->hpll.fbc);
124394b49d53SJani Nikula 
124494b49d53SJani Nikula 	drm_WARN_ON(&dev_priv->drm,
124594b49d53SJani Nikula 		    (intermediate->sr.plane >
124694b49d53SJani Nikula 		     g4x_plane_fifo_size(PLANE_PRIMARY, G4X_WM_LEVEL_SR) ||
124794b49d53SJani Nikula 		     intermediate->sr.cursor >
124894b49d53SJani Nikula 		     g4x_plane_fifo_size(PLANE_CURSOR, G4X_WM_LEVEL_SR)) &&
124994b49d53SJani Nikula 		    intermediate->cxsr);
125094b49d53SJani Nikula 	drm_WARN_ON(&dev_priv->drm,
125194b49d53SJani Nikula 		    (intermediate->sr.plane >
125294b49d53SJani Nikula 		     g4x_plane_fifo_size(PLANE_PRIMARY, G4X_WM_LEVEL_HPLL) ||
125394b49d53SJani Nikula 		     intermediate->sr.cursor >
125494b49d53SJani Nikula 		     g4x_plane_fifo_size(PLANE_CURSOR, G4X_WM_LEVEL_HPLL)) &&
125594b49d53SJani Nikula 		    intermediate->hpll_en);
125694b49d53SJani Nikula 
125794b49d53SJani Nikula 	drm_WARN_ON(&dev_priv->drm,
125894b49d53SJani Nikula 		    intermediate->sr.fbc > g4x_fbc_fifo_size(1) &&
125994b49d53SJani Nikula 		    intermediate->fbc_en && intermediate->cxsr);
126094b49d53SJani Nikula 	drm_WARN_ON(&dev_priv->drm,
126194b49d53SJani Nikula 		    intermediate->hpll.fbc > g4x_fbc_fifo_size(2) &&
126294b49d53SJani Nikula 		    intermediate->fbc_en && intermediate->hpll_en);
126394b49d53SJani Nikula 
126494b49d53SJani Nikula out:
126594b49d53SJani Nikula 	/*
126694b49d53SJani Nikula 	 * If our intermediate WM are identical to the final WM, then we can
126794b49d53SJani Nikula 	 * omit the post-vblank programming; only update if it's different.
126894b49d53SJani Nikula 	 */
126994b49d53SJani Nikula 	if (memcmp(intermediate, optimal, sizeof(*intermediate)) != 0)
127094b49d53SJani Nikula 		new_crtc_state->wm.need_postvbl_update = true;
127194b49d53SJani Nikula 
127294b49d53SJani Nikula 	return 0;
127394b49d53SJani Nikula }
127494b49d53SJani Nikula 
g4x_merge_wm(struct drm_i915_private * dev_priv,struct g4x_wm_values * wm)127594b49d53SJani Nikula static void g4x_merge_wm(struct drm_i915_private *dev_priv,
127694b49d53SJani Nikula 			 struct g4x_wm_values *wm)
127794b49d53SJani Nikula {
127894b49d53SJani Nikula 	struct intel_crtc *crtc;
127994b49d53SJani Nikula 	int num_active_pipes = 0;
128094b49d53SJani Nikula 
128194b49d53SJani Nikula 	wm->cxsr = true;
128294b49d53SJani Nikula 	wm->hpll_en = true;
128394b49d53SJani Nikula 	wm->fbc_en = true;
128494b49d53SJani Nikula 
128594b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
128694b49d53SJani Nikula 		const struct g4x_wm_state *wm_state = &crtc->wm.active.g4x;
128794b49d53SJani Nikula 
128894b49d53SJani Nikula 		if (!crtc->active)
128994b49d53SJani Nikula 			continue;
129094b49d53SJani Nikula 
129194b49d53SJani Nikula 		if (!wm_state->cxsr)
129294b49d53SJani Nikula 			wm->cxsr = false;
129394b49d53SJani Nikula 		if (!wm_state->hpll_en)
129494b49d53SJani Nikula 			wm->hpll_en = false;
129594b49d53SJani Nikula 		if (!wm_state->fbc_en)
129694b49d53SJani Nikula 			wm->fbc_en = false;
129794b49d53SJani Nikula 
129894b49d53SJani Nikula 		num_active_pipes++;
129994b49d53SJani Nikula 	}
130094b49d53SJani Nikula 
130194b49d53SJani Nikula 	if (num_active_pipes != 1) {
130294b49d53SJani Nikula 		wm->cxsr = false;
130394b49d53SJani Nikula 		wm->hpll_en = false;
130494b49d53SJani Nikula 		wm->fbc_en = false;
130594b49d53SJani Nikula 	}
130694b49d53SJani Nikula 
130794b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
130894b49d53SJani Nikula 		const struct g4x_wm_state *wm_state = &crtc->wm.active.g4x;
130994b49d53SJani Nikula 		enum pipe pipe = crtc->pipe;
131094b49d53SJani Nikula 
131194b49d53SJani Nikula 		wm->pipe[pipe] = wm_state->wm;
131294b49d53SJani Nikula 		if (crtc->active && wm->cxsr)
131394b49d53SJani Nikula 			wm->sr = wm_state->sr;
131494b49d53SJani Nikula 		if (crtc->active && wm->hpll_en)
131594b49d53SJani Nikula 			wm->hpll = wm_state->hpll;
131694b49d53SJani Nikula 	}
131794b49d53SJani Nikula }
131894b49d53SJani Nikula 
g4x_program_watermarks(struct drm_i915_private * dev_priv)131994b49d53SJani Nikula static void g4x_program_watermarks(struct drm_i915_private *dev_priv)
132094b49d53SJani Nikula {
132194b49d53SJani Nikula 	struct g4x_wm_values *old_wm = &dev_priv->display.wm.g4x;
132294b49d53SJani Nikula 	struct g4x_wm_values new_wm = {};
132394b49d53SJani Nikula 
132494b49d53SJani Nikula 	g4x_merge_wm(dev_priv, &new_wm);
132594b49d53SJani Nikula 
132694b49d53SJani Nikula 	if (memcmp(old_wm, &new_wm, sizeof(new_wm)) == 0)
132794b49d53SJani Nikula 		return;
132894b49d53SJani Nikula 
132994b49d53SJani Nikula 	if (is_disabling(old_wm->cxsr, new_wm.cxsr, true))
133094b49d53SJani Nikula 		_intel_set_memory_cxsr(dev_priv, false);
133194b49d53SJani Nikula 
133294b49d53SJani Nikula 	g4x_write_wm_values(dev_priv, &new_wm);
133394b49d53SJani Nikula 
133494b49d53SJani Nikula 	if (is_enabling(old_wm->cxsr, new_wm.cxsr, true))
133594b49d53SJani Nikula 		_intel_set_memory_cxsr(dev_priv, true);
133694b49d53SJani Nikula 
133794b49d53SJani Nikula 	*old_wm = new_wm;
133894b49d53SJani Nikula }
133994b49d53SJani Nikula 
g4x_initial_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)134094b49d53SJani Nikula static void g4x_initial_watermarks(struct intel_atomic_state *state,
134194b49d53SJani Nikula 				   struct intel_crtc *crtc)
134294b49d53SJani Nikula {
134394b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
134494b49d53SJani Nikula 	const struct intel_crtc_state *crtc_state =
134594b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
134694b49d53SJani Nikula 
134794b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
134894b49d53SJani Nikula 	crtc->wm.active.g4x = crtc_state->wm.g4x.intermediate;
134994b49d53SJani Nikula 	g4x_program_watermarks(dev_priv);
135094b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
135194b49d53SJani Nikula }
135294b49d53SJani Nikula 
g4x_optimize_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)135394b49d53SJani Nikula static void g4x_optimize_watermarks(struct intel_atomic_state *state,
135494b49d53SJani Nikula 				    struct intel_crtc *crtc)
135594b49d53SJani Nikula {
135694b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
135794b49d53SJani Nikula 	const struct intel_crtc_state *crtc_state =
135894b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
135994b49d53SJani Nikula 
136094b49d53SJani Nikula 	if (!crtc_state->wm.need_postvbl_update)
136194b49d53SJani Nikula 		return;
136294b49d53SJani Nikula 
136394b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
136494b49d53SJani Nikula 	crtc->wm.active.g4x = crtc_state->wm.g4x.optimal;
136594b49d53SJani Nikula 	g4x_program_watermarks(dev_priv);
136694b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
136794b49d53SJani Nikula }
136894b49d53SJani Nikula 
136994b49d53SJani Nikula /* latency must be in 0.1us units. */
vlv_wm_method2(unsigned int pixel_rate,unsigned int htotal,unsigned int width,unsigned int cpp,unsigned int latency)137094b49d53SJani Nikula static unsigned int vlv_wm_method2(unsigned int pixel_rate,
137194b49d53SJani Nikula 				   unsigned int htotal,
137294b49d53SJani Nikula 				   unsigned int width,
137394b49d53SJani Nikula 				   unsigned int cpp,
137494b49d53SJani Nikula 				   unsigned int latency)
137594b49d53SJani Nikula {
137694b49d53SJani Nikula 	unsigned int ret;
137794b49d53SJani Nikula 
137894b49d53SJani Nikula 	ret = intel_wm_method2(pixel_rate, htotal,
137994b49d53SJani Nikula 			       width, cpp, latency);
138094b49d53SJani Nikula 	ret = DIV_ROUND_UP(ret, 64);
138194b49d53SJani Nikula 
138294b49d53SJani Nikula 	return ret;
138394b49d53SJani Nikula }
138494b49d53SJani Nikula 
vlv_setup_wm_latency(struct drm_i915_private * dev_priv)138594b49d53SJani Nikula static void vlv_setup_wm_latency(struct drm_i915_private *dev_priv)
138694b49d53SJani Nikula {
138794b49d53SJani Nikula 	/* all latencies in usec */
138894b49d53SJani Nikula 	dev_priv->display.wm.pri_latency[VLV_WM_LEVEL_PM2] = 3;
138994b49d53SJani Nikula 
139094b49d53SJani Nikula 	dev_priv->display.wm.num_levels = VLV_WM_LEVEL_PM2 + 1;
139194b49d53SJani Nikula 
139294b49d53SJani Nikula 	if (IS_CHERRYVIEW(dev_priv)) {
139394b49d53SJani Nikula 		dev_priv->display.wm.pri_latency[VLV_WM_LEVEL_PM5] = 12;
139494b49d53SJani Nikula 		dev_priv->display.wm.pri_latency[VLV_WM_LEVEL_DDR_DVFS] = 33;
139594b49d53SJani Nikula 
139694b49d53SJani Nikula 		dev_priv->display.wm.num_levels = VLV_WM_LEVEL_DDR_DVFS + 1;
139794b49d53SJani Nikula 	}
139894b49d53SJani Nikula }
139994b49d53SJani Nikula 
vlv_compute_wm_level(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,int level)140094b49d53SJani Nikula static u16 vlv_compute_wm_level(const struct intel_crtc_state *crtc_state,
140194b49d53SJani Nikula 				const struct intel_plane_state *plane_state,
140294b49d53SJani Nikula 				int level)
140394b49d53SJani Nikula {
140494b49d53SJani Nikula 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
140594b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
140694b49d53SJani Nikula 	const struct drm_display_mode *pipe_mode =
140794b49d53SJani Nikula 		&crtc_state->hw.pipe_mode;
140894b49d53SJani Nikula 	unsigned int pixel_rate, htotal, cpp, width, wm;
140994b49d53SJani Nikula 
141094b49d53SJani Nikula 	if (dev_priv->display.wm.pri_latency[level] == 0)
141194b49d53SJani Nikula 		return USHRT_MAX;
141294b49d53SJani Nikula 
141394b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state))
141494b49d53SJani Nikula 		return 0;
141594b49d53SJani Nikula 
141694b49d53SJani Nikula 	cpp = plane_state->hw.fb->format->cpp[0];
141794b49d53SJani Nikula 	pixel_rate = crtc_state->pixel_rate;
141894b49d53SJani Nikula 	htotal = pipe_mode->crtc_htotal;
141994b49d53SJani Nikula 	width = drm_rect_width(&plane_state->uapi.src) >> 16;
142094b49d53SJani Nikula 
142194b49d53SJani Nikula 	if (plane->id == PLANE_CURSOR) {
142294b49d53SJani Nikula 		/*
142394b49d53SJani Nikula 		 * FIXME the formula gives values that are
142494b49d53SJani Nikula 		 * too big for the cursor FIFO, and hence we
142594b49d53SJani Nikula 		 * would never be able to use cursors. For
142694b49d53SJani Nikula 		 * now just hardcode the watermark.
142794b49d53SJani Nikula 		 */
142894b49d53SJani Nikula 		wm = 63;
142994b49d53SJani Nikula 	} else {
143094b49d53SJani Nikula 		wm = vlv_wm_method2(pixel_rate, htotal, width, cpp,
143194b49d53SJani Nikula 				    dev_priv->display.wm.pri_latency[level] * 10);
143294b49d53SJani Nikula 	}
143394b49d53SJani Nikula 
143494b49d53SJani Nikula 	return min_t(unsigned int, wm, USHRT_MAX);
143594b49d53SJani Nikula }
143694b49d53SJani Nikula 
vlv_need_sprite0_fifo_workaround(unsigned int active_planes)143794b49d53SJani Nikula static bool vlv_need_sprite0_fifo_workaround(unsigned int active_planes)
143894b49d53SJani Nikula {
143994b49d53SJani Nikula 	return (active_planes & (BIT(PLANE_SPRITE0) |
144094b49d53SJani Nikula 				 BIT(PLANE_SPRITE1))) == BIT(PLANE_SPRITE1);
144194b49d53SJani Nikula }
144294b49d53SJani Nikula 
vlv_compute_fifo(struct intel_crtc_state * crtc_state)144394b49d53SJani Nikula static int vlv_compute_fifo(struct intel_crtc_state *crtc_state)
144494b49d53SJani Nikula {
144594b49d53SJani Nikula 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
144694b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
144794b49d53SJani Nikula 	const struct g4x_pipe_wm *raw =
144894b49d53SJani Nikula 		&crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2];
144994b49d53SJani Nikula 	struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state;
145094b49d53SJani Nikula 	u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
145194b49d53SJani Nikula 	int num_active_planes = hweight8(active_planes);
145294b49d53SJani Nikula 	const int fifo_size = 511;
145394b49d53SJani Nikula 	int fifo_extra, fifo_left = fifo_size;
145494b49d53SJani Nikula 	int sprite0_fifo_extra = 0;
145594b49d53SJani Nikula 	unsigned int total_rate;
145694b49d53SJani Nikula 	enum plane_id plane_id;
145794b49d53SJani Nikula 
145894b49d53SJani Nikula 	/*
145994b49d53SJani Nikula 	 * When enabling sprite0 after sprite1 has already been enabled
146094b49d53SJani Nikula 	 * we tend to get an underrun unless sprite0 already has some
146194b49d53SJani Nikula 	 * FIFO space allcoated. Hence we always allocate at least one
146294b49d53SJani Nikula 	 * cacheline for sprite0 whenever sprite1 is enabled.
146394b49d53SJani Nikula 	 *
146494b49d53SJani Nikula 	 * All other plane enable sequences appear immune to this problem.
146594b49d53SJani Nikula 	 */
146694b49d53SJani Nikula 	if (vlv_need_sprite0_fifo_workaround(active_planes))
146794b49d53SJani Nikula 		sprite0_fifo_extra = 1;
146894b49d53SJani Nikula 
146994b49d53SJani Nikula 	total_rate = raw->plane[PLANE_PRIMARY] +
147094b49d53SJani Nikula 		raw->plane[PLANE_SPRITE0] +
147194b49d53SJani Nikula 		raw->plane[PLANE_SPRITE1] +
147294b49d53SJani Nikula 		sprite0_fifo_extra;
147394b49d53SJani Nikula 
147494b49d53SJani Nikula 	if (total_rate > fifo_size)
147594b49d53SJani Nikula 		return -EINVAL;
147694b49d53SJani Nikula 
147794b49d53SJani Nikula 	if (total_rate == 0)
147894b49d53SJani Nikula 		total_rate = 1;
147994b49d53SJani Nikula 
148094b49d53SJani Nikula 	for_each_plane_id_on_crtc(crtc, plane_id) {
148194b49d53SJani Nikula 		unsigned int rate;
148294b49d53SJani Nikula 
148394b49d53SJani Nikula 		if ((active_planes & BIT(plane_id)) == 0) {
148494b49d53SJani Nikula 			fifo_state->plane[plane_id] = 0;
148594b49d53SJani Nikula 			continue;
148694b49d53SJani Nikula 		}
148794b49d53SJani Nikula 
148894b49d53SJani Nikula 		rate = raw->plane[plane_id];
148994b49d53SJani Nikula 		fifo_state->plane[plane_id] = fifo_size * rate / total_rate;
149094b49d53SJani Nikula 		fifo_left -= fifo_state->plane[plane_id];
149194b49d53SJani Nikula 	}
149294b49d53SJani Nikula 
149394b49d53SJani Nikula 	fifo_state->plane[PLANE_SPRITE0] += sprite0_fifo_extra;
149494b49d53SJani Nikula 	fifo_left -= sprite0_fifo_extra;
149594b49d53SJani Nikula 
149694b49d53SJani Nikula 	fifo_state->plane[PLANE_CURSOR] = 63;
149794b49d53SJani Nikula 
149894b49d53SJani Nikula 	fifo_extra = DIV_ROUND_UP(fifo_left, num_active_planes ?: 1);
149994b49d53SJani Nikula 
150094b49d53SJani Nikula 	/* spread the remainder evenly */
150194b49d53SJani Nikula 	for_each_plane_id_on_crtc(crtc, plane_id) {
150294b49d53SJani Nikula 		int plane_extra;
150394b49d53SJani Nikula 
150494b49d53SJani Nikula 		if (fifo_left == 0)
150594b49d53SJani Nikula 			break;
150694b49d53SJani Nikula 
150794b49d53SJani Nikula 		if ((active_planes & BIT(plane_id)) == 0)
150894b49d53SJani Nikula 			continue;
150994b49d53SJani Nikula 
151094b49d53SJani Nikula 		plane_extra = min(fifo_extra, fifo_left);
151194b49d53SJani Nikula 		fifo_state->plane[plane_id] += plane_extra;
151294b49d53SJani Nikula 		fifo_left -= plane_extra;
151394b49d53SJani Nikula 	}
151494b49d53SJani Nikula 
151594b49d53SJani Nikula 	drm_WARN_ON(&dev_priv->drm, active_planes != 0 && fifo_left != 0);
151694b49d53SJani Nikula 
151794b49d53SJani Nikula 	/* give it all to the first plane if none are active */
151894b49d53SJani Nikula 	if (active_planes == 0) {
151994b49d53SJani Nikula 		drm_WARN_ON(&dev_priv->drm, fifo_left != fifo_size);
152094b49d53SJani Nikula 		fifo_state->plane[PLANE_PRIMARY] = fifo_left;
152194b49d53SJani Nikula 	}
152294b49d53SJani Nikula 
152394b49d53SJani Nikula 	return 0;
152494b49d53SJani Nikula }
152594b49d53SJani Nikula 
152694b49d53SJani Nikula /* mark all levels starting from 'level' as invalid */
vlv_invalidate_wms(struct intel_crtc * crtc,struct vlv_wm_state * wm_state,int level)152794b49d53SJani Nikula static void vlv_invalidate_wms(struct intel_crtc *crtc,
152894b49d53SJani Nikula 			       struct vlv_wm_state *wm_state, int level)
152994b49d53SJani Nikula {
153094b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
153194b49d53SJani Nikula 
153294b49d53SJani Nikula 	for (; level < dev_priv->display.wm.num_levels; level++) {
153394b49d53SJani Nikula 		enum plane_id plane_id;
153494b49d53SJani Nikula 
153594b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id)
153694b49d53SJani Nikula 			wm_state->wm[level].plane[plane_id] = USHRT_MAX;
153794b49d53SJani Nikula 
153894b49d53SJani Nikula 		wm_state->sr[level].cursor = USHRT_MAX;
153994b49d53SJani Nikula 		wm_state->sr[level].plane = USHRT_MAX;
154094b49d53SJani Nikula 	}
154194b49d53SJani Nikula }
154294b49d53SJani Nikula 
vlv_invert_wm_value(u16 wm,u16 fifo_size)154394b49d53SJani Nikula static u16 vlv_invert_wm_value(u16 wm, u16 fifo_size)
154494b49d53SJani Nikula {
154594b49d53SJani Nikula 	if (wm > fifo_size)
154694b49d53SJani Nikula 		return USHRT_MAX;
154794b49d53SJani Nikula 	else
154894b49d53SJani Nikula 		return fifo_size - wm;
154994b49d53SJani Nikula }
155094b49d53SJani Nikula 
155194b49d53SJani Nikula /*
155294b49d53SJani Nikula  * Starting from 'level' set all higher
155394b49d53SJani Nikula  * levels to 'value' in the "raw" watermarks.
155494b49d53SJani Nikula  */
vlv_raw_plane_wm_set(struct intel_crtc_state * crtc_state,int level,enum plane_id plane_id,u16 value)155594b49d53SJani Nikula static bool vlv_raw_plane_wm_set(struct intel_crtc_state *crtc_state,
155694b49d53SJani Nikula 				 int level, enum plane_id plane_id, u16 value)
155794b49d53SJani Nikula {
155894b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
155994b49d53SJani Nikula 	bool dirty = false;
156094b49d53SJani Nikula 
156194b49d53SJani Nikula 	for (; level < dev_priv->display.wm.num_levels; level++) {
156294b49d53SJani Nikula 		struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
156394b49d53SJani Nikula 
156494b49d53SJani Nikula 		dirty |= raw->plane[plane_id] != value;
156594b49d53SJani Nikula 		raw->plane[plane_id] = value;
156694b49d53SJani Nikula 	}
156794b49d53SJani Nikula 
156894b49d53SJani Nikula 	return dirty;
156994b49d53SJani Nikula }
157094b49d53SJani Nikula 
vlv_raw_plane_wm_compute(struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)157194b49d53SJani Nikula static bool vlv_raw_plane_wm_compute(struct intel_crtc_state *crtc_state,
157294b49d53SJani Nikula 				     const struct intel_plane_state *plane_state)
157394b49d53SJani Nikula {
157494b49d53SJani Nikula 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
157594b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
157694b49d53SJani Nikula 	enum plane_id plane_id = plane->id;
157794b49d53SJani Nikula 	int level;
157894b49d53SJani Nikula 	bool dirty = false;
157994b49d53SJani Nikula 
158094b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state)) {
158194b49d53SJani Nikula 		dirty |= vlv_raw_plane_wm_set(crtc_state, 0, plane_id, 0);
158294b49d53SJani Nikula 		goto out;
158394b49d53SJani Nikula 	}
158494b49d53SJani Nikula 
158594b49d53SJani Nikula 	for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
158694b49d53SJani Nikula 		struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
158794b49d53SJani Nikula 		int wm = vlv_compute_wm_level(crtc_state, plane_state, level);
158894b49d53SJani Nikula 		int max_wm = plane_id == PLANE_CURSOR ? 63 : 511;
158994b49d53SJani Nikula 
159094b49d53SJani Nikula 		if (wm > max_wm)
159194b49d53SJani Nikula 			break;
159294b49d53SJani Nikula 
159394b49d53SJani Nikula 		dirty |= raw->plane[plane_id] != wm;
159494b49d53SJani Nikula 		raw->plane[plane_id] = wm;
159594b49d53SJani Nikula 	}
159694b49d53SJani Nikula 
159794b49d53SJani Nikula 	/* mark all higher levels as invalid */
159894b49d53SJani Nikula 	dirty |= vlv_raw_plane_wm_set(crtc_state, level, plane_id, USHRT_MAX);
159994b49d53SJani Nikula 
160094b49d53SJani Nikula out:
160194b49d53SJani Nikula 	if (dirty)
160294b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
160394b49d53SJani Nikula 			    "%s watermarks: PM2=%d, PM5=%d, DDR DVFS=%d\n",
160494b49d53SJani Nikula 			    plane->base.name,
160594b49d53SJani Nikula 			    crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2].plane[plane_id],
160694b49d53SJani Nikula 			    crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM5].plane[plane_id],
160794b49d53SJani Nikula 			    crtc_state->wm.vlv.raw[VLV_WM_LEVEL_DDR_DVFS].plane[plane_id]);
160894b49d53SJani Nikula 
160994b49d53SJani Nikula 	return dirty;
161094b49d53SJani Nikula }
161194b49d53SJani Nikula 
vlv_raw_plane_wm_is_valid(const struct intel_crtc_state * crtc_state,enum plane_id plane_id,int level)161294b49d53SJani Nikula static bool vlv_raw_plane_wm_is_valid(const struct intel_crtc_state *crtc_state,
161394b49d53SJani Nikula 				      enum plane_id plane_id, int level)
161494b49d53SJani Nikula {
161594b49d53SJani Nikula 	const struct g4x_pipe_wm *raw =
161694b49d53SJani Nikula 		&crtc_state->wm.vlv.raw[level];
161794b49d53SJani Nikula 	const struct vlv_fifo_state *fifo_state =
161894b49d53SJani Nikula 		&crtc_state->wm.vlv.fifo_state;
161994b49d53SJani Nikula 
162094b49d53SJani Nikula 	return raw->plane[plane_id] <= fifo_state->plane[plane_id];
162194b49d53SJani Nikula }
162294b49d53SJani Nikula 
vlv_raw_crtc_wm_is_valid(const struct intel_crtc_state * crtc_state,int level)162394b49d53SJani Nikula static bool vlv_raw_crtc_wm_is_valid(const struct intel_crtc_state *crtc_state, int level)
162494b49d53SJani Nikula {
162594b49d53SJani Nikula 	return vlv_raw_plane_wm_is_valid(crtc_state, PLANE_PRIMARY, level) &&
162694b49d53SJani Nikula 		vlv_raw_plane_wm_is_valid(crtc_state, PLANE_SPRITE0, level) &&
162794b49d53SJani Nikula 		vlv_raw_plane_wm_is_valid(crtc_state, PLANE_SPRITE1, level) &&
162894b49d53SJani Nikula 		vlv_raw_plane_wm_is_valid(crtc_state, PLANE_CURSOR, level);
162994b49d53SJani Nikula }
163094b49d53SJani Nikula 
_vlv_compute_pipe_wm(struct intel_crtc_state * crtc_state)163194b49d53SJani Nikula static int _vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state)
163294b49d53SJani Nikula {
163394b49d53SJani Nikula 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
163494b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
163594b49d53SJani Nikula 	struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
163694b49d53SJani Nikula 	const struct vlv_fifo_state *fifo_state =
163794b49d53SJani Nikula 		&crtc_state->wm.vlv.fifo_state;
163894b49d53SJani Nikula 	u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
163994b49d53SJani Nikula 	int num_active_planes = hweight8(active_planes);
164094b49d53SJani Nikula 	enum plane_id plane_id;
164194b49d53SJani Nikula 	int level;
164294b49d53SJani Nikula 
164394b49d53SJani Nikula 	/* initially allow all levels */
164494b49d53SJani Nikula 	wm_state->num_levels = dev_priv->display.wm.num_levels;
164594b49d53SJani Nikula 	/*
164694b49d53SJani Nikula 	 * Note that enabling cxsr with no primary/sprite planes
164794b49d53SJani Nikula 	 * enabled can wedge the pipe. Hence we only allow cxsr
164894b49d53SJani Nikula 	 * with exactly one enabled primary/sprite plane.
164994b49d53SJani Nikula 	 */
165094b49d53SJani Nikula 	wm_state->cxsr = crtc->pipe != PIPE_C && num_active_planes == 1;
165194b49d53SJani Nikula 
165294b49d53SJani Nikula 	for (level = 0; level < wm_state->num_levels; level++) {
165394b49d53SJani Nikula 		const struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
165494b49d53SJani Nikula 		const int sr_fifo_size = INTEL_NUM_PIPES(dev_priv) * 512 - 1;
165594b49d53SJani Nikula 
165694b49d53SJani Nikula 		if (!vlv_raw_crtc_wm_is_valid(crtc_state, level))
165794b49d53SJani Nikula 			break;
165894b49d53SJani Nikula 
165994b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id) {
166094b49d53SJani Nikula 			wm_state->wm[level].plane[plane_id] =
166194b49d53SJani Nikula 				vlv_invert_wm_value(raw->plane[plane_id],
166294b49d53SJani Nikula 						    fifo_state->plane[plane_id]);
166394b49d53SJani Nikula 		}
166494b49d53SJani Nikula 
166594b49d53SJani Nikula 		wm_state->sr[level].plane =
166694b49d53SJani Nikula 			vlv_invert_wm_value(max3(raw->plane[PLANE_PRIMARY],
166794b49d53SJani Nikula 						 raw->plane[PLANE_SPRITE0],
166894b49d53SJani Nikula 						 raw->plane[PLANE_SPRITE1]),
166994b49d53SJani Nikula 					    sr_fifo_size);
167094b49d53SJani Nikula 
167194b49d53SJani Nikula 		wm_state->sr[level].cursor =
167294b49d53SJani Nikula 			vlv_invert_wm_value(raw->plane[PLANE_CURSOR],
167394b49d53SJani Nikula 					    63);
167494b49d53SJani Nikula 	}
167594b49d53SJani Nikula 
167694b49d53SJani Nikula 	if (level == 0)
167794b49d53SJani Nikula 		return -EINVAL;
167894b49d53SJani Nikula 
167994b49d53SJani Nikula 	/* limit to only levels we can actually handle */
168094b49d53SJani Nikula 	wm_state->num_levels = level;
168194b49d53SJani Nikula 
168294b49d53SJani Nikula 	/* invalidate the higher levels */
168394b49d53SJani Nikula 	vlv_invalidate_wms(crtc, wm_state, level);
168494b49d53SJani Nikula 
168594b49d53SJani Nikula 	return 0;
168694b49d53SJani Nikula }
168794b49d53SJani Nikula 
vlv_compute_pipe_wm(struct intel_atomic_state * state,struct intel_crtc * crtc)168894b49d53SJani Nikula static int vlv_compute_pipe_wm(struct intel_atomic_state *state,
168994b49d53SJani Nikula 			       struct intel_crtc *crtc)
169094b49d53SJani Nikula {
169194b49d53SJani Nikula 	struct intel_crtc_state *crtc_state =
169294b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
169394b49d53SJani Nikula 	const struct intel_plane_state *old_plane_state;
169494b49d53SJani Nikula 	const struct intel_plane_state *new_plane_state;
169594b49d53SJani Nikula 	struct intel_plane *plane;
169694b49d53SJani Nikula 	unsigned int dirty = 0;
169794b49d53SJani Nikula 	int i;
169894b49d53SJani Nikula 
169994b49d53SJani Nikula 	for_each_oldnew_intel_plane_in_state(state, plane,
170094b49d53SJani Nikula 					     old_plane_state,
170194b49d53SJani Nikula 					     new_plane_state, i) {
170294b49d53SJani Nikula 		if (new_plane_state->hw.crtc != &crtc->base &&
170394b49d53SJani Nikula 		    old_plane_state->hw.crtc != &crtc->base)
170494b49d53SJani Nikula 			continue;
170594b49d53SJani Nikula 
170694b49d53SJani Nikula 		if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state))
170794b49d53SJani Nikula 			dirty |= BIT(plane->id);
170894b49d53SJani Nikula 	}
170994b49d53SJani Nikula 
171094b49d53SJani Nikula 	/*
171194b49d53SJani Nikula 	 * DSPARB registers may have been reset due to the
171294b49d53SJani Nikula 	 * power well being turned off. Make sure we restore
171394b49d53SJani Nikula 	 * them to a consistent state even if no primary/sprite
171494b49d53SJani Nikula 	 * planes are initially active. We also force a FIFO
171594b49d53SJani Nikula 	 * recomputation so that we are sure to sanitize the
171694b49d53SJani Nikula 	 * FIFO setting we took over from the BIOS even if there
171794b49d53SJani Nikula 	 * are no active planes on the crtc.
171894b49d53SJani Nikula 	 */
171994b49d53SJani Nikula 	if (intel_crtc_needs_modeset(crtc_state))
172094b49d53SJani Nikula 		dirty = ~0;
172194b49d53SJani Nikula 
172294b49d53SJani Nikula 	if (!dirty)
172394b49d53SJani Nikula 		return 0;
172494b49d53SJani Nikula 
172594b49d53SJani Nikula 	/* cursor changes don't warrant a FIFO recompute */
172694b49d53SJani Nikula 	if (dirty & ~BIT(PLANE_CURSOR)) {
172794b49d53SJani Nikula 		const struct intel_crtc_state *old_crtc_state =
172894b49d53SJani Nikula 			intel_atomic_get_old_crtc_state(state, crtc);
172994b49d53SJani Nikula 		const struct vlv_fifo_state *old_fifo_state =
173094b49d53SJani Nikula 			&old_crtc_state->wm.vlv.fifo_state;
173194b49d53SJani Nikula 		const struct vlv_fifo_state *new_fifo_state =
173294b49d53SJani Nikula 			&crtc_state->wm.vlv.fifo_state;
173394b49d53SJani Nikula 		int ret;
173494b49d53SJani Nikula 
173594b49d53SJani Nikula 		ret = vlv_compute_fifo(crtc_state);
173694b49d53SJani Nikula 		if (ret)
173794b49d53SJani Nikula 			return ret;
173894b49d53SJani Nikula 
173994b49d53SJani Nikula 		if (intel_crtc_needs_modeset(crtc_state) ||
174094b49d53SJani Nikula 		    memcmp(old_fifo_state, new_fifo_state,
174194b49d53SJani Nikula 			   sizeof(*new_fifo_state)) != 0)
174294b49d53SJani Nikula 			crtc_state->fifo_changed = true;
174394b49d53SJani Nikula 	}
174494b49d53SJani Nikula 
174594b49d53SJani Nikula 	return _vlv_compute_pipe_wm(crtc_state);
174694b49d53SJani Nikula }
174794b49d53SJani Nikula 
174894b49d53SJani Nikula #define VLV_FIFO(plane, value) \
174994b49d53SJani Nikula 	(((value) << DSPARB_ ## plane ## _SHIFT_VLV) & DSPARB_ ## plane ## _MASK_VLV)
175094b49d53SJani Nikula 
vlv_atomic_update_fifo(struct intel_atomic_state * state,struct intel_crtc * crtc)175194b49d53SJani Nikula static void vlv_atomic_update_fifo(struct intel_atomic_state *state,
175294b49d53SJani Nikula 				   struct intel_crtc *crtc)
175394b49d53SJani Nikula {
175494b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
175594b49d53SJani Nikula 	struct intel_uncore *uncore = &dev_priv->uncore;
175694b49d53SJani Nikula 	const struct intel_crtc_state *crtc_state =
175794b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
175894b49d53SJani Nikula 	const struct vlv_fifo_state *fifo_state =
175994b49d53SJani Nikula 		&crtc_state->wm.vlv.fifo_state;
176094b49d53SJani Nikula 	int sprite0_start, sprite1_start, fifo_size;
176194b49d53SJani Nikula 	u32 dsparb, dsparb2, dsparb3;
176294b49d53SJani Nikula 
176394b49d53SJani Nikula 	if (!crtc_state->fifo_changed)
176494b49d53SJani Nikula 		return;
176594b49d53SJani Nikula 
176694b49d53SJani Nikula 	sprite0_start = fifo_state->plane[PLANE_PRIMARY];
176794b49d53SJani Nikula 	sprite1_start = fifo_state->plane[PLANE_SPRITE0] + sprite0_start;
176894b49d53SJani Nikula 	fifo_size = fifo_state->plane[PLANE_SPRITE1] + sprite1_start;
176994b49d53SJani Nikula 
177094b49d53SJani Nikula 	drm_WARN_ON(&dev_priv->drm, fifo_state->plane[PLANE_CURSOR] != 63);
177194b49d53SJani Nikula 	drm_WARN_ON(&dev_priv->drm, fifo_size != 511);
177294b49d53SJani Nikula 
177394b49d53SJani Nikula 	trace_vlv_fifo_size(crtc, sprite0_start, sprite1_start, fifo_size);
177494b49d53SJani Nikula 
177594b49d53SJani Nikula 	/*
177694b49d53SJani Nikula 	 * uncore.lock serves a double purpose here. It allows us to
177794b49d53SJani Nikula 	 * use the less expensive I915_{READ,WRITE}_FW() functions, and
177894b49d53SJani Nikula 	 * it protects the DSPARB registers from getting clobbered by
177994b49d53SJani Nikula 	 * parallel updates from multiple pipes.
178094b49d53SJani Nikula 	 *
178194b49d53SJani Nikula 	 * intel_pipe_update_start() has already disabled interrupts
178294b49d53SJani Nikula 	 * for us, so a plain spin_lock() is sufficient here.
178394b49d53SJani Nikula 	 */
178494b49d53SJani Nikula 	spin_lock(&uncore->lock);
178594b49d53SJani Nikula 
178694b49d53SJani Nikula 	switch (crtc->pipe) {
178794b49d53SJani Nikula 	case PIPE_A:
178894b49d53SJani Nikula 		dsparb = intel_uncore_read_fw(uncore, DSPARB);
178994b49d53SJani Nikula 		dsparb2 = intel_uncore_read_fw(uncore, DSPARB2);
179094b49d53SJani Nikula 
179194b49d53SJani Nikula 		dsparb &= ~(VLV_FIFO(SPRITEA, 0xff) |
179294b49d53SJani Nikula 			    VLV_FIFO(SPRITEB, 0xff));
179394b49d53SJani Nikula 		dsparb |= (VLV_FIFO(SPRITEA, sprite0_start) |
179494b49d53SJani Nikula 			   VLV_FIFO(SPRITEB, sprite1_start));
179594b49d53SJani Nikula 
179694b49d53SJani Nikula 		dsparb2 &= ~(VLV_FIFO(SPRITEA_HI, 0x1) |
179794b49d53SJani Nikula 			     VLV_FIFO(SPRITEB_HI, 0x1));
179894b49d53SJani Nikula 		dsparb2 |= (VLV_FIFO(SPRITEA_HI, sprite0_start >> 8) |
179994b49d53SJani Nikula 			   VLV_FIFO(SPRITEB_HI, sprite1_start >> 8));
180094b49d53SJani Nikula 
180194b49d53SJani Nikula 		intel_uncore_write_fw(uncore, DSPARB, dsparb);
180294b49d53SJani Nikula 		intel_uncore_write_fw(uncore, DSPARB2, dsparb2);
180394b49d53SJani Nikula 		break;
180494b49d53SJani Nikula 	case PIPE_B:
180594b49d53SJani Nikula 		dsparb = intel_uncore_read_fw(uncore, DSPARB);
180694b49d53SJani Nikula 		dsparb2 = intel_uncore_read_fw(uncore, DSPARB2);
180794b49d53SJani Nikula 
180894b49d53SJani Nikula 		dsparb &= ~(VLV_FIFO(SPRITEC, 0xff) |
180994b49d53SJani Nikula 			    VLV_FIFO(SPRITED, 0xff));
181094b49d53SJani Nikula 		dsparb |= (VLV_FIFO(SPRITEC, sprite0_start) |
181194b49d53SJani Nikula 			   VLV_FIFO(SPRITED, sprite1_start));
181294b49d53SJani Nikula 
181394b49d53SJani Nikula 		dsparb2 &= ~(VLV_FIFO(SPRITEC_HI, 0xff) |
181494b49d53SJani Nikula 			     VLV_FIFO(SPRITED_HI, 0xff));
181594b49d53SJani Nikula 		dsparb2 |= (VLV_FIFO(SPRITEC_HI, sprite0_start >> 8) |
181694b49d53SJani Nikula 			   VLV_FIFO(SPRITED_HI, sprite1_start >> 8));
181794b49d53SJani Nikula 
181894b49d53SJani Nikula 		intel_uncore_write_fw(uncore, DSPARB, dsparb);
181994b49d53SJani Nikula 		intel_uncore_write_fw(uncore, DSPARB2, dsparb2);
182094b49d53SJani Nikula 		break;
182194b49d53SJani Nikula 	case PIPE_C:
182294b49d53SJani Nikula 		dsparb3 = intel_uncore_read_fw(uncore, DSPARB3);
182394b49d53SJani Nikula 		dsparb2 = intel_uncore_read_fw(uncore, DSPARB2);
182494b49d53SJani Nikula 
182594b49d53SJani Nikula 		dsparb3 &= ~(VLV_FIFO(SPRITEE, 0xff) |
182694b49d53SJani Nikula 			     VLV_FIFO(SPRITEF, 0xff));
182794b49d53SJani Nikula 		dsparb3 |= (VLV_FIFO(SPRITEE, sprite0_start) |
182894b49d53SJani Nikula 			    VLV_FIFO(SPRITEF, sprite1_start));
182994b49d53SJani Nikula 
183094b49d53SJani Nikula 		dsparb2 &= ~(VLV_FIFO(SPRITEE_HI, 0xff) |
183194b49d53SJani Nikula 			     VLV_FIFO(SPRITEF_HI, 0xff));
183294b49d53SJani Nikula 		dsparb2 |= (VLV_FIFO(SPRITEE_HI, sprite0_start >> 8) |
183394b49d53SJani Nikula 			   VLV_FIFO(SPRITEF_HI, sprite1_start >> 8));
183494b49d53SJani Nikula 
183594b49d53SJani Nikula 		intel_uncore_write_fw(uncore, DSPARB3, dsparb3);
183694b49d53SJani Nikula 		intel_uncore_write_fw(uncore, DSPARB2, dsparb2);
183794b49d53SJani Nikula 		break;
183894b49d53SJani Nikula 	default:
183994b49d53SJani Nikula 		break;
184094b49d53SJani Nikula 	}
184194b49d53SJani Nikula 
184294b49d53SJani Nikula 	intel_uncore_posting_read_fw(uncore, DSPARB);
184394b49d53SJani Nikula 
184494b49d53SJani Nikula 	spin_unlock(&uncore->lock);
184594b49d53SJani Nikula }
184694b49d53SJani Nikula 
184794b49d53SJani Nikula #undef VLV_FIFO
184894b49d53SJani Nikula 
vlv_compute_intermediate_wm(struct intel_atomic_state * state,struct intel_crtc * crtc)184994b49d53SJani Nikula static int vlv_compute_intermediate_wm(struct intel_atomic_state *state,
185094b49d53SJani Nikula 				       struct intel_crtc *crtc)
185194b49d53SJani Nikula {
185294b49d53SJani Nikula 	struct intel_crtc_state *new_crtc_state =
185394b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
185494b49d53SJani Nikula 	const struct intel_crtc_state *old_crtc_state =
185594b49d53SJani Nikula 		intel_atomic_get_old_crtc_state(state, crtc);
185694b49d53SJani Nikula 	struct vlv_wm_state *intermediate = &new_crtc_state->wm.vlv.intermediate;
185794b49d53SJani Nikula 	const struct vlv_wm_state *optimal = &new_crtc_state->wm.vlv.optimal;
185894b49d53SJani Nikula 	const struct vlv_wm_state *active = &old_crtc_state->wm.vlv.optimal;
185994b49d53SJani Nikula 	int level;
186094b49d53SJani Nikula 
186194b49d53SJani Nikula 	if (!new_crtc_state->hw.active ||
186294b49d53SJani Nikula 	    intel_crtc_needs_modeset(new_crtc_state)) {
186394b49d53SJani Nikula 		*intermediate = *optimal;
186494b49d53SJani Nikula 
186594b49d53SJani Nikula 		intermediate->cxsr = false;
186694b49d53SJani Nikula 		goto out;
186794b49d53SJani Nikula 	}
186894b49d53SJani Nikula 
186994b49d53SJani Nikula 	intermediate->num_levels = min(optimal->num_levels, active->num_levels);
187094b49d53SJani Nikula 	intermediate->cxsr = optimal->cxsr && active->cxsr &&
187194b49d53SJani Nikula 		!new_crtc_state->disable_cxsr;
187294b49d53SJani Nikula 
187394b49d53SJani Nikula 	for (level = 0; level < intermediate->num_levels; level++) {
187494b49d53SJani Nikula 		enum plane_id plane_id;
187594b49d53SJani Nikula 
187694b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id) {
187794b49d53SJani Nikula 			intermediate->wm[level].plane[plane_id] =
187894b49d53SJani Nikula 				min(optimal->wm[level].plane[plane_id],
187994b49d53SJani Nikula 				    active->wm[level].plane[plane_id]);
188094b49d53SJani Nikula 		}
188194b49d53SJani Nikula 
188294b49d53SJani Nikula 		intermediate->sr[level].plane = min(optimal->sr[level].plane,
188394b49d53SJani Nikula 						    active->sr[level].plane);
188494b49d53SJani Nikula 		intermediate->sr[level].cursor = min(optimal->sr[level].cursor,
188594b49d53SJani Nikula 						     active->sr[level].cursor);
188694b49d53SJani Nikula 	}
188794b49d53SJani Nikula 
188894b49d53SJani Nikula 	vlv_invalidate_wms(crtc, intermediate, level);
188994b49d53SJani Nikula 
189094b49d53SJani Nikula out:
189194b49d53SJani Nikula 	/*
189294b49d53SJani Nikula 	 * If our intermediate WM are identical to the final WM, then we can
189394b49d53SJani Nikula 	 * omit the post-vblank programming; only update if it's different.
189494b49d53SJani Nikula 	 */
189594b49d53SJani Nikula 	if (memcmp(intermediate, optimal, sizeof(*intermediate)) != 0)
189694b49d53SJani Nikula 		new_crtc_state->wm.need_postvbl_update = true;
189794b49d53SJani Nikula 
189894b49d53SJani Nikula 	return 0;
189994b49d53SJani Nikula }
190094b49d53SJani Nikula 
vlv_merge_wm(struct drm_i915_private * dev_priv,struct vlv_wm_values * wm)190194b49d53SJani Nikula static void vlv_merge_wm(struct drm_i915_private *dev_priv,
190294b49d53SJani Nikula 			 struct vlv_wm_values *wm)
190394b49d53SJani Nikula {
190494b49d53SJani Nikula 	struct intel_crtc *crtc;
190594b49d53SJani Nikula 	int num_active_pipes = 0;
190694b49d53SJani Nikula 
190794b49d53SJani Nikula 	wm->level = dev_priv->display.wm.num_levels - 1;
190894b49d53SJani Nikula 	wm->cxsr = true;
190994b49d53SJani Nikula 
191094b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
191194b49d53SJani Nikula 		const struct vlv_wm_state *wm_state = &crtc->wm.active.vlv;
191294b49d53SJani Nikula 
191394b49d53SJani Nikula 		if (!crtc->active)
191494b49d53SJani Nikula 			continue;
191594b49d53SJani Nikula 
191694b49d53SJani Nikula 		if (!wm_state->cxsr)
191794b49d53SJani Nikula 			wm->cxsr = false;
191894b49d53SJani Nikula 
191994b49d53SJani Nikula 		num_active_pipes++;
192094b49d53SJani Nikula 		wm->level = min_t(int, wm->level, wm_state->num_levels - 1);
192194b49d53SJani Nikula 	}
192294b49d53SJani Nikula 
192394b49d53SJani Nikula 	if (num_active_pipes != 1)
192494b49d53SJani Nikula 		wm->cxsr = false;
192594b49d53SJani Nikula 
192694b49d53SJani Nikula 	if (num_active_pipes > 1)
192794b49d53SJani Nikula 		wm->level = VLV_WM_LEVEL_PM2;
192894b49d53SJani Nikula 
192994b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
193094b49d53SJani Nikula 		const struct vlv_wm_state *wm_state = &crtc->wm.active.vlv;
193194b49d53SJani Nikula 		enum pipe pipe = crtc->pipe;
193294b49d53SJani Nikula 
193394b49d53SJani Nikula 		wm->pipe[pipe] = wm_state->wm[wm->level];
193494b49d53SJani Nikula 		if (crtc->active && wm->cxsr)
193594b49d53SJani Nikula 			wm->sr = wm_state->sr[wm->level];
193694b49d53SJani Nikula 
193794b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_PRIMARY] = DDL_PRECISION_HIGH | 2;
193894b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_SPRITE0] = DDL_PRECISION_HIGH | 2;
193994b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_SPRITE1] = DDL_PRECISION_HIGH | 2;
194094b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_CURSOR] = DDL_PRECISION_HIGH | 2;
194194b49d53SJani Nikula 	}
194294b49d53SJani Nikula }
194394b49d53SJani Nikula 
vlv_program_watermarks(struct drm_i915_private * dev_priv)194494b49d53SJani Nikula static void vlv_program_watermarks(struct drm_i915_private *dev_priv)
194594b49d53SJani Nikula {
194694b49d53SJani Nikula 	struct vlv_wm_values *old_wm = &dev_priv->display.wm.vlv;
194794b49d53SJani Nikula 	struct vlv_wm_values new_wm = {};
194894b49d53SJani Nikula 
194994b49d53SJani Nikula 	vlv_merge_wm(dev_priv, &new_wm);
195094b49d53SJani Nikula 
195194b49d53SJani Nikula 	if (memcmp(old_wm, &new_wm, sizeof(new_wm)) == 0)
195294b49d53SJani Nikula 		return;
195394b49d53SJani Nikula 
195494b49d53SJani Nikula 	if (is_disabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_DDR_DVFS))
195594b49d53SJani Nikula 		chv_set_memory_dvfs(dev_priv, false);
195694b49d53SJani Nikula 
195794b49d53SJani Nikula 	if (is_disabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_PM5))
195894b49d53SJani Nikula 		chv_set_memory_pm5(dev_priv, false);
195994b49d53SJani Nikula 
196094b49d53SJani Nikula 	if (is_disabling(old_wm->cxsr, new_wm.cxsr, true))
196194b49d53SJani Nikula 		_intel_set_memory_cxsr(dev_priv, false);
196294b49d53SJani Nikula 
196394b49d53SJani Nikula 	vlv_write_wm_values(dev_priv, &new_wm);
196494b49d53SJani Nikula 
196594b49d53SJani Nikula 	if (is_enabling(old_wm->cxsr, new_wm.cxsr, true))
196694b49d53SJani Nikula 		_intel_set_memory_cxsr(dev_priv, true);
196794b49d53SJani Nikula 
196894b49d53SJani Nikula 	if (is_enabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_PM5))
196994b49d53SJani Nikula 		chv_set_memory_pm5(dev_priv, true);
197094b49d53SJani Nikula 
197194b49d53SJani Nikula 	if (is_enabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_DDR_DVFS))
197294b49d53SJani Nikula 		chv_set_memory_dvfs(dev_priv, true);
197394b49d53SJani Nikula 
197494b49d53SJani Nikula 	*old_wm = new_wm;
197594b49d53SJani Nikula }
197694b49d53SJani Nikula 
vlv_initial_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)197794b49d53SJani Nikula static void vlv_initial_watermarks(struct intel_atomic_state *state,
197894b49d53SJani Nikula 				   struct intel_crtc *crtc)
197994b49d53SJani Nikula {
198094b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
198194b49d53SJani Nikula 	const struct intel_crtc_state *crtc_state =
198294b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
198394b49d53SJani Nikula 
198494b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
198594b49d53SJani Nikula 	crtc->wm.active.vlv = crtc_state->wm.vlv.intermediate;
198694b49d53SJani Nikula 	vlv_program_watermarks(dev_priv);
198794b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
198894b49d53SJani Nikula }
198994b49d53SJani Nikula 
vlv_optimize_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)199094b49d53SJani Nikula static void vlv_optimize_watermarks(struct intel_atomic_state *state,
199194b49d53SJani Nikula 				    struct intel_crtc *crtc)
199294b49d53SJani Nikula {
199394b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
199494b49d53SJani Nikula 	const struct intel_crtc_state *crtc_state =
199594b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
199694b49d53SJani Nikula 
199794b49d53SJani Nikula 	if (!crtc_state->wm.need_postvbl_update)
199894b49d53SJani Nikula 		return;
199994b49d53SJani Nikula 
200094b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
200194b49d53SJani Nikula 	crtc->wm.active.vlv = crtc_state->wm.vlv.optimal;
200294b49d53SJani Nikula 	vlv_program_watermarks(dev_priv);
200394b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
200494b49d53SJani Nikula }
200594b49d53SJani Nikula 
i965_update_wm(struct drm_i915_private * dev_priv)200694b49d53SJani Nikula static void i965_update_wm(struct drm_i915_private *dev_priv)
200794b49d53SJani Nikula {
200894b49d53SJani Nikula 	struct intel_crtc *crtc;
200994b49d53SJani Nikula 	int srwm = 1;
201094b49d53SJani Nikula 	int cursor_sr = 16;
201194b49d53SJani Nikula 	bool cxsr_enabled;
201294b49d53SJani Nikula 
201394b49d53SJani Nikula 	/* Calc sr entries for one plane configs */
201494b49d53SJani Nikula 	crtc = single_enabled_crtc(dev_priv);
201594b49d53SJani Nikula 	if (crtc) {
201694b49d53SJani Nikula 		/* self-refresh has much higher latency */
201794b49d53SJani Nikula 		static const int sr_latency_ns = 12000;
201894b49d53SJani Nikula 		const struct drm_display_mode *pipe_mode =
201994b49d53SJani Nikula 			&crtc->config->hw.pipe_mode;
202094b49d53SJani Nikula 		const struct drm_framebuffer *fb =
202194b49d53SJani Nikula 			crtc->base.primary->state->fb;
202294b49d53SJani Nikula 		int pixel_rate = crtc->config->pixel_rate;
202394b49d53SJani Nikula 		int htotal = pipe_mode->crtc_htotal;
202494b49d53SJani Nikula 		int width = drm_rect_width(&crtc->base.primary->state->src) >> 16;
202594b49d53SJani Nikula 		int cpp = fb->format->cpp[0];
202694b49d53SJani Nikula 		int entries;
202794b49d53SJani Nikula 
202894b49d53SJani Nikula 		entries = intel_wm_method2(pixel_rate, htotal,
202994b49d53SJani Nikula 					   width, cpp, sr_latency_ns / 100);
203094b49d53SJani Nikula 		entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
203194b49d53SJani Nikula 		srwm = I965_FIFO_SIZE - entries;
203294b49d53SJani Nikula 		if (srwm < 0)
203394b49d53SJani Nikula 			srwm = 1;
203494b49d53SJani Nikula 		srwm &= 0x1ff;
203594b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
203694b49d53SJani Nikula 			    "self-refresh entries: %d, wm: %d\n",
203794b49d53SJani Nikula 			    entries, srwm);
203894b49d53SJani Nikula 
203994b49d53SJani Nikula 		entries = intel_wm_method2(pixel_rate, htotal,
204094b49d53SJani Nikula 					   crtc->base.cursor->state->crtc_w, 4,
204194b49d53SJani Nikula 					   sr_latency_ns / 100);
204294b49d53SJani Nikula 		entries = DIV_ROUND_UP(entries,
204394b49d53SJani Nikula 				       i965_cursor_wm_info.cacheline_size) +
204494b49d53SJani Nikula 			i965_cursor_wm_info.guard_size;
204594b49d53SJani Nikula 
204694b49d53SJani Nikula 		cursor_sr = i965_cursor_wm_info.fifo_size - entries;
204794b49d53SJani Nikula 		if (cursor_sr > i965_cursor_wm_info.max_wm)
204894b49d53SJani Nikula 			cursor_sr = i965_cursor_wm_info.max_wm;
204994b49d53SJani Nikula 
205094b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
205194b49d53SJani Nikula 			    "self-refresh watermark: display plane %d "
205294b49d53SJani Nikula 			    "cursor %d\n", srwm, cursor_sr);
205394b49d53SJani Nikula 
205494b49d53SJani Nikula 		cxsr_enabled = true;
205594b49d53SJani Nikula 	} else {
205694b49d53SJani Nikula 		cxsr_enabled = false;
205794b49d53SJani Nikula 		/* Turn off self refresh if both pipes are enabled */
205894b49d53SJani Nikula 		intel_set_memory_cxsr(dev_priv, false);
205994b49d53SJani Nikula 	}
206094b49d53SJani Nikula 
206194b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
206294b49d53SJani Nikula 		    "Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
206394b49d53SJani Nikula 		    srwm);
206494b49d53SJani Nikula 
206594b49d53SJani Nikula 	/* 965 has limitations... */
206694b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW1, FW_WM(srwm, SR) |
206794b49d53SJani Nikula 		   FW_WM(8, CURSORB) |
206894b49d53SJani Nikula 		   FW_WM(8, PLANEB) |
206994b49d53SJani Nikula 		   FW_WM(8, PLANEA));
207094b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW2, FW_WM(8, CURSORA) |
207194b49d53SJani Nikula 		   FW_WM(8, PLANEC_OLD));
207294b49d53SJani Nikula 	/* update cursor SR watermark */
207394b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, DSPFW3, FW_WM(cursor_sr, CURSOR_SR));
207494b49d53SJani Nikula 
207594b49d53SJani Nikula 	if (cxsr_enabled)
207694b49d53SJani Nikula 		intel_set_memory_cxsr(dev_priv, true);
207794b49d53SJani Nikula }
207894b49d53SJani Nikula 
207994b49d53SJani Nikula #undef FW_WM
208094b49d53SJani Nikula 
intel_crtc_for_plane(struct drm_i915_private * i915,enum i9xx_plane_id i9xx_plane)208194b49d53SJani Nikula static struct intel_crtc *intel_crtc_for_plane(struct drm_i915_private *i915,
208294b49d53SJani Nikula 					       enum i9xx_plane_id i9xx_plane)
208394b49d53SJani Nikula {
208494b49d53SJani Nikula 	struct intel_plane *plane;
208594b49d53SJani Nikula 
208694b49d53SJani Nikula 	for_each_intel_plane(&i915->drm, plane) {
208794b49d53SJani Nikula 		if (plane->id == PLANE_PRIMARY &&
208894b49d53SJani Nikula 		    plane->i9xx_plane == i9xx_plane)
208994b49d53SJani Nikula 			return intel_crtc_for_pipe(i915, plane->pipe);
209094b49d53SJani Nikula 	}
209194b49d53SJani Nikula 
209294b49d53SJani Nikula 	return NULL;
209394b49d53SJani Nikula }
209494b49d53SJani Nikula 
i9xx_update_wm(struct drm_i915_private * dev_priv)209594b49d53SJani Nikula static void i9xx_update_wm(struct drm_i915_private *dev_priv)
209694b49d53SJani Nikula {
209794b49d53SJani Nikula 	const struct intel_watermark_params *wm_info;
209894b49d53SJani Nikula 	u32 fwater_lo;
209994b49d53SJani Nikula 	u32 fwater_hi;
210094b49d53SJani Nikula 	int cwm, srwm = 1;
210194b49d53SJani Nikula 	int fifo_size;
210294b49d53SJani Nikula 	int planea_wm, planeb_wm;
210394b49d53SJani Nikula 	struct intel_crtc *crtc;
210494b49d53SJani Nikula 
210594b49d53SJani Nikula 	if (IS_I945GM(dev_priv))
210694b49d53SJani Nikula 		wm_info = &i945_wm_info;
210794b49d53SJani Nikula 	else if (DISPLAY_VER(dev_priv) != 2)
210894b49d53SJani Nikula 		wm_info = &i915_wm_info;
210994b49d53SJani Nikula 	else
211094b49d53SJani Nikula 		wm_info = &i830_a_wm_info;
211194b49d53SJani Nikula 
211294b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) == 2)
211394b49d53SJani Nikula 		fifo_size = i830_get_fifo_size(dev_priv, PLANE_A);
211494b49d53SJani Nikula 	else
211594b49d53SJani Nikula 		fifo_size = i9xx_get_fifo_size(dev_priv, PLANE_A);
211694b49d53SJani Nikula 	crtc = intel_crtc_for_plane(dev_priv, PLANE_A);
211794b49d53SJani Nikula 	if (intel_crtc_active(crtc)) {
211894b49d53SJani Nikula 		const struct drm_framebuffer *fb =
211994b49d53SJani Nikula 			crtc->base.primary->state->fb;
212094b49d53SJani Nikula 		int cpp;
212194b49d53SJani Nikula 
212294b49d53SJani Nikula 		if (DISPLAY_VER(dev_priv) == 2)
212394b49d53SJani Nikula 			cpp = 4;
212494b49d53SJani Nikula 		else
212594b49d53SJani Nikula 			cpp = fb->format->cpp[0];
212694b49d53SJani Nikula 
212794b49d53SJani Nikula 		planea_wm = intel_calculate_wm(crtc->config->pixel_rate,
212894b49d53SJani Nikula 					       wm_info, fifo_size, cpp,
212994b49d53SJani Nikula 					       pessimal_latency_ns);
213094b49d53SJani Nikula 	} else {
213194b49d53SJani Nikula 		planea_wm = fifo_size - wm_info->guard_size;
213294b49d53SJani Nikula 		if (planea_wm > (long)wm_info->max_wm)
213394b49d53SJani Nikula 			planea_wm = wm_info->max_wm;
213494b49d53SJani Nikula 	}
213594b49d53SJani Nikula 
213694b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) == 2)
213794b49d53SJani Nikula 		wm_info = &i830_bc_wm_info;
213894b49d53SJani Nikula 
213994b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) == 2)
214094b49d53SJani Nikula 		fifo_size = i830_get_fifo_size(dev_priv, PLANE_B);
214194b49d53SJani Nikula 	else
214294b49d53SJani Nikula 		fifo_size = i9xx_get_fifo_size(dev_priv, PLANE_B);
214394b49d53SJani Nikula 	crtc = intel_crtc_for_plane(dev_priv, PLANE_B);
214494b49d53SJani Nikula 	if (intel_crtc_active(crtc)) {
214594b49d53SJani Nikula 		const struct drm_framebuffer *fb =
214694b49d53SJani Nikula 			crtc->base.primary->state->fb;
214794b49d53SJani Nikula 		int cpp;
214894b49d53SJani Nikula 
214994b49d53SJani Nikula 		if (DISPLAY_VER(dev_priv) == 2)
215094b49d53SJani Nikula 			cpp = 4;
215194b49d53SJani Nikula 		else
215294b49d53SJani Nikula 			cpp = fb->format->cpp[0];
215394b49d53SJani Nikula 
215494b49d53SJani Nikula 		planeb_wm = intel_calculate_wm(crtc->config->pixel_rate,
215594b49d53SJani Nikula 					       wm_info, fifo_size, cpp,
215694b49d53SJani Nikula 					       pessimal_latency_ns);
215794b49d53SJani Nikula 	} else {
215894b49d53SJani Nikula 		planeb_wm = fifo_size - wm_info->guard_size;
215994b49d53SJani Nikula 		if (planeb_wm > (long)wm_info->max_wm)
216094b49d53SJani Nikula 			planeb_wm = wm_info->max_wm;
216194b49d53SJani Nikula 	}
216294b49d53SJani Nikula 
216394b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
216494b49d53SJani Nikula 		    "FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
216594b49d53SJani Nikula 
216694b49d53SJani Nikula 	crtc = single_enabled_crtc(dev_priv);
216794b49d53SJani Nikula 	if (IS_I915GM(dev_priv) && crtc) {
216894b49d53SJani Nikula 		struct drm_i915_gem_object *obj;
216994b49d53SJani Nikula 
217094b49d53SJani Nikula 		obj = intel_fb_obj(crtc->base.primary->state->fb);
217194b49d53SJani Nikula 
217294b49d53SJani Nikula 		/* self-refresh seems busted with untiled */
217394b49d53SJani Nikula 		if (!i915_gem_object_is_tiled(obj))
217494b49d53SJani Nikula 			crtc = NULL;
217594b49d53SJani Nikula 	}
217694b49d53SJani Nikula 
217794b49d53SJani Nikula 	/*
217894b49d53SJani Nikula 	 * Overlay gets an aggressive default since video jitter is bad.
217994b49d53SJani Nikula 	 */
218094b49d53SJani Nikula 	cwm = 2;
218194b49d53SJani Nikula 
218294b49d53SJani Nikula 	/* Play safe and disable self-refresh before adjusting watermarks. */
218394b49d53SJani Nikula 	intel_set_memory_cxsr(dev_priv, false);
218494b49d53SJani Nikula 
218594b49d53SJani Nikula 	/* Calc sr entries for one plane configs */
218694b49d53SJani Nikula 	if (HAS_FW_BLC(dev_priv) && crtc) {
218794b49d53SJani Nikula 		/* self-refresh has much higher latency */
218894b49d53SJani Nikula 		static const int sr_latency_ns = 6000;
218994b49d53SJani Nikula 		const struct drm_display_mode *pipe_mode =
219094b49d53SJani Nikula 			&crtc->config->hw.pipe_mode;
219194b49d53SJani Nikula 		const struct drm_framebuffer *fb =
219294b49d53SJani Nikula 			crtc->base.primary->state->fb;
219394b49d53SJani Nikula 		int pixel_rate = crtc->config->pixel_rate;
219494b49d53SJani Nikula 		int htotal = pipe_mode->crtc_htotal;
219594b49d53SJani Nikula 		int width = drm_rect_width(&crtc->base.primary->state->src) >> 16;
219694b49d53SJani Nikula 		int cpp;
219794b49d53SJani Nikula 		int entries;
219894b49d53SJani Nikula 
219994b49d53SJani Nikula 		if (IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
220094b49d53SJani Nikula 			cpp = 4;
220194b49d53SJani Nikula 		else
220294b49d53SJani Nikula 			cpp = fb->format->cpp[0];
220394b49d53SJani Nikula 
220494b49d53SJani Nikula 		entries = intel_wm_method2(pixel_rate, htotal, width, cpp,
220594b49d53SJani Nikula 					   sr_latency_ns / 100);
220694b49d53SJani Nikula 		entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
220794b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
220894b49d53SJani Nikula 			    "self-refresh entries: %d\n", entries);
220994b49d53SJani Nikula 		srwm = wm_info->fifo_size - entries;
221094b49d53SJani Nikula 		if (srwm < 0)
221194b49d53SJani Nikula 			srwm = 1;
221294b49d53SJani Nikula 
221394b49d53SJani Nikula 		if (IS_I945G(dev_priv) || IS_I945GM(dev_priv))
221494b49d53SJani Nikula 			intel_uncore_write(&dev_priv->uncore, FW_BLC_SELF,
221594b49d53SJani Nikula 				   FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
221694b49d53SJani Nikula 		else
221794b49d53SJani Nikula 			intel_uncore_write(&dev_priv->uncore, FW_BLC_SELF, srwm & 0x3f);
221894b49d53SJani Nikula 	}
221994b49d53SJani Nikula 
222094b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
222194b49d53SJani Nikula 		    "Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
222294b49d53SJani Nikula 		     planea_wm, planeb_wm, cwm, srwm);
222394b49d53SJani Nikula 
222494b49d53SJani Nikula 	fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
222594b49d53SJani Nikula 	fwater_hi = (cwm & 0x1f);
222694b49d53SJani Nikula 
222794b49d53SJani Nikula 	/* Set request length to 8 cachelines per fetch */
222894b49d53SJani Nikula 	fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
222994b49d53SJani Nikula 	fwater_hi = fwater_hi | (1 << 8);
223094b49d53SJani Nikula 
223194b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, FW_BLC, fwater_lo);
223294b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, FW_BLC2, fwater_hi);
223394b49d53SJani Nikula 
223494b49d53SJani Nikula 	if (crtc)
223594b49d53SJani Nikula 		intel_set_memory_cxsr(dev_priv, true);
223694b49d53SJani Nikula }
223794b49d53SJani Nikula 
i845_update_wm(struct drm_i915_private * dev_priv)223894b49d53SJani Nikula static void i845_update_wm(struct drm_i915_private *dev_priv)
223994b49d53SJani Nikula {
224094b49d53SJani Nikula 	struct intel_crtc *crtc;
224194b49d53SJani Nikula 	u32 fwater_lo;
224294b49d53SJani Nikula 	int planea_wm;
224394b49d53SJani Nikula 
224494b49d53SJani Nikula 	crtc = single_enabled_crtc(dev_priv);
224594b49d53SJani Nikula 	if (crtc == NULL)
224694b49d53SJani Nikula 		return;
224794b49d53SJani Nikula 
224894b49d53SJani Nikula 	planea_wm = intel_calculate_wm(crtc->config->pixel_rate,
224994b49d53SJani Nikula 				       &i845_wm_info,
225094b49d53SJani Nikula 				       i845_get_fifo_size(dev_priv, PLANE_A),
225194b49d53SJani Nikula 				       4, pessimal_latency_ns);
225294b49d53SJani Nikula 	fwater_lo = intel_uncore_read(&dev_priv->uncore, FW_BLC) & ~0xfff;
225394b49d53SJani Nikula 	fwater_lo |= (3<<8) | planea_wm;
225494b49d53SJani Nikula 
225594b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
225694b49d53SJani Nikula 		    "Setting FIFO watermarks - A: %d\n", planea_wm);
225794b49d53SJani Nikula 
225894b49d53SJani Nikula 	intel_uncore_write(&dev_priv->uncore, FW_BLC, fwater_lo);
225994b49d53SJani Nikula }
226094b49d53SJani Nikula 
226194b49d53SJani Nikula /* latency must be in 0.1us units. */
ilk_wm_method1(unsigned int pixel_rate,unsigned int cpp,unsigned int latency)226294b49d53SJani Nikula static unsigned int ilk_wm_method1(unsigned int pixel_rate,
226394b49d53SJani Nikula 				   unsigned int cpp,
226494b49d53SJani Nikula 				   unsigned int latency)
226594b49d53SJani Nikula {
226694b49d53SJani Nikula 	unsigned int ret;
226794b49d53SJani Nikula 
226894b49d53SJani Nikula 	ret = intel_wm_method1(pixel_rate, cpp, latency);
226994b49d53SJani Nikula 	ret = DIV_ROUND_UP(ret, 64) + 2;
227094b49d53SJani Nikula 
227194b49d53SJani Nikula 	return ret;
227294b49d53SJani Nikula }
227394b49d53SJani Nikula 
227494b49d53SJani Nikula /* latency must be in 0.1us units. */
ilk_wm_method2(unsigned int pixel_rate,unsigned int htotal,unsigned int width,unsigned int cpp,unsigned int latency)227594b49d53SJani Nikula static unsigned int ilk_wm_method2(unsigned int pixel_rate,
227694b49d53SJani Nikula 				   unsigned int htotal,
227794b49d53SJani Nikula 				   unsigned int width,
227894b49d53SJani Nikula 				   unsigned int cpp,
227994b49d53SJani Nikula 				   unsigned int latency)
228094b49d53SJani Nikula {
228194b49d53SJani Nikula 	unsigned int ret;
228294b49d53SJani Nikula 
228394b49d53SJani Nikula 	ret = intel_wm_method2(pixel_rate, htotal,
228494b49d53SJani Nikula 			       width, cpp, latency);
228594b49d53SJani Nikula 	ret = DIV_ROUND_UP(ret, 64) + 2;
228694b49d53SJani Nikula 
228794b49d53SJani Nikula 	return ret;
228894b49d53SJani Nikula }
228994b49d53SJani Nikula 
ilk_wm_fbc(u32 pri_val,u32 horiz_pixels,u8 cpp)229094b49d53SJani Nikula static u32 ilk_wm_fbc(u32 pri_val, u32 horiz_pixels, u8 cpp)
229194b49d53SJani Nikula {
229294b49d53SJani Nikula 	/*
229394b49d53SJani Nikula 	 * Neither of these should be possible since this function shouldn't be
229494b49d53SJani Nikula 	 * called if the CRTC is off or the plane is invisible.  But let's be
229594b49d53SJani Nikula 	 * extra paranoid to avoid a potential divide-by-zero if we screw up
229694b49d53SJani Nikula 	 * elsewhere in the driver.
229794b49d53SJani Nikula 	 */
229894b49d53SJani Nikula 	if (WARN_ON(!cpp))
229994b49d53SJani Nikula 		return 0;
230094b49d53SJani Nikula 	if (WARN_ON(!horiz_pixels))
230194b49d53SJani Nikula 		return 0;
230294b49d53SJani Nikula 
230394b49d53SJani Nikula 	return DIV_ROUND_UP(pri_val * 64, horiz_pixels * cpp) + 2;
230494b49d53SJani Nikula }
230594b49d53SJani Nikula 
230694b49d53SJani Nikula struct ilk_wm_maximums {
230794b49d53SJani Nikula 	u16 pri;
230894b49d53SJani Nikula 	u16 spr;
230994b49d53SJani Nikula 	u16 cur;
231094b49d53SJani Nikula 	u16 fbc;
231194b49d53SJani Nikula };
231294b49d53SJani Nikula 
231394b49d53SJani Nikula /*
231494b49d53SJani Nikula  * For both WM_PIPE and WM_LP.
231594b49d53SJani Nikula  * mem_value must be in 0.1us units.
231694b49d53SJani Nikula  */
ilk_compute_pri_wm(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,u32 mem_value,bool is_lp)231794b49d53SJani Nikula static u32 ilk_compute_pri_wm(const struct intel_crtc_state *crtc_state,
231894b49d53SJani Nikula 			      const struct intel_plane_state *plane_state,
231994b49d53SJani Nikula 			      u32 mem_value, bool is_lp)
232094b49d53SJani Nikula {
232194b49d53SJani Nikula 	u32 method1, method2;
232294b49d53SJani Nikula 	int cpp;
232394b49d53SJani Nikula 
232494b49d53SJani Nikula 	if (mem_value == 0)
232594b49d53SJani Nikula 		return U32_MAX;
232694b49d53SJani Nikula 
232794b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state))
232894b49d53SJani Nikula 		return 0;
232994b49d53SJani Nikula 
233094b49d53SJani Nikula 	cpp = plane_state->hw.fb->format->cpp[0];
233194b49d53SJani Nikula 
233294b49d53SJani Nikula 	method1 = ilk_wm_method1(crtc_state->pixel_rate, cpp, mem_value);
233394b49d53SJani Nikula 
233494b49d53SJani Nikula 	if (!is_lp)
233594b49d53SJani Nikula 		return method1;
233694b49d53SJani Nikula 
233794b49d53SJani Nikula 	method2 = ilk_wm_method2(crtc_state->pixel_rate,
233894b49d53SJani Nikula 				 crtc_state->hw.pipe_mode.crtc_htotal,
233994b49d53SJani Nikula 				 drm_rect_width(&plane_state->uapi.src) >> 16,
234094b49d53SJani Nikula 				 cpp, mem_value);
234194b49d53SJani Nikula 
234294b49d53SJani Nikula 	return min(method1, method2);
234394b49d53SJani Nikula }
234494b49d53SJani Nikula 
234594b49d53SJani Nikula /*
234694b49d53SJani Nikula  * For both WM_PIPE and WM_LP.
234794b49d53SJani Nikula  * mem_value must be in 0.1us units.
234894b49d53SJani Nikula  */
ilk_compute_spr_wm(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,u32 mem_value)234994b49d53SJani Nikula static u32 ilk_compute_spr_wm(const struct intel_crtc_state *crtc_state,
235094b49d53SJani Nikula 			      const struct intel_plane_state *plane_state,
235194b49d53SJani Nikula 			      u32 mem_value)
235294b49d53SJani Nikula {
235394b49d53SJani Nikula 	u32 method1, method2;
235494b49d53SJani Nikula 	int cpp;
235594b49d53SJani Nikula 
235694b49d53SJani Nikula 	if (mem_value == 0)
235794b49d53SJani Nikula 		return U32_MAX;
235894b49d53SJani Nikula 
235994b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state))
236094b49d53SJani Nikula 		return 0;
236194b49d53SJani Nikula 
236294b49d53SJani Nikula 	cpp = plane_state->hw.fb->format->cpp[0];
236394b49d53SJani Nikula 
236494b49d53SJani Nikula 	method1 = ilk_wm_method1(crtc_state->pixel_rate, cpp, mem_value);
236594b49d53SJani Nikula 	method2 = ilk_wm_method2(crtc_state->pixel_rate,
236694b49d53SJani Nikula 				 crtc_state->hw.pipe_mode.crtc_htotal,
236794b49d53SJani Nikula 				 drm_rect_width(&plane_state->uapi.src) >> 16,
236894b49d53SJani Nikula 				 cpp, mem_value);
236994b49d53SJani Nikula 	return min(method1, method2);
237094b49d53SJani Nikula }
237194b49d53SJani Nikula 
237294b49d53SJani Nikula /*
237394b49d53SJani Nikula  * For both WM_PIPE and WM_LP.
237494b49d53SJani Nikula  * mem_value must be in 0.1us units.
237594b49d53SJani Nikula  */
ilk_compute_cur_wm(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,u32 mem_value)237694b49d53SJani Nikula static u32 ilk_compute_cur_wm(const struct intel_crtc_state *crtc_state,
237794b49d53SJani Nikula 			      const struct intel_plane_state *plane_state,
237894b49d53SJani Nikula 			      u32 mem_value)
237994b49d53SJani Nikula {
238094b49d53SJani Nikula 	int cpp;
238194b49d53SJani Nikula 
238294b49d53SJani Nikula 	if (mem_value == 0)
238394b49d53SJani Nikula 		return U32_MAX;
238494b49d53SJani Nikula 
238594b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state))
238694b49d53SJani Nikula 		return 0;
238794b49d53SJani Nikula 
238894b49d53SJani Nikula 	cpp = plane_state->hw.fb->format->cpp[0];
238994b49d53SJani Nikula 
239094b49d53SJani Nikula 	return ilk_wm_method2(crtc_state->pixel_rate,
239194b49d53SJani Nikula 			      crtc_state->hw.pipe_mode.crtc_htotal,
239294b49d53SJani Nikula 			      drm_rect_width(&plane_state->uapi.src) >> 16,
239394b49d53SJani Nikula 			      cpp, mem_value);
239494b49d53SJani Nikula }
239594b49d53SJani Nikula 
239694b49d53SJani Nikula /* Only for WM_LP. */
ilk_compute_fbc_wm(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,u32 pri_val)239794b49d53SJani Nikula static u32 ilk_compute_fbc_wm(const struct intel_crtc_state *crtc_state,
239894b49d53SJani Nikula 			      const struct intel_plane_state *plane_state,
239994b49d53SJani Nikula 			      u32 pri_val)
240094b49d53SJani Nikula {
240194b49d53SJani Nikula 	int cpp;
240294b49d53SJani Nikula 
240394b49d53SJani Nikula 	if (!intel_wm_plane_visible(crtc_state, plane_state))
240494b49d53SJani Nikula 		return 0;
240594b49d53SJani Nikula 
240694b49d53SJani Nikula 	cpp = plane_state->hw.fb->format->cpp[0];
240794b49d53SJani Nikula 
240894b49d53SJani Nikula 	return ilk_wm_fbc(pri_val, drm_rect_width(&plane_state->uapi.src) >> 16,
240994b49d53SJani Nikula 			  cpp);
241094b49d53SJani Nikula }
241194b49d53SJani Nikula 
241294b49d53SJani Nikula static unsigned int
ilk_display_fifo_size(const struct drm_i915_private * dev_priv)241394b49d53SJani Nikula ilk_display_fifo_size(const struct drm_i915_private *dev_priv)
241494b49d53SJani Nikula {
241594b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) >= 8)
241694b49d53SJani Nikula 		return 3072;
241794b49d53SJani Nikula 	else if (DISPLAY_VER(dev_priv) >= 7)
241894b49d53SJani Nikula 		return 768;
241994b49d53SJani Nikula 	else
242094b49d53SJani Nikula 		return 512;
242194b49d53SJani Nikula }
242294b49d53SJani Nikula 
242394b49d53SJani Nikula static unsigned int
ilk_plane_wm_reg_max(const struct drm_i915_private * dev_priv,int level,bool is_sprite)242494b49d53SJani Nikula ilk_plane_wm_reg_max(const struct drm_i915_private *dev_priv,
242594b49d53SJani Nikula 		     int level, bool is_sprite)
242694b49d53SJani Nikula {
242794b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) >= 8)
242894b49d53SJani Nikula 		/* BDW primary/sprite plane watermarks */
242994b49d53SJani Nikula 		return level == 0 ? 255 : 2047;
243094b49d53SJani Nikula 	else if (DISPLAY_VER(dev_priv) >= 7)
243194b49d53SJani Nikula 		/* IVB/HSW primary/sprite plane watermarks */
243294b49d53SJani Nikula 		return level == 0 ? 127 : 1023;
243394b49d53SJani Nikula 	else if (!is_sprite)
243494b49d53SJani Nikula 		/* ILK/SNB primary plane watermarks */
243594b49d53SJani Nikula 		return level == 0 ? 127 : 511;
243694b49d53SJani Nikula 	else
243794b49d53SJani Nikula 		/* ILK/SNB sprite plane watermarks */
243894b49d53SJani Nikula 		return level == 0 ? 63 : 255;
243994b49d53SJani Nikula }
244094b49d53SJani Nikula 
244194b49d53SJani Nikula static unsigned int
ilk_cursor_wm_reg_max(const struct drm_i915_private * dev_priv,int level)244294b49d53SJani Nikula ilk_cursor_wm_reg_max(const struct drm_i915_private *dev_priv, int level)
244394b49d53SJani Nikula {
244494b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) >= 7)
244594b49d53SJani Nikula 		return level == 0 ? 63 : 255;
244694b49d53SJani Nikula 	else
244794b49d53SJani Nikula 		return level == 0 ? 31 : 63;
244894b49d53SJani Nikula }
244994b49d53SJani Nikula 
ilk_fbc_wm_reg_max(const struct drm_i915_private * dev_priv)245094b49d53SJani Nikula static unsigned int ilk_fbc_wm_reg_max(const struct drm_i915_private *dev_priv)
245194b49d53SJani Nikula {
245294b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) >= 8)
245394b49d53SJani Nikula 		return 31;
245494b49d53SJani Nikula 	else
245594b49d53SJani Nikula 		return 15;
245694b49d53SJani Nikula }
245794b49d53SJani Nikula 
245894b49d53SJani Nikula /* Calculate the maximum primary/sprite plane watermark */
ilk_plane_wm_max(const struct drm_i915_private * dev_priv,int level,const struct intel_wm_config * config,enum intel_ddb_partitioning ddb_partitioning,bool is_sprite)245994b49d53SJani Nikula static unsigned int ilk_plane_wm_max(const struct drm_i915_private *dev_priv,
246094b49d53SJani Nikula 				     int level,
246194b49d53SJani Nikula 				     const struct intel_wm_config *config,
246294b49d53SJani Nikula 				     enum intel_ddb_partitioning ddb_partitioning,
246394b49d53SJani Nikula 				     bool is_sprite)
246494b49d53SJani Nikula {
246594b49d53SJani Nikula 	unsigned int fifo_size = ilk_display_fifo_size(dev_priv);
246694b49d53SJani Nikula 
246794b49d53SJani Nikula 	/* if sprites aren't enabled, sprites get nothing */
246894b49d53SJani Nikula 	if (is_sprite && !config->sprites_enabled)
246994b49d53SJani Nikula 		return 0;
247094b49d53SJani Nikula 
247194b49d53SJani Nikula 	/* HSW allows LP1+ watermarks even with multiple pipes */
247294b49d53SJani Nikula 	if (level == 0 || config->num_pipes_active > 1) {
247394b49d53SJani Nikula 		fifo_size /= INTEL_NUM_PIPES(dev_priv);
247494b49d53SJani Nikula 
247594b49d53SJani Nikula 		/*
247694b49d53SJani Nikula 		 * For some reason the non self refresh
247794b49d53SJani Nikula 		 * FIFO size is only half of the self
247894b49d53SJani Nikula 		 * refresh FIFO size on ILK/SNB.
247994b49d53SJani Nikula 		 */
248094b49d53SJani Nikula 		if (DISPLAY_VER(dev_priv) <= 6)
248194b49d53SJani Nikula 			fifo_size /= 2;
248294b49d53SJani Nikula 	}
248394b49d53SJani Nikula 
248494b49d53SJani Nikula 	if (config->sprites_enabled) {
248594b49d53SJani Nikula 		/* level 0 is always calculated with 1:1 split */
248694b49d53SJani Nikula 		if (level > 0 && ddb_partitioning == INTEL_DDB_PART_5_6) {
248794b49d53SJani Nikula 			if (is_sprite)
248894b49d53SJani Nikula 				fifo_size *= 5;
248994b49d53SJani Nikula 			fifo_size /= 6;
249094b49d53SJani Nikula 		} else {
249194b49d53SJani Nikula 			fifo_size /= 2;
249294b49d53SJani Nikula 		}
249394b49d53SJani Nikula 	}
249494b49d53SJani Nikula 
249594b49d53SJani Nikula 	/* clamp to max that the registers can hold */
249694b49d53SJani Nikula 	return min(fifo_size, ilk_plane_wm_reg_max(dev_priv, level, is_sprite));
249794b49d53SJani Nikula }
249894b49d53SJani Nikula 
249994b49d53SJani Nikula /* Calculate the maximum cursor plane watermark */
ilk_cursor_wm_max(const struct drm_i915_private * dev_priv,int level,const struct intel_wm_config * config)250094b49d53SJani Nikula static unsigned int ilk_cursor_wm_max(const struct drm_i915_private *dev_priv,
250194b49d53SJani Nikula 				      int level,
250294b49d53SJani Nikula 				      const struct intel_wm_config *config)
250394b49d53SJani Nikula {
250494b49d53SJani Nikula 	/* HSW LP1+ watermarks w/ multiple pipes */
250594b49d53SJani Nikula 	if (level > 0 && config->num_pipes_active > 1)
250694b49d53SJani Nikula 		return 64;
250794b49d53SJani Nikula 
250894b49d53SJani Nikula 	/* otherwise just report max that registers can hold */
250994b49d53SJani Nikula 	return ilk_cursor_wm_reg_max(dev_priv, level);
251094b49d53SJani Nikula }
251194b49d53SJani Nikula 
ilk_compute_wm_maximums(const struct drm_i915_private * dev_priv,int level,const struct intel_wm_config * config,enum intel_ddb_partitioning ddb_partitioning,struct ilk_wm_maximums * max)251294b49d53SJani Nikula static void ilk_compute_wm_maximums(const struct drm_i915_private *dev_priv,
251394b49d53SJani Nikula 				    int level,
251494b49d53SJani Nikula 				    const struct intel_wm_config *config,
251594b49d53SJani Nikula 				    enum intel_ddb_partitioning ddb_partitioning,
251694b49d53SJani Nikula 				    struct ilk_wm_maximums *max)
251794b49d53SJani Nikula {
251894b49d53SJani Nikula 	max->pri = ilk_plane_wm_max(dev_priv, level, config, ddb_partitioning, false);
251994b49d53SJani Nikula 	max->spr = ilk_plane_wm_max(dev_priv, level, config, ddb_partitioning, true);
252094b49d53SJani Nikula 	max->cur = ilk_cursor_wm_max(dev_priv, level, config);
252194b49d53SJani Nikula 	max->fbc = ilk_fbc_wm_reg_max(dev_priv);
252294b49d53SJani Nikula }
252394b49d53SJani Nikula 
ilk_compute_wm_reg_maximums(const struct drm_i915_private * dev_priv,int level,struct ilk_wm_maximums * max)252494b49d53SJani Nikula static void ilk_compute_wm_reg_maximums(const struct drm_i915_private *dev_priv,
252594b49d53SJani Nikula 					int level,
252694b49d53SJani Nikula 					struct ilk_wm_maximums *max)
252794b49d53SJani Nikula {
252894b49d53SJani Nikula 	max->pri = ilk_plane_wm_reg_max(dev_priv, level, false);
252994b49d53SJani Nikula 	max->spr = ilk_plane_wm_reg_max(dev_priv, level, true);
253094b49d53SJani Nikula 	max->cur = ilk_cursor_wm_reg_max(dev_priv, level);
253194b49d53SJani Nikula 	max->fbc = ilk_fbc_wm_reg_max(dev_priv);
253294b49d53SJani Nikula }
253394b49d53SJani Nikula 
ilk_validate_wm_level(int level,const struct ilk_wm_maximums * max,struct intel_wm_level * result)253494b49d53SJani Nikula static bool ilk_validate_wm_level(int level,
253594b49d53SJani Nikula 				  const struct ilk_wm_maximums *max,
253694b49d53SJani Nikula 				  struct intel_wm_level *result)
253794b49d53SJani Nikula {
253894b49d53SJani Nikula 	bool ret;
253994b49d53SJani Nikula 
254094b49d53SJani Nikula 	/* already determined to be invalid? */
254194b49d53SJani Nikula 	if (!result->enable)
254294b49d53SJani Nikula 		return false;
254394b49d53SJani Nikula 
254494b49d53SJani Nikula 	result->enable = result->pri_val <= max->pri &&
254594b49d53SJani Nikula 			 result->spr_val <= max->spr &&
254694b49d53SJani Nikula 			 result->cur_val <= max->cur;
254794b49d53SJani Nikula 
254894b49d53SJani Nikula 	ret = result->enable;
254994b49d53SJani Nikula 
255094b49d53SJani Nikula 	/*
255194b49d53SJani Nikula 	 * HACK until we can pre-compute everything,
255294b49d53SJani Nikula 	 * and thus fail gracefully if LP0 watermarks
255394b49d53SJani Nikula 	 * are exceeded...
255494b49d53SJani Nikula 	 */
255594b49d53SJani Nikula 	if (level == 0 && !result->enable) {
255694b49d53SJani Nikula 		if (result->pri_val > max->pri)
255794b49d53SJani Nikula 			DRM_DEBUG_KMS("Primary WM%d too large %u (max %u)\n",
255894b49d53SJani Nikula 				      level, result->pri_val, max->pri);
255994b49d53SJani Nikula 		if (result->spr_val > max->spr)
256094b49d53SJani Nikula 			DRM_DEBUG_KMS("Sprite WM%d too large %u (max %u)\n",
256194b49d53SJani Nikula 				      level, result->spr_val, max->spr);
256294b49d53SJani Nikula 		if (result->cur_val > max->cur)
256394b49d53SJani Nikula 			DRM_DEBUG_KMS("Cursor WM%d too large %u (max %u)\n",
256494b49d53SJani Nikula 				      level, result->cur_val, max->cur);
256594b49d53SJani Nikula 
256694b49d53SJani Nikula 		result->pri_val = min_t(u32, result->pri_val, max->pri);
256794b49d53SJani Nikula 		result->spr_val = min_t(u32, result->spr_val, max->spr);
256894b49d53SJani Nikula 		result->cur_val = min_t(u32, result->cur_val, max->cur);
256994b49d53SJani Nikula 		result->enable = true;
257094b49d53SJani Nikula 	}
257194b49d53SJani Nikula 
257294b49d53SJani Nikula 	return ret;
257394b49d53SJani Nikula }
257494b49d53SJani Nikula 
ilk_compute_wm_level(const struct drm_i915_private * dev_priv,const struct intel_crtc * crtc,int level,struct intel_crtc_state * crtc_state,const struct intel_plane_state * pristate,const struct intel_plane_state * sprstate,const struct intel_plane_state * curstate,struct intel_wm_level * result)257594b49d53SJani Nikula static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
257694b49d53SJani Nikula 				 const struct intel_crtc *crtc,
257794b49d53SJani Nikula 				 int level,
257894b49d53SJani Nikula 				 struct intel_crtc_state *crtc_state,
257994b49d53SJani Nikula 				 const struct intel_plane_state *pristate,
258094b49d53SJani Nikula 				 const struct intel_plane_state *sprstate,
258194b49d53SJani Nikula 				 const struct intel_plane_state *curstate,
258294b49d53SJani Nikula 				 struct intel_wm_level *result)
258394b49d53SJani Nikula {
258494b49d53SJani Nikula 	u16 pri_latency = dev_priv->display.wm.pri_latency[level];
258594b49d53SJani Nikula 	u16 spr_latency = dev_priv->display.wm.spr_latency[level];
258694b49d53SJani Nikula 	u16 cur_latency = dev_priv->display.wm.cur_latency[level];
258794b49d53SJani Nikula 
258894b49d53SJani Nikula 	/* WM1+ latency values stored in 0.5us units */
258994b49d53SJani Nikula 	if (level > 0) {
259094b49d53SJani Nikula 		pri_latency *= 5;
259194b49d53SJani Nikula 		spr_latency *= 5;
259294b49d53SJani Nikula 		cur_latency *= 5;
259394b49d53SJani Nikula 	}
259494b49d53SJani Nikula 
259594b49d53SJani Nikula 	if (pristate) {
259694b49d53SJani Nikula 		result->pri_val = ilk_compute_pri_wm(crtc_state, pristate,
259794b49d53SJani Nikula 						     pri_latency, level);
259894b49d53SJani Nikula 		result->fbc_val = ilk_compute_fbc_wm(crtc_state, pristate, result->pri_val);
259994b49d53SJani Nikula 	}
260094b49d53SJani Nikula 
260194b49d53SJani Nikula 	if (sprstate)
260294b49d53SJani Nikula 		result->spr_val = ilk_compute_spr_wm(crtc_state, sprstate, spr_latency);
260394b49d53SJani Nikula 
260494b49d53SJani Nikula 	if (curstate)
260594b49d53SJani Nikula 		result->cur_val = ilk_compute_cur_wm(crtc_state, curstate, cur_latency);
260694b49d53SJani Nikula 
260794b49d53SJani Nikula 	result->enable = true;
260894b49d53SJani Nikula }
260994b49d53SJani Nikula 
hsw_read_wm_latency(struct drm_i915_private * i915,u16 wm[])261094b49d53SJani Nikula static void hsw_read_wm_latency(struct drm_i915_private *i915, u16 wm[])
261194b49d53SJani Nikula {
261294b49d53SJani Nikula 	u64 sskpd;
261394b49d53SJani Nikula 
261494b49d53SJani Nikula 	i915->display.wm.num_levels = 5;
261594b49d53SJani Nikula 
261694b49d53SJani Nikula 	sskpd = intel_uncore_read64(&i915->uncore, MCH_SSKPD);
261794b49d53SJani Nikula 
261894b49d53SJani Nikula 	wm[0] = REG_FIELD_GET64(SSKPD_NEW_WM0_MASK_HSW, sskpd);
261994b49d53SJani Nikula 	if (wm[0] == 0)
262094b49d53SJani Nikula 		wm[0] = REG_FIELD_GET64(SSKPD_OLD_WM0_MASK_HSW, sskpd);
262194b49d53SJani Nikula 	wm[1] = REG_FIELD_GET64(SSKPD_WM1_MASK_HSW, sskpd);
262294b49d53SJani Nikula 	wm[2] = REG_FIELD_GET64(SSKPD_WM2_MASK_HSW, sskpd);
262394b49d53SJani Nikula 	wm[3] = REG_FIELD_GET64(SSKPD_WM3_MASK_HSW, sskpd);
262494b49d53SJani Nikula 	wm[4] = REG_FIELD_GET64(SSKPD_WM4_MASK_HSW, sskpd);
262594b49d53SJani Nikula }
262694b49d53SJani Nikula 
snb_read_wm_latency(struct drm_i915_private * i915,u16 wm[])262794b49d53SJani Nikula static void snb_read_wm_latency(struct drm_i915_private *i915, u16 wm[])
262894b49d53SJani Nikula {
262994b49d53SJani Nikula 	u32 sskpd;
263094b49d53SJani Nikula 
263194b49d53SJani Nikula 	i915->display.wm.num_levels = 4;
263294b49d53SJani Nikula 
263394b49d53SJani Nikula 	sskpd = intel_uncore_read(&i915->uncore, MCH_SSKPD);
263494b49d53SJani Nikula 
263594b49d53SJani Nikula 	wm[0] = REG_FIELD_GET(SSKPD_WM0_MASK_SNB, sskpd);
263694b49d53SJani Nikula 	wm[1] = REG_FIELD_GET(SSKPD_WM1_MASK_SNB, sskpd);
263794b49d53SJani Nikula 	wm[2] = REG_FIELD_GET(SSKPD_WM2_MASK_SNB, sskpd);
263894b49d53SJani Nikula 	wm[3] = REG_FIELD_GET(SSKPD_WM3_MASK_SNB, sskpd);
263994b49d53SJani Nikula }
264094b49d53SJani Nikula 
ilk_read_wm_latency(struct drm_i915_private * i915,u16 wm[])264194b49d53SJani Nikula static void ilk_read_wm_latency(struct drm_i915_private *i915, u16 wm[])
264294b49d53SJani Nikula {
264394b49d53SJani Nikula 	u32 mltr;
264494b49d53SJani Nikula 
264594b49d53SJani Nikula 	i915->display.wm.num_levels = 3;
264694b49d53SJani Nikula 
264794b49d53SJani Nikula 	mltr = intel_uncore_read(&i915->uncore, MLTR_ILK);
264894b49d53SJani Nikula 
264994b49d53SJani Nikula 	/* ILK primary LP0 latency is 700 ns */
265094b49d53SJani Nikula 	wm[0] = 7;
265194b49d53SJani Nikula 	wm[1] = REG_FIELD_GET(MLTR_WM1_MASK, mltr);
265294b49d53SJani Nikula 	wm[2] = REG_FIELD_GET(MLTR_WM2_MASK, mltr);
265394b49d53SJani Nikula }
265494b49d53SJani Nikula 
intel_fixup_spr_wm_latency(struct drm_i915_private * dev_priv,u16 wm[5])265594b49d53SJani Nikula static void intel_fixup_spr_wm_latency(struct drm_i915_private *dev_priv,
265694b49d53SJani Nikula 				       u16 wm[5])
265794b49d53SJani Nikula {
265894b49d53SJani Nikula 	/* ILK sprite LP0 latency is 1300 ns */
265994b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) == 5)
266094b49d53SJani Nikula 		wm[0] = 13;
266194b49d53SJani Nikula }
266294b49d53SJani Nikula 
intel_fixup_cur_wm_latency(struct drm_i915_private * dev_priv,u16 wm[5])266394b49d53SJani Nikula static void intel_fixup_cur_wm_latency(struct drm_i915_private *dev_priv,
266494b49d53SJani Nikula 				       u16 wm[5])
266594b49d53SJani Nikula {
266694b49d53SJani Nikula 	/* ILK cursor LP0 latency is 1300 ns */
266794b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) == 5)
266894b49d53SJani Nikula 		wm[0] = 13;
266994b49d53SJani Nikula }
267094b49d53SJani Nikula 
ilk_increase_wm_latency(struct drm_i915_private * dev_priv,u16 wm[5],u16 min)267194b49d53SJani Nikula static bool ilk_increase_wm_latency(struct drm_i915_private *dev_priv,
267294b49d53SJani Nikula 				    u16 wm[5], u16 min)
267394b49d53SJani Nikula {
267494b49d53SJani Nikula 	int level;
267594b49d53SJani Nikula 
267694b49d53SJani Nikula 	if (wm[0] >= min)
267794b49d53SJani Nikula 		return false;
267894b49d53SJani Nikula 
267994b49d53SJani Nikula 	wm[0] = max(wm[0], min);
268094b49d53SJani Nikula 	for (level = 1; level < dev_priv->display.wm.num_levels; level++)
268194b49d53SJani Nikula 		wm[level] = max_t(u16, wm[level], DIV_ROUND_UP(min, 5));
268294b49d53SJani Nikula 
268394b49d53SJani Nikula 	return true;
268494b49d53SJani Nikula }
268594b49d53SJani Nikula 
snb_wm_latency_quirk(struct drm_i915_private * dev_priv)268694b49d53SJani Nikula static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv)
268794b49d53SJani Nikula {
268894b49d53SJani Nikula 	bool changed;
268994b49d53SJani Nikula 
269094b49d53SJani Nikula 	/*
269194b49d53SJani Nikula 	 * The BIOS provided WM memory latency values are often
269294b49d53SJani Nikula 	 * inadequate for high resolution displays. Adjust them.
269394b49d53SJani Nikula 	 */
269494b49d53SJani Nikula 	changed = ilk_increase_wm_latency(dev_priv, dev_priv->display.wm.pri_latency, 12);
269594b49d53SJani Nikula 	changed |= ilk_increase_wm_latency(dev_priv, dev_priv->display.wm.spr_latency, 12);
269694b49d53SJani Nikula 	changed |= ilk_increase_wm_latency(dev_priv, dev_priv->display.wm.cur_latency, 12);
269794b49d53SJani Nikula 
269894b49d53SJani Nikula 	if (!changed)
269994b49d53SJani Nikula 		return;
270094b49d53SJani Nikula 
270194b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
270294b49d53SJani Nikula 		    "WM latency values increased to avoid potential underruns\n");
270394b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Primary", dev_priv->display.wm.pri_latency);
270494b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->display.wm.spr_latency);
270594b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->display.wm.cur_latency);
270694b49d53SJani Nikula }
270794b49d53SJani Nikula 
snb_wm_lp3_irq_quirk(struct drm_i915_private * dev_priv)270894b49d53SJani Nikula static void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv)
270994b49d53SJani Nikula {
271094b49d53SJani Nikula 	/*
271194b49d53SJani Nikula 	 * On some SNB machines (Thinkpad X220 Tablet at least)
271294b49d53SJani Nikula 	 * LP3 usage can cause vblank interrupts to be lost.
271394b49d53SJani Nikula 	 * The DEIIR bit will go high but it looks like the CPU
271494b49d53SJani Nikula 	 * never gets interrupted.
271594b49d53SJani Nikula 	 *
271694b49d53SJani Nikula 	 * It's not clear whether other interrupt source could
271794b49d53SJani Nikula 	 * be affected or if this is somehow limited to vblank
271894b49d53SJani Nikula 	 * interrupts only. To play it safe we disable LP3
271994b49d53SJani Nikula 	 * watermarks entirely.
272094b49d53SJani Nikula 	 */
272194b49d53SJani Nikula 	if (dev_priv->display.wm.pri_latency[3] == 0 &&
272294b49d53SJani Nikula 	    dev_priv->display.wm.spr_latency[3] == 0 &&
272394b49d53SJani Nikula 	    dev_priv->display.wm.cur_latency[3] == 0)
272494b49d53SJani Nikula 		return;
272594b49d53SJani Nikula 
272694b49d53SJani Nikula 	dev_priv->display.wm.pri_latency[3] = 0;
272794b49d53SJani Nikula 	dev_priv->display.wm.spr_latency[3] = 0;
272894b49d53SJani Nikula 	dev_priv->display.wm.cur_latency[3] = 0;
272994b49d53SJani Nikula 
273094b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
273194b49d53SJani Nikula 		    "LP3 watermarks disabled due to potential for lost interrupts\n");
273294b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Primary", dev_priv->display.wm.pri_latency);
273394b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->display.wm.spr_latency);
273494b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->display.wm.cur_latency);
273594b49d53SJani Nikula }
273694b49d53SJani Nikula 
ilk_setup_wm_latency(struct drm_i915_private * dev_priv)273794b49d53SJani Nikula static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv)
273894b49d53SJani Nikula {
273994b49d53SJani Nikula 	if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
274094b49d53SJani Nikula 		hsw_read_wm_latency(dev_priv, dev_priv->display.wm.pri_latency);
274194b49d53SJani Nikula 	else if (DISPLAY_VER(dev_priv) >= 6)
274294b49d53SJani Nikula 		snb_read_wm_latency(dev_priv, dev_priv->display.wm.pri_latency);
274394b49d53SJani Nikula 	else
274494b49d53SJani Nikula 		ilk_read_wm_latency(dev_priv, dev_priv->display.wm.pri_latency);
274594b49d53SJani Nikula 
274694b49d53SJani Nikula 	memcpy(dev_priv->display.wm.spr_latency, dev_priv->display.wm.pri_latency,
274794b49d53SJani Nikula 	       sizeof(dev_priv->display.wm.pri_latency));
274894b49d53SJani Nikula 	memcpy(dev_priv->display.wm.cur_latency, dev_priv->display.wm.pri_latency,
274994b49d53SJani Nikula 	       sizeof(dev_priv->display.wm.pri_latency));
275094b49d53SJani Nikula 
275194b49d53SJani Nikula 	intel_fixup_spr_wm_latency(dev_priv, dev_priv->display.wm.spr_latency);
275294b49d53SJani Nikula 	intel_fixup_cur_wm_latency(dev_priv, dev_priv->display.wm.cur_latency);
275394b49d53SJani Nikula 
275494b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Primary", dev_priv->display.wm.pri_latency);
275594b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->display.wm.spr_latency);
275694b49d53SJani Nikula 	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->display.wm.cur_latency);
275794b49d53SJani Nikula 
275894b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) == 6) {
275994b49d53SJani Nikula 		snb_wm_latency_quirk(dev_priv);
276094b49d53SJani Nikula 		snb_wm_lp3_irq_quirk(dev_priv);
276194b49d53SJani Nikula 	}
276294b49d53SJani Nikula }
276394b49d53SJani Nikula 
ilk_validate_pipe_wm(const struct drm_i915_private * dev_priv,struct intel_pipe_wm * pipe_wm)276494b49d53SJani Nikula static bool ilk_validate_pipe_wm(const struct drm_i915_private *dev_priv,
276594b49d53SJani Nikula 				 struct intel_pipe_wm *pipe_wm)
276694b49d53SJani Nikula {
276794b49d53SJani Nikula 	/* LP0 watermark maximums depend on this pipe alone */
276894b49d53SJani Nikula 	const struct intel_wm_config config = {
276994b49d53SJani Nikula 		.num_pipes_active = 1,
277094b49d53SJani Nikula 		.sprites_enabled = pipe_wm->sprites_enabled,
277194b49d53SJani Nikula 		.sprites_scaled = pipe_wm->sprites_scaled,
277294b49d53SJani Nikula 	};
277394b49d53SJani Nikula 	struct ilk_wm_maximums max;
277494b49d53SJani Nikula 
277594b49d53SJani Nikula 	/* LP0 watermarks always use 1/2 DDB partitioning */
277694b49d53SJani Nikula 	ilk_compute_wm_maximums(dev_priv, 0, &config, INTEL_DDB_PART_1_2, &max);
277794b49d53SJani Nikula 
277894b49d53SJani Nikula 	/* At least LP0 must be valid */
277994b49d53SJani Nikula 	if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) {
278094b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm, "LP0 watermark invalid\n");
278194b49d53SJani Nikula 		return false;
278294b49d53SJani Nikula 	}
278394b49d53SJani Nikula 
278494b49d53SJani Nikula 	return true;
278594b49d53SJani Nikula }
278694b49d53SJani Nikula 
278794b49d53SJani Nikula /* Compute new watermarks for the pipe */
ilk_compute_pipe_wm(struct intel_atomic_state * state,struct intel_crtc * crtc)278894b49d53SJani Nikula static int ilk_compute_pipe_wm(struct intel_atomic_state *state,
278994b49d53SJani Nikula 			       struct intel_crtc *crtc)
279094b49d53SJani Nikula {
279194b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
279294b49d53SJani Nikula 	struct intel_crtc_state *crtc_state =
279394b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
279494b49d53SJani Nikula 	struct intel_pipe_wm *pipe_wm;
279594b49d53SJani Nikula 	struct intel_plane *plane;
279694b49d53SJani Nikula 	const struct intel_plane_state *plane_state;
279794b49d53SJani Nikula 	const struct intel_plane_state *pristate = NULL;
279894b49d53SJani Nikula 	const struct intel_plane_state *sprstate = NULL;
279994b49d53SJani Nikula 	const struct intel_plane_state *curstate = NULL;
280094b49d53SJani Nikula 	struct ilk_wm_maximums max;
280194b49d53SJani Nikula 	int level, usable_level;
280294b49d53SJani Nikula 
280394b49d53SJani Nikula 	pipe_wm = &crtc_state->wm.ilk.optimal;
280494b49d53SJani Nikula 
280594b49d53SJani Nikula 	intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
280694b49d53SJani Nikula 		if (plane->base.type == DRM_PLANE_TYPE_PRIMARY)
280794b49d53SJani Nikula 			pristate = plane_state;
280894b49d53SJani Nikula 		else if (plane->base.type == DRM_PLANE_TYPE_OVERLAY)
280994b49d53SJani Nikula 			sprstate = plane_state;
281094b49d53SJani Nikula 		else if (plane->base.type == DRM_PLANE_TYPE_CURSOR)
281194b49d53SJani Nikula 			curstate = plane_state;
281294b49d53SJani Nikula 	}
281394b49d53SJani Nikula 
281494b49d53SJani Nikula 	pipe_wm->pipe_enabled = crtc_state->hw.active;
281594b49d53SJani Nikula 	pipe_wm->sprites_enabled = crtc_state->active_planes & BIT(PLANE_SPRITE0);
281694b49d53SJani Nikula 	pipe_wm->sprites_scaled = crtc_state->scaled_planes & BIT(PLANE_SPRITE0);
281794b49d53SJani Nikula 
281894b49d53SJani Nikula 	usable_level = dev_priv->display.wm.num_levels - 1;
281994b49d53SJani Nikula 
282094b49d53SJani Nikula 	/* ILK/SNB: LP2+ watermarks only w/o sprites */
282194b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) <= 6 && pipe_wm->sprites_enabled)
282294b49d53SJani Nikula 		usable_level = 1;
282394b49d53SJani Nikula 
282494b49d53SJani Nikula 	/* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
282594b49d53SJani Nikula 	if (pipe_wm->sprites_scaled)
282694b49d53SJani Nikula 		usable_level = 0;
282794b49d53SJani Nikula 
282894b49d53SJani Nikula 	memset(&pipe_wm->wm, 0, sizeof(pipe_wm->wm));
282994b49d53SJani Nikula 	ilk_compute_wm_level(dev_priv, crtc, 0, crtc_state,
283094b49d53SJani Nikula 			     pristate, sprstate, curstate, &pipe_wm->wm[0]);
283194b49d53SJani Nikula 
283294b49d53SJani Nikula 	if (!ilk_validate_pipe_wm(dev_priv, pipe_wm))
283394b49d53SJani Nikula 		return -EINVAL;
283494b49d53SJani Nikula 
283594b49d53SJani Nikula 	ilk_compute_wm_reg_maximums(dev_priv, 1, &max);
283694b49d53SJani Nikula 
283794b49d53SJani Nikula 	for (level = 1; level <= usable_level; level++) {
283894b49d53SJani Nikula 		struct intel_wm_level *wm = &pipe_wm->wm[level];
283994b49d53SJani Nikula 
284094b49d53SJani Nikula 		ilk_compute_wm_level(dev_priv, crtc, level, crtc_state,
284194b49d53SJani Nikula 				     pristate, sprstate, curstate, wm);
284294b49d53SJani Nikula 
284394b49d53SJani Nikula 		/*
284494b49d53SJani Nikula 		 * Disable any watermark level that exceeds the
284594b49d53SJani Nikula 		 * register maximums since such watermarks are
284694b49d53SJani Nikula 		 * always invalid.
284794b49d53SJani Nikula 		 */
284894b49d53SJani Nikula 		if (!ilk_validate_wm_level(level, &max, wm)) {
284994b49d53SJani Nikula 			memset(wm, 0, sizeof(*wm));
285094b49d53SJani Nikula 			break;
285194b49d53SJani Nikula 		}
285294b49d53SJani Nikula 	}
285394b49d53SJani Nikula 
285494b49d53SJani Nikula 	return 0;
285594b49d53SJani Nikula }
285694b49d53SJani Nikula 
285794b49d53SJani Nikula /*
285894b49d53SJani Nikula  * Build a set of 'intermediate' watermark values that satisfy both the old
285994b49d53SJani Nikula  * state and the new state.  These can be programmed to the hardware
286094b49d53SJani Nikula  * immediately.
286194b49d53SJani Nikula  */
ilk_compute_intermediate_wm(struct intel_atomic_state * state,struct intel_crtc * crtc)286294b49d53SJani Nikula static int ilk_compute_intermediate_wm(struct intel_atomic_state *state,
286394b49d53SJani Nikula 				       struct intel_crtc *crtc)
286494b49d53SJani Nikula {
286594b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
286694b49d53SJani Nikula 	struct intel_crtc_state *new_crtc_state =
286794b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
286894b49d53SJani Nikula 	const struct intel_crtc_state *old_crtc_state =
286994b49d53SJani Nikula 		intel_atomic_get_old_crtc_state(state, crtc);
287094b49d53SJani Nikula 	struct intel_pipe_wm *a = &new_crtc_state->wm.ilk.intermediate;
287194b49d53SJani Nikula 	const struct intel_pipe_wm *b = &old_crtc_state->wm.ilk.optimal;
287294b49d53SJani Nikula 	int level;
287394b49d53SJani Nikula 
287494b49d53SJani Nikula 	/*
287594b49d53SJani Nikula 	 * Start with the final, target watermarks, then combine with the
287694b49d53SJani Nikula 	 * currently active watermarks to get values that are safe both before
287794b49d53SJani Nikula 	 * and after the vblank.
287894b49d53SJani Nikula 	 */
287994b49d53SJani Nikula 	*a = new_crtc_state->wm.ilk.optimal;
288094b49d53SJani Nikula 	if (!new_crtc_state->hw.active ||
288194b49d53SJani Nikula 	    intel_crtc_needs_modeset(new_crtc_state) ||
288294b49d53SJani Nikula 	    state->skip_intermediate_wm)
288394b49d53SJani Nikula 		return 0;
288494b49d53SJani Nikula 
288594b49d53SJani Nikula 	a->pipe_enabled |= b->pipe_enabled;
288694b49d53SJani Nikula 	a->sprites_enabled |= b->sprites_enabled;
288794b49d53SJani Nikula 	a->sprites_scaled |= b->sprites_scaled;
288894b49d53SJani Nikula 
288994b49d53SJani Nikula 	for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
289094b49d53SJani Nikula 		struct intel_wm_level *a_wm = &a->wm[level];
289194b49d53SJani Nikula 		const struct intel_wm_level *b_wm = &b->wm[level];
289294b49d53SJani Nikula 
289394b49d53SJani Nikula 		a_wm->enable &= b_wm->enable;
289494b49d53SJani Nikula 		a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
289594b49d53SJani Nikula 		a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
289694b49d53SJani Nikula 		a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
289794b49d53SJani Nikula 		a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
289894b49d53SJani Nikula 	}
289994b49d53SJani Nikula 
290094b49d53SJani Nikula 	/*
290194b49d53SJani Nikula 	 * We need to make sure that these merged watermark values are
290294b49d53SJani Nikula 	 * actually a valid configuration themselves.  If they're not,
290394b49d53SJani Nikula 	 * there's no safe way to transition from the old state to
290494b49d53SJani Nikula 	 * the new state, so we need to fail the atomic transaction.
290594b49d53SJani Nikula 	 */
290694b49d53SJani Nikula 	if (!ilk_validate_pipe_wm(dev_priv, a))
290794b49d53SJani Nikula 		return -EINVAL;
290894b49d53SJani Nikula 
290994b49d53SJani Nikula 	/*
291094b49d53SJani Nikula 	 * If our intermediate WM are identical to the final WM, then we can
291194b49d53SJani Nikula 	 * omit the post-vblank programming; only update if it's different.
291294b49d53SJani Nikula 	 */
291394b49d53SJani Nikula 	if (memcmp(a, &new_crtc_state->wm.ilk.optimal, sizeof(*a)) != 0)
291494b49d53SJani Nikula 		new_crtc_state->wm.need_postvbl_update = true;
291594b49d53SJani Nikula 
291694b49d53SJani Nikula 	return 0;
291794b49d53SJani Nikula }
291894b49d53SJani Nikula 
291994b49d53SJani Nikula /*
292094b49d53SJani Nikula  * Merge the watermarks from all active pipes for a specific level.
292194b49d53SJani Nikula  */
ilk_merge_wm_level(struct drm_i915_private * dev_priv,int level,struct intel_wm_level * ret_wm)292294b49d53SJani Nikula static void ilk_merge_wm_level(struct drm_i915_private *dev_priv,
292394b49d53SJani Nikula 			       int level,
292494b49d53SJani Nikula 			       struct intel_wm_level *ret_wm)
292594b49d53SJani Nikula {
292694b49d53SJani Nikula 	const struct intel_crtc *crtc;
292794b49d53SJani Nikula 
292894b49d53SJani Nikula 	ret_wm->enable = true;
292994b49d53SJani Nikula 
293094b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
293194b49d53SJani Nikula 		const struct intel_pipe_wm *active = &crtc->wm.active.ilk;
293294b49d53SJani Nikula 		const struct intel_wm_level *wm = &active->wm[level];
293394b49d53SJani Nikula 
293494b49d53SJani Nikula 		if (!active->pipe_enabled)
293594b49d53SJani Nikula 			continue;
293694b49d53SJani Nikula 
293794b49d53SJani Nikula 		/*
293894b49d53SJani Nikula 		 * The watermark values may have been used in the past,
293994b49d53SJani Nikula 		 * so we must maintain them in the registers for some
294094b49d53SJani Nikula 		 * time even if the level is now disabled.
294194b49d53SJani Nikula 		 */
294294b49d53SJani Nikula 		if (!wm->enable)
294394b49d53SJani Nikula 			ret_wm->enable = false;
294494b49d53SJani Nikula 
294594b49d53SJani Nikula 		ret_wm->pri_val = max(ret_wm->pri_val, wm->pri_val);
294694b49d53SJani Nikula 		ret_wm->spr_val = max(ret_wm->spr_val, wm->spr_val);
294794b49d53SJani Nikula 		ret_wm->cur_val = max(ret_wm->cur_val, wm->cur_val);
294894b49d53SJani Nikula 		ret_wm->fbc_val = max(ret_wm->fbc_val, wm->fbc_val);
294994b49d53SJani Nikula 	}
295094b49d53SJani Nikula }
295194b49d53SJani Nikula 
295294b49d53SJani Nikula /*
295394b49d53SJani Nikula  * Merge all low power watermarks for all active pipes.
295494b49d53SJani Nikula  */
ilk_wm_merge(struct drm_i915_private * dev_priv,const struct intel_wm_config * config,const struct ilk_wm_maximums * max,struct intel_pipe_wm * merged)295594b49d53SJani Nikula static void ilk_wm_merge(struct drm_i915_private *dev_priv,
295694b49d53SJani Nikula 			 const struct intel_wm_config *config,
295794b49d53SJani Nikula 			 const struct ilk_wm_maximums *max,
295894b49d53SJani Nikula 			 struct intel_pipe_wm *merged)
295994b49d53SJani Nikula {
296094b49d53SJani Nikula 	int level, num_levels = dev_priv->display.wm.num_levels;
296194b49d53SJani Nikula 	int last_enabled_level = num_levels - 1;
296294b49d53SJani Nikula 
296394b49d53SJani Nikula 	/* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */
296494b49d53SJani Nikula 	if ((DISPLAY_VER(dev_priv) <= 6 || IS_IVYBRIDGE(dev_priv)) &&
296594b49d53SJani Nikula 	    config->num_pipes_active > 1)
296694b49d53SJani Nikula 		last_enabled_level = 0;
296794b49d53SJani Nikula 
296894b49d53SJani Nikula 	/* ILK: FBC WM must be disabled always */
296994b49d53SJani Nikula 	merged->fbc_wm_enabled = DISPLAY_VER(dev_priv) >= 6;
297094b49d53SJani Nikula 
297194b49d53SJani Nikula 	/* merge each WM1+ level */
297294b49d53SJani Nikula 	for (level = 1; level < num_levels; level++) {
297394b49d53SJani Nikula 		struct intel_wm_level *wm = &merged->wm[level];
297494b49d53SJani Nikula 
297594b49d53SJani Nikula 		ilk_merge_wm_level(dev_priv, level, wm);
297694b49d53SJani Nikula 
297794b49d53SJani Nikula 		if (level > last_enabled_level)
297894b49d53SJani Nikula 			wm->enable = false;
297994b49d53SJani Nikula 		else if (!ilk_validate_wm_level(level, max, wm))
298094b49d53SJani Nikula 			/* make sure all following levels get disabled */
298194b49d53SJani Nikula 			last_enabled_level = level - 1;
298294b49d53SJani Nikula 
298394b49d53SJani Nikula 		/*
298494b49d53SJani Nikula 		 * The spec says it is preferred to disable
298594b49d53SJani Nikula 		 * FBC WMs instead of disabling a WM level.
298694b49d53SJani Nikula 		 */
298794b49d53SJani Nikula 		if (wm->fbc_val > max->fbc) {
298894b49d53SJani Nikula 			if (wm->enable)
298994b49d53SJani Nikula 				merged->fbc_wm_enabled = false;
299094b49d53SJani Nikula 			wm->fbc_val = 0;
299194b49d53SJani Nikula 		}
299294b49d53SJani Nikula 	}
299394b49d53SJani Nikula 
299494b49d53SJani Nikula 	/* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */
299594b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) == 5 && HAS_FBC(dev_priv) &&
299694b49d53SJani Nikula 	    dev_priv->params.enable_fbc && !merged->fbc_wm_enabled) {
299794b49d53SJani Nikula 		for (level = 2; level < num_levels; level++) {
299894b49d53SJani Nikula 			struct intel_wm_level *wm = &merged->wm[level];
299994b49d53SJani Nikula 
300094b49d53SJani Nikula 			wm->enable = false;
300194b49d53SJani Nikula 		}
300294b49d53SJani Nikula 	}
300394b49d53SJani Nikula }
300494b49d53SJani Nikula 
ilk_wm_lp_to_level(int wm_lp,const struct intel_pipe_wm * pipe_wm)300594b49d53SJani Nikula static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm)
300694b49d53SJani Nikula {
300794b49d53SJani Nikula 	/* LP1,LP2,LP3 levels are either 1,2,3 or 1,3,4 */
300894b49d53SJani Nikula 	return wm_lp + (wm_lp >= 2 && pipe_wm->wm[4].enable);
300994b49d53SJani Nikula }
301094b49d53SJani Nikula 
301194b49d53SJani Nikula /* The value we need to program into the WM_LPx latency field */
ilk_wm_lp_latency(struct drm_i915_private * dev_priv,int level)301294b49d53SJani Nikula static unsigned int ilk_wm_lp_latency(struct drm_i915_private *dev_priv,
301394b49d53SJani Nikula 				      int level)
301494b49d53SJani Nikula {
301594b49d53SJani Nikula 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
301694b49d53SJani Nikula 		return 2 * level;
301794b49d53SJani Nikula 	else
301894b49d53SJani Nikula 		return dev_priv->display.wm.pri_latency[level];
301994b49d53SJani Nikula }
302094b49d53SJani Nikula 
ilk_compute_wm_results(struct drm_i915_private * dev_priv,const struct intel_pipe_wm * merged,enum intel_ddb_partitioning partitioning,struct ilk_wm_values * results)302194b49d53SJani Nikula static void ilk_compute_wm_results(struct drm_i915_private *dev_priv,
302294b49d53SJani Nikula 				   const struct intel_pipe_wm *merged,
302394b49d53SJani Nikula 				   enum intel_ddb_partitioning partitioning,
302494b49d53SJani Nikula 				   struct ilk_wm_values *results)
302594b49d53SJani Nikula {
302694b49d53SJani Nikula 	struct intel_crtc *crtc;
302794b49d53SJani Nikula 	int level, wm_lp;
302894b49d53SJani Nikula 
302994b49d53SJani Nikula 	results->enable_fbc_wm = merged->fbc_wm_enabled;
303094b49d53SJani Nikula 	results->partitioning = partitioning;
303194b49d53SJani Nikula 
303294b49d53SJani Nikula 	/* LP1+ register values */
303394b49d53SJani Nikula 	for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
303494b49d53SJani Nikula 		const struct intel_wm_level *r;
303594b49d53SJani Nikula 
303694b49d53SJani Nikula 		level = ilk_wm_lp_to_level(wm_lp, merged);
303794b49d53SJani Nikula 
303894b49d53SJani Nikula 		r = &merged->wm[level];
303994b49d53SJani Nikula 
304094b49d53SJani Nikula 		/*
304194b49d53SJani Nikula 		 * Maintain the watermark values even if the level is
304294b49d53SJani Nikula 		 * disabled. Doing otherwise could cause underruns.
304394b49d53SJani Nikula 		 */
304494b49d53SJani Nikula 		results->wm_lp[wm_lp - 1] =
304594b49d53SJani Nikula 			WM_LP_LATENCY(ilk_wm_lp_latency(dev_priv, level)) |
304694b49d53SJani Nikula 			WM_LP_PRIMARY(r->pri_val) |
304794b49d53SJani Nikula 			WM_LP_CURSOR(r->cur_val);
304894b49d53SJani Nikula 
304994b49d53SJani Nikula 		if (r->enable)
305094b49d53SJani Nikula 			results->wm_lp[wm_lp - 1] |= WM_LP_ENABLE;
305194b49d53SJani Nikula 
305294b49d53SJani Nikula 		if (DISPLAY_VER(dev_priv) >= 8)
305394b49d53SJani Nikula 			results->wm_lp[wm_lp - 1] |= WM_LP_FBC_BDW(r->fbc_val);
305494b49d53SJani Nikula 		else
305594b49d53SJani Nikula 			results->wm_lp[wm_lp - 1] |= WM_LP_FBC_ILK(r->fbc_val);
305694b49d53SJani Nikula 
305794b49d53SJani Nikula 		results->wm_lp_spr[wm_lp - 1] = WM_LP_SPRITE(r->spr_val);
305894b49d53SJani Nikula 
305994b49d53SJani Nikula 		/*
306094b49d53SJani Nikula 		 * Always set WM_LP_SPRITE_EN when spr_val != 0, even if the
306194b49d53SJani Nikula 		 * level is disabled. Doing otherwise could cause underruns.
306294b49d53SJani Nikula 		 */
306394b49d53SJani Nikula 		if (DISPLAY_VER(dev_priv) <= 6 && r->spr_val) {
306494b49d53SJani Nikula 			drm_WARN_ON(&dev_priv->drm, wm_lp != 1);
306594b49d53SJani Nikula 			results->wm_lp_spr[wm_lp - 1] |= WM_LP_SPRITE_ENABLE;
306694b49d53SJani Nikula 		}
306794b49d53SJani Nikula 	}
306894b49d53SJani Nikula 
306994b49d53SJani Nikula 	/* LP0 register values */
307094b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
307194b49d53SJani Nikula 		enum pipe pipe = crtc->pipe;
307294b49d53SJani Nikula 		const struct intel_pipe_wm *pipe_wm = &crtc->wm.active.ilk;
307394b49d53SJani Nikula 		const struct intel_wm_level *r = &pipe_wm->wm[0];
307494b49d53SJani Nikula 
307594b49d53SJani Nikula 		if (drm_WARN_ON(&dev_priv->drm, !r->enable))
307694b49d53SJani Nikula 			continue;
307794b49d53SJani Nikula 
307894b49d53SJani Nikula 		results->wm_pipe[pipe] =
307994b49d53SJani Nikula 			WM0_PIPE_PRIMARY(r->pri_val) |
308094b49d53SJani Nikula 			WM0_PIPE_SPRITE(r->spr_val) |
308194b49d53SJani Nikula 			WM0_PIPE_CURSOR(r->cur_val);
308294b49d53SJani Nikula 	}
308394b49d53SJani Nikula }
308494b49d53SJani Nikula 
308594b49d53SJani Nikula /*
308694b49d53SJani Nikula  * Find the result with the highest level enabled. Check for enable_fbc_wm in
308794b49d53SJani Nikula  * case both are at the same level. Prefer r1 in case they're the same.
308894b49d53SJani Nikula  */
308994b49d53SJani Nikula static struct intel_pipe_wm *
ilk_find_best_result(struct drm_i915_private * dev_priv,struct intel_pipe_wm * r1,struct intel_pipe_wm * r2)309094b49d53SJani Nikula ilk_find_best_result(struct drm_i915_private *dev_priv,
309194b49d53SJani Nikula 		     struct intel_pipe_wm *r1,
309294b49d53SJani Nikula 		     struct intel_pipe_wm *r2)
309394b49d53SJani Nikula {
309494b49d53SJani Nikula 	int level, level1 = 0, level2 = 0;
309594b49d53SJani Nikula 
309694b49d53SJani Nikula 	for (level = 1; level < dev_priv->display.wm.num_levels; level++) {
309794b49d53SJani Nikula 		if (r1->wm[level].enable)
309894b49d53SJani Nikula 			level1 = level;
309994b49d53SJani Nikula 		if (r2->wm[level].enable)
310094b49d53SJani Nikula 			level2 = level;
310194b49d53SJani Nikula 	}
310294b49d53SJani Nikula 
310394b49d53SJani Nikula 	if (level1 == level2) {
310494b49d53SJani Nikula 		if (r2->fbc_wm_enabled && !r1->fbc_wm_enabled)
310594b49d53SJani Nikula 			return r2;
310694b49d53SJani Nikula 		else
310794b49d53SJani Nikula 			return r1;
310894b49d53SJani Nikula 	} else if (level1 > level2) {
310994b49d53SJani Nikula 		return r1;
311094b49d53SJani Nikula 	} else {
311194b49d53SJani Nikula 		return r2;
311294b49d53SJani Nikula 	}
311394b49d53SJani Nikula }
311494b49d53SJani Nikula 
311594b49d53SJani Nikula /* dirty bits used to track which watermarks need changes */
311694b49d53SJani Nikula #define WM_DIRTY_PIPE(pipe) (1 << (pipe))
311794b49d53SJani Nikula #define WM_DIRTY_LP(wm_lp) (1 << (15 + (wm_lp)))
311894b49d53SJani Nikula #define WM_DIRTY_LP_ALL (WM_DIRTY_LP(1) | WM_DIRTY_LP(2) | WM_DIRTY_LP(3))
311994b49d53SJani Nikula #define WM_DIRTY_FBC (1 << 24)
312094b49d53SJani Nikula #define WM_DIRTY_DDB (1 << 25)
312194b49d53SJani Nikula 
ilk_compute_wm_dirty(struct drm_i915_private * dev_priv,const struct ilk_wm_values * old,const struct ilk_wm_values * new)312294b49d53SJani Nikula static unsigned int ilk_compute_wm_dirty(struct drm_i915_private *dev_priv,
312394b49d53SJani Nikula 					 const struct ilk_wm_values *old,
312494b49d53SJani Nikula 					 const struct ilk_wm_values *new)
312594b49d53SJani Nikula {
312694b49d53SJani Nikula 	unsigned int dirty = 0;
312794b49d53SJani Nikula 	enum pipe pipe;
312894b49d53SJani Nikula 	int wm_lp;
312994b49d53SJani Nikula 
313094b49d53SJani Nikula 	for_each_pipe(dev_priv, pipe) {
313194b49d53SJani Nikula 		if (old->wm_pipe[pipe] != new->wm_pipe[pipe]) {
313294b49d53SJani Nikula 			dirty |= WM_DIRTY_PIPE(pipe);
313394b49d53SJani Nikula 			/* Must disable LP1+ watermarks too */
313494b49d53SJani Nikula 			dirty |= WM_DIRTY_LP_ALL;
313594b49d53SJani Nikula 		}
313694b49d53SJani Nikula 	}
313794b49d53SJani Nikula 
313894b49d53SJani Nikula 	if (old->enable_fbc_wm != new->enable_fbc_wm) {
313994b49d53SJani Nikula 		dirty |= WM_DIRTY_FBC;
314094b49d53SJani Nikula 		/* Must disable LP1+ watermarks too */
314194b49d53SJani Nikula 		dirty |= WM_DIRTY_LP_ALL;
314294b49d53SJani Nikula 	}
314394b49d53SJani Nikula 
314494b49d53SJani Nikula 	if (old->partitioning != new->partitioning) {
314594b49d53SJani Nikula 		dirty |= WM_DIRTY_DDB;
314694b49d53SJani Nikula 		/* Must disable LP1+ watermarks too */
314794b49d53SJani Nikula 		dirty |= WM_DIRTY_LP_ALL;
314894b49d53SJani Nikula 	}
314994b49d53SJani Nikula 
315094b49d53SJani Nikula 	/* LP1+ watermarks already deemed dirty, no need to continue */
315194b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP_ALL)
315294b49d53SJani Nikula 		return dirty;
315394b49d53SJani Nikula 
315494b49d53SJani Nikula 	/* Find the lowest numbered LP1+ watermark in need of an update... */
315594b49d53SJani Nikula 	for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
315694b49d53SJani Nikula 		if (old->wm_lp[wm_lp - 1] != new->wm_lp[wm_lp - 1] ||
315794b49d53SJani Nikula 		    old->wm_lp_spr[wm_lp - 1] != new->wm_lp_spr[wm_lp - 1])
315894b49d53SJani Nikula 			break;
315994b49d53SJani Nikula 	}
316094b49d53SJani Nikula 
316194b49d53SJani Nikula 	/* ...and mark it and all higher numbered LP1+ watermarks as dirty */
316294b49d53SJani Nikula 	for (; wm_lp <= 3; wm_lp++)
316394b49d53SJani Nikula 		dirty |= WM_DIRTY_LP(wm_lp);
316494b49d53SJani Nikula 
316594b49d53SJani Nikula 	return dirty;
316694b49d53SJani Nikula }
316794b49d53SJani Nikula 
_ilk_disable_lp_wm(struct drm_i915_private * dev_priv,unsigned int dirty)316894b49d53SJani Nikula static bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv,
316994b49d53SJani Nikula 			       unsigned int dirty)
317094b49d53SJani Nikula {
317194b49d53SJani Nikula 	struct ilk_wm_values *previous = &dev_priv->display.wm.hw;
317294b49d53SJani Nikula 	bool changed = false;
317394b49d53SJani Nikula 
317494b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM_LP_ENABLE) {
317594b49d53SJani Nikula 		previous->wm_lp[2] &= ~WM_LP_ENABLE;
317694b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM3_LP_ILK, previous->wm_lp[2]);
317794b49d53SJani Nikula 		changed = true;
317894b49d53SJani Nikula 	}
317994b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM_LP_ENABLE) {
318094b49d53SJani Nikula 		previous->wm_lp[1] &= ~WM_LP_ENABLE;
318194b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM2_LP_ILK, previous->wm_lp[1]);
318294b49d53SJani Nikula 		changed = true;
318394b49d53SJani Nikula 	}
318494b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM_LP_ENABLE) {
318594b49d53SJani Nikula 		previous->wm_lp[0] &= ~WM_LP_ENABLE;
318694b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM1_LP_ILK, previous->wm_lp[0]);
318794b49d53SJani Nikula 		changed = true;
318894b49d53SJani Nikula 	}
318994b49d53SJani Nikula 
319094b49d53SJani Nikula 	/*
319194b49d53SJani Nikula 	 * Don't touch WM_LP_SPRITE_ENABLE here.
319294b49d53SJani Nikula 	 * Doing so could cause underruns.
319394b49d53SJani Nikula 	 */
319494b49d53SJani Nikula 
319594b49d53SJani Nikula 	return changed;
319694b49d53SJani Nikula }
319794b49d53SJani Nikula 
319894b49d53SJani Nikula /*
319994b49d53SJani Nikula  * The spec says we shouldn't write when we don't need, because every write
320094b49d53SJani Nikula  * causes WMs to be re-evaluated, expending some power.
320194b49d53SJani Nikula  */
ilk_write_wm_values(struct drm_i915_private * dev_priv,struct ilk_wm_values * results)320294b49d53SJani Nikula static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
320394b49d53SJani Nikula 				struct ilk_wm_values *results)
320494b49d53SJani Nikula {
320594b49d53SJani Nikula 	struct ilk_wm_values *previous = &dev_priv->display.wm.hw;
320694b49d53SJani Nikula 	unsigned int dirty;
320794b49d53SJani Nikula 
320894b49d53SJani Nikula 	dirty = ilk_compute_wm_dirty(dev_priv, previous, results);
320994b49d53SJani Nikula 	if (!dirty)
321094b49d53SJani Nikula 		return;
321194b49d53SJani Nikula 
321294b49d53SJani Nikula 	_ilk_disable_lp_wm(dev_priv, dirty);
321394b49d53SJani Nikula 
321494b49d53SJani Nikula 	if (dirty & WM_DIRTY_PIPE(PIPE_A))
321594b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM0_PIPE_ILK(PIPE_A), results->wm_pipe[0]);
321694b49d53SJani Nikula 	if (dirty & WM_DIRTY_PIPE(PIPE_B))
321794b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM0_PIPE_ILK(PIPE_B), results->wm_pipe[1]);
321894b49d53SJani Nikula 	if (dirty & WM_DIRTY_PIPE(PIPE_C))
321994b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM0_PIPE_ILK(PIPE_C), results->wm_pipe[2]);
322094b49d53SJani Nikula 
322194b49d53SJani Nikula 	if (dirty & WM_DIRTY_DDB) {
322294b49d53SJani Nikula 		if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
322394b49d53SJani Nikula 			intel_uncore_rmw(&dev_priv->uncore, WM_MISC, WM_MISC_DATA_PARTITION_5_6,
322494b49d53SJani Nikula 					 results->partitioning == INTEL_DDB_PART_1_2 ? 0 :
322594b49d53SJani Nikula 					 WM_MISC_DATA_PARTITION_5_6);
322694b49d53SJani Nikula 		else
322794b49d53SJani Nikula 			intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL2, DISP_DATA_PARTITION_5_6,
322894b49d53SJani Nikula 					 results->partitioning == INTEL_DDB_PART_1_2 ? 0 :
322994b49d53SJani Nikula 					 DISP_DATA_PARTITION_5_6);
323094b49d53SJani Nikula 	}
323194b49d53SJani Nikula 
323294b49d53SJani Nikula 	if (dirty & WM_DIRTY_FBC)
323394b49d53SJani Nikula 		intel_uncore_rmw(&dev_priv->uncore, DISP_ARB_CTL, DISP_FBC_WM_DIS,
323494b49d53SJani Nikula 				 results->enable_fbc_wm ? 0 : DISP_FBC_WM_DIS);
323594b49d53SJani Nikula 
323694b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP(1) &&
323794b49d53SJani Nikula 	    previous->wm_lp_spr[0] != results->wm_lp_spr[0])
323894b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM1S_LP_ILK, results->wm_lp_spr[0]);
323994b49d53SJani Nikula 
324094b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) >= 7) {
324194b49d53SJani Nikula 		if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1])
324294b49d53SJani Nikula 			intel_uncore_write(&dev_priv->uncore, WM2S_LP_IVB, results->wm_lp_spr[1]);
324394b49d53SJani Nikula 		if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2])
324494b49d53SJani Nikula 			intel_uncore_write(&dev_priv->uncore, WM3S_LP_IVB, results->wm_lp_spr[2]);
324594b49d53SJani Nikula 	}
324694b49d53SJani Nikula 
324794b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != results->wm_lp[0])
324894b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM1_LP_ILK, results->wm_lp[0]);
324994b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != results->wm_lp[1])
325094b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM2_LP_ILK, results->wm_lp[1]);
325194b49d53SJani Nikula 	if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != results->wm_lp[2])
325294b49d53SJani Nikula 		intel_uncore_write(&dev_priv->uncore, WM3_LP_ILK, results->wm_lp[2]);
325394b49d53SJani Nikula 
325494b49d53SJani Nikula 	dev_priv->display.wm.hw = *results;
325594b49d53SJani Nikula }
325694b49d53SJani Nikula 
ilk_disable_lp_wm(struct drm_i915_private * dev_priv)325794b49d53SJani Nikula bool ilk_disable_lp_wm(struct drm_i915_private *dev_priv)
325894b49d53SJani Nikula {
325994b49d53SJani Nikula 	return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
326094b49d53SJani Nikula }
326194b49d53SJani Nikula 
ilk_compute_wm_config(struct drm_i915_private * dev_priv,struct intel_wm_config * config)326294b49d53SJani Nikula static void ilk_compute_wm_config(struct drm_i915_private *dev_priv,
326394b49d53SJani Nikula 				  struct intel_wm_config *config)
326494b49d53SJani Nikula {
326594b49d53SJani Nikula 	struct intel_crtc *crtc;
326694b49d53SJani Nikula 
326794b49d53SJani Nikula 	/* Compute the currently _active_ config */
326894b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
326994b49d53SJani Nikula 		const struct intel_pipe_wm *wm = &crtc->wm.active.ilk;
327094b49d53SJani Nikula 
327194b49d53SJani Nikula 		if (!wm->pipe_enabled)
327294b49d53SJani Nikula 			continue;
327394b49d53SJani Nikula 
327494b49d53SJani Nikula 		config->sprites_enabled |= wm->sprites_enabled;
327594b49d53SJani Nikula 		config->sprites_scaled |= wm->sprites_scaled;
327694b49d53SJani Nikula 		config->num_pipes_active++;
327794b49d53SJani Nikula 	}
327894b49d53SJani Nikula }
327994b49d53SJani Nikula 
ilk_program_watermarks(struct drm_i915_private * dev_priv)328094b49d53SJani Nikula static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
328194b49d53SJani Nikula {
328294b49d53SJani Nikula 	struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
328394b49d53SJani Nikula 	struct ilk_wm_maximums max;
328494b49d53SJani Nikula 	struct intel_wm_config config = {};
328594b49d53SJani Nikula 	struct ilk_wm_values results = {};
328694b49d53SJani Nikula 	enum intel_ddb_partitioning partitioning;
328794b49d53SJani Nikula 
328894b49d53SJani Nikula 	ilk_compute_wm_config(dev_priv, &config);
328994b49d53SJani Nikula 
329094b49d53SJani Nikula 	ilk_compute_wm_maximums(dev_priv, 1, &config, INTEL_DDB_PART_1_2, &max);
329194b49d53SJani Nikula 	ilk_wm_merge(dev_priv, &config, &max, &lp_wm_1_2);
329294b49d53SJani Nikula 
329394b49d53SJani Nikula 	/* 5/6 split only in single pipe config on IVB+ */
329494b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) >= 7 &&
329594b49d53SJani Nikula 	    config.num_pipes_active == 1 && config.sprites_enabled) {
329694b49d53SJani Nikula 		ilk_compute_wm_maximums(dev_priv, 1, &config, INTEL_DDB_PART_5_6, &max);
329794b49d53SJani Nikula 		ilk_wm_merge(dev_priv, &config, &max, &lp_wm_5_6);
329894b49d53SJani Nikula 
329994b49d53SJani Nikula 		best_lp_wm = ilk_find_best_result(dev_priv, &lp_wm_1_2, &lp_wm_5_6);
330094b49d53SJani Nikula 	} else {
330194b49d53SJani Nikula 		best_lp_wm = &lp_wm_1_2;
330294b49d53SJani Nikula 	}
330394b49d53SJani Nikula 
330494b49d53SJani Nikula 	partitioning = (best_lp_wm == &lp_wm_1_2) ?
330594b49d53SJani Nikula 		       INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6;
330694b49d53SJani Nikula 
330794b49d53SJani Nikula 	ilk_compute_wm_results(dev_priv, best_lp_wm, partitioning, &results);
330894b49d53SJani Nikula 
330994b49d53SJani Nikula 	ilk_write_wm_values(dev_priv, &results);
331094b49d53SJani Nikula }
331194b49d53SJani Nikula 
ilk_initial_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)331294b49d53SJani Nikula static void ilk_initial_watermarks(struct intel_atomic_state *state,
331394b49d53SJani Nikula 				   struct intel_crtc *crtc)
331494b49d53SJani Nikula {
331594b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
331694b49d53SJani Nikula 	const struct intel_crtc_state *crtc_state =
331794b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
331894b49d53SJani Nikula 
331994b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
332094b49d53SJani Nikula 	crtc->wm.active.ilk = crtc_state->wm.ilk.intermediate;
332194b49d53SJani Nikula 	ilk_program_watermarks(dev_priv);
332294b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
332394b49d53SJani Nikula }
332494b49d53SJani Nikula 
ilk_optimize_watermarks(struct intel_atomic_state * state,struct intel_crtc * crtc)332594b49d53SJani Nikula static void ilk_optimize_watermarks(struct intel_atomic_state *state,
332694b49d53SJani Nikula 				    struct intel_crtc *crtc)
332794b49d53SJani Nikula {
332894b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
332994b49d53SJani Nikula 	const struct intel_crtc_state *crtc_state =
333094b49d53SJani Nikula 		intel_atomic_get_new_crtc_state(state, crtc);
333194b49d53SJani Nikula 
333294b49d53SJani Nikula 	if (!crtc_state->wm.need_postvbl_update)
333394b49d53SJani Nikula 		return;
333494b49d53SJani Nikula 
333594b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
333694b49d53SJani Nikula 	crtc->wm.active.ilk = crtc_state->wm.ilk.optimal;
333794b49d53SJani Nikula 	ilk_program_watermarks(dev_priv);
333894b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
333994b49d53SJani Nikula }
334094b49d53SJani Nikula 
ilk_pipe_wm_get_hw_state(struct intel_crtc * crtc)334194b49d53SJani Nikula static void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
334294b49d53SJani Nikula {
334394b49d53SJani Nikula 	struct drm_device *dev = crtc->base.dev;
334494b49d53SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(dev);
334594b49d53SJani Nikula 	struct ilk_wm_values *hw = &dev_priv->display.wm.hw;
334694b49d53SJani Nikula 	struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
334794b49d53SJani Nikula 	struct intel_pipe_wm *active = &crtc_state->wm.ilk.optimal;
334894b49d53SJani Nikula 	enum pipe pipe = crtc->pipe;
334994b49d53SJani Nikula 
335094b49d53SJani Nikula 	hw->wm_pipe[pipe] = intel_uncore_read(&dev_priv->uncore, WM0_PIPE_ILK(pipe));
335194b49d53SJani Nikula 
335294b49d53SJani Nikula 	memset(active, 0, sizeof(*active));
335394b49d53SJani Nikula 
335494b49d53SJani Nikula 	active->pipe_enabled = crtc->active;
335594b49d53SJani Nikula 
335694b49d53SJani Nikula 	if (active->pipe_enabled) {
335794b49d53SJani Nikula 		u32 tmp = hw->wm_pipe[pipe];
335894b49d53SJani Nikula 
335994b49d53SJani Nikula 		/*
336094b49d53SJani Nikula 		 * For active pipes LP0 watermark is marked as
336194b49d53SJani Nikula 		 * enabled, and LP1+ watermaks as disabled since
336294b49d53SJani Nikula 		 * we can't really reverse compute them in case
336394b49d53SJani Nikula 		 * multiple pipes are active.
336494b49d53SJani Nikula 		 */
336594b49d53SJani Nikula 		active->wm[0].enable = true;
336694b49d53SJani Nikula 		active->wm[0].pri_val = REG_FIELD_GET(WM0_PIPE_PRIMARY_MASK, tmp);
336794b49d53SJani Nikula 		active->wm[0].spr_val = REG_FIELD_GET(WM0_PIPE_SPRITE_MASK, tmp);
336894b49d53SJani Nikula 		active->wm[0].cur_val = REG_FIELD_GET(WM0_PIPE_CURSOR_MASK, tmp);
336994b49d53SJani Nikula 	} else {
337094b49d53SJani Nikula 		int level;
337194b49d53SJani Nikula 
337294b49d53SJani Nikula 		/*
337394b49d53SJani Nikula 		 * For inactive pipes, all watermark levels
337494b49d53SJani Nikula 		 * should be marked as enabled but zeroed,
337594b49d53SJani Nikula 		 * which is what we'd compute them to.
337694b49d53SJani Nikula 		 */
337794b49d53SJani Nikula 		for (level = 0; level < dev_priv->display.wm.num_levels; level++)
337894b49d53SJani Nikula 			active->wm[level].enable = true;
337994b49d53SJani Nikula 	}
338094b49d53SJani Nikula 
338194b49d53SJani Nikula 	crtc->wm.active.ilk = *active;
338294b49d53SJani Nikula }
338394b49d53SJani Nikula 
ilk_sanitize_watermarks_add_affected(struct drm_atomic_state * state)33843dadb4a1SJani Nikula static int ilk_sanitize_watermarks_add_affected(struct drm_atomic_state *state)
33853dadb4a1SJani Nikula {
33863dadb4a1SJani Nikula 	struct drm_plane *plane;
33873dadb4a1SJani Nikula 	struct intel_crtc *crtc;
33883dadb4a1SJani Nikula 
33893dadb4a1SJani Nikula 	for_each_intel_crtc(state->dev, crtc) {
33903dadb4a1SJani Nikula 		struct intel_crtc_state *crtc_state;
33913dadb4a1SJani Nikula 
33923dadb4a1SJani Nikula 		crtc_state = intel_atomic_get_crtc_state(state, crtc);
33933dadb4a1SJani Nikula 		if (IS_ERR(crtc_state))
33943dadb4a1SJani Nikula 			return PTR_ERR(crtc_state);
33953dadb4a1SJani Nikula 
33963dadb4a1SJani Nikula 		if (crtc_state->hw.active) {
33973dadb4a1SJani Nikula 			/*
33983dadb4a1SJani Nikula 			 * Preserve the inherited flag to avoid
33993dadb4a1SJani Nikula 			 * taking the full modeset path.
34003dadb4a1SJani Nikula 			 */
34013dadb4a1SJani Nikula 			crtc_state->inherited = true;
34023dadb4a1SJani Nikula 		}
34033dadb4a1SJani Nikula 	}
34043dadb4a1SJani Nikula 
34053dadb4a1SJani Nikula 	drm_for_each_plane(plane, state->dev) {
34063dadb4a1SJani Nikula 		struct drm_plane_state *plane_state;
34073dadb4a1SJani Nikula 
34083dadb4a1SJani Nikula 		plane_state = drm_atomic_get_plane_state(state, plane);
34093dadb4a1SJani Nikula 		if (IS_ERR(plane_state))
34103dadb4a1SJani Nikula 			return PTR_ERR(plane_state);
34113dadb4a1SJani Nikula 	}
34123dadb4a1SJani Nikula 
34133dadb4a1SJani Nikula 	return 0;
34143dadb4a1SJani Nikula }
34153dadb4a1SJani Nikula 
34163dadb4a1SJani Nikula /*
34173dadb4a1SJani Nikula  * Calculate what we think the watermarks should be for the state we've read
34183dadb4a1SJani Nikula  * out of the hardware and then immediately program those watermarks so that
34193dadb4a1SJani Nikula  * we ensure the hardware settings match our internal state.
34203dadb4a1SJani Nikula  *
34213dadb4a1SJani Nikula  * We can calculate what we think WM's should be by creating a duplicate of the
34223dadb4a1SJani Nikula  * current state (which was constructed during hardware readout) and running it
34233dadb4a1SJani Nikula  * through the atomic check code to calculate new watermark values in the
34243dadb4a1SJani Nikula  * state object.
34253dadb4a1SJani Nikula  */
ilk_wm_sanitize(struct drm_i915_private * dev_priv)34263dadb4a1SJani Nikula void ilk_wm_sanitize(struct drm_i915_private *dev_priv)
34273dadb4a1SJani Nikula {
34283dadb4a1SJani Nikula 	struct drm_atomic_state *state;
34293dadb4a1SJani Nikula 	struct intel_atomic_state *intel_state;
34303dadb4a1SJani Nikula 	struct intel_crtc *crtc;
34313dadb4a1SJani Nikula 	struct intel_crtc_state *crtc_state;
34323dadb4a1SJani Nikula 	struct drm_modeset_acquire_ctx ctx;
34333dadb4a1SJani Nikula 	int ret;
34343dadb4a1SJani Nikula 	int i;
34353dadb4a1SJani Nikula 
34363dadb4a1SJani Nikula 	/* Only supported on platforms that use atomic watermark design */
34373dadb4a1SJani Nikula 	if (!dev_priv->display.funcs.wm->optimize_watermarks)
34383dadb4a1SJani Nikula 		return;
34393dadb4a1SJani Nikula 
34407380f545SJani Nikula 	if (drm_WARN_ON(&dev_priv->drm, DISPLAY_VER(dev_priv) >= 9))
34417380f545SJani Nikula 		return;
34427380f545SJani Nikula 
34433dadb4a1SJani Nikula 	state = drm_atomic_state_alloc(&dev_priv->drm);
34443dadb4a1SJani Nikula 	if (drm_WARN_ON(&dev_priv->drm, !state))
34453dadb4a1SJani Nikula 		return;
34463dadb4a1SJani Nikula 
34473dadb4a1SJani Nikula 	intel_state = to_intel_atomic_state(state);
34483dadb4a1SJani Nikula 
34493dadb4a1SJani Nikula 	drm_modeset_acquire_init(&ctx, 0);
34503dadb4a1SJani Nikula 
34513dadb4a1SJani Nikula 	state->acquire_ctx = &ctx;
345276ec6927SVille Syrjälä 	to_intel_atomic_state(state)->internal = true;
34533dadb4a1SJani Nikula 
345476ec6927SVille Syrjälä retry:
34553dadb4a1SJani Nikula 	/*
34563dadb4a1SJani Nikula 	 * Hardware readout is the only time we don't want to calculate
34573dadb4a1SJani Nikula 	 * intermediate watermarks (since we don't trust the current
34583dadb4a1SJani Nikula 	 * watermarks).
34593dadb4a1SJani Nikula 	 */
34603dadb4a1SJani Nikula 	if (!HAS_GMCH(dev_priv))
34613dadb4a1SJani Nikula 		intel_state->skip_intermediate_wm = true;
34623dadb4a1SJani Nikula 
34633dadb4a1SJani Nikula 	ret = ilk_sanitize_watermarks_add_affected(state);
34643dadb4a1SJani Nikula 	if (ret)
34653dadb4a1SJani Nikula 		goto fail;
34663dadb4a1SJani Nikula 
34673dadb4a1SJani Nikula 	ret = intel_atomic_check(&dev_priv->drm, state);
34683dadb4a1SJani Nikula 	if (ret)
34693dadb4a1SJani Nikula 		goto fail;
34703dadb4a1SJani Nikula 
34713dadb4a1SJani Nikula 	/* Write calculated watermark values back */
34723dadb4a1SJani Nikula 	for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) {
34733dadb4a1SJani Nikula 		crtc_state->wm.need_postvbl_update = true;
34743dadb4a1SJani Nikula 		intel_optimize_watermarks(intel_state, crtc);
34753dadb4a1SJani Nikula 
34763dadb4a1SJani Nikula 		to_intel_crtc_state(crtc->base.state)->wm = crtc_state->wm;
34773dadb4a1SJani Nikula 	}
34783dadb4a1SJani Nikula 
34793dadb4a1SJani Nikula fail:
34803dadb4a1SJani Nikula 	if (ret == -EDEADLK) {
34813dadb4a1SJani Nikula 		drm_atomic_state_clear(state);
34823dadb4a1SJani Nikula 		drm_modeset_backoff(&ctx);
34833dadb4a1SJani Nikula 		goto retry;
34843dadb4a1SJani Nikula 	}
34853dadb4a1SJani Nikula 
34863dadb4a1SJani Nikula 	/*
34873dadb4a1SJani Nikula 	 * If we fail here, it means that the hardware appears to be
34883dadb4a1SJani Nikula 	 * programmed in a way that shouldn't be possible, given our
34893dadb4a1SJani Nikula 	 * understanding of watermark requirements.  This might mean a
34903dadb4a1SJani Nikula 	 * mistake in the hardware readout code or a mistake in the
34913dadb4a1SJani Nikula 	 * watermark calculations for a given platform.  Raise a WARN
34923dadb4a1SJani Nikula 	 * so that this is noticeable.
34933dadb4a1SJani Nikula 	 *
34943dadb4a1SJani Nikula 	 * If this actually happens, we'll have to just leave the
34953dadb4a1SJani Nikula 	 * BIOS-programmed watermarks untouched and hope for the best.
34963dadb4a1SJani Nikula 	 */
34973dadb4a1SJani Nikula 	drm_WARN(&dev_priv->drm, ret,
34983dadb4a1SJani Nikula 		 "Could not determine valid watermarks for inherited state\n");
34993dadb4a1SJani Nikula 
35003dadb4a1SJani Nikula 	drm_atomic_state_put(state);
35013dadb4a1SJani Nikula 
35023dadb4a1SJani Nikula 	drm_modeset_drop_locks(&ctx);
35033dadb4a1SJani Nikula 	drm_modeset_acquire_fini(&ctx);
35043dadb4a1SJani Nikula }
35053dadb4a1SJani Nikula 
350694b49d53SJani Nikula #define _FW_WM(value, plane) \
350794b49d53SJani Nikula 	(((value) & DSPFW_ ## plane ## _MASK) >> DSPFW_ ## plane ## _SHIFT)
350894b49d53SJani Nikula #define _FW_WM_VLV(value, plane) \
350994b49d53SJani Nikula 	(((value) & DSPFW_ ## plane ## _MASK_VLV) >> DSPFW_ ## plane ## _SHIFT)
351094b49d53SJani Nikula 
g4x_read_wm_values(struct drm_i915_private * dev_priv,struct g4x_wm_values * wm)351194b49d53SJani Nikula static void g4x_read_wm_values(struct drm_i915_private *dev_priv,
351294b49d53SJani Nikula 			       struct g4x_wm_values *wm)
351394b49d53SJani Nikula {
351494b49d53SJani Nikula 	u32 tmp;
351594b49d53SJani Nikula 
351694b49d53SJani Nikula 	tmp = intel_uncore_read(&dev_priv->uncore, DSPFW1);
351794b49d53SJani Nikula 	wm->sr.plane = _FW_WM(tmp, SR);
351894b49d53SJani Nikula 	wm->pipe[PIPE_B].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORB);
351994b49d53SJani Nikula 	wm->pipe[PIPE_B].plane[PLANE_PRIMARY] = _FW_WM(tmp, PLANEB);
352094b49d53SJani Nikula 	wm->pipe[PIPE_A].plane[PLANE_PRIMARY] = _FW_WM(tmp, PLANEA);
352194b49d53SJani Nikula 
352294b49d53SJani Nikula 	tmp = intel_uncore_read(&dev_priv->uncore, DSPFW2);
352394b49d53SJani Nikula 	wm->fbc_en = tmp & DSPFW_FBC_SR_EN;
352494b49d53SJani Nikula 	wm->sr.fbc = _FW_WM(tmp, FBC_SR);
352594b49d53SJani Nikula 	wm->hpll.fbc = _FW_WM(tmp, FBC_HPLL_SR);
352694b49d53SJani Nikula 	wm->pipe[PIPE_B].plane[PLANE_SPRITE0] = _FW_WM(tmp, SPRITEB);
352794b49d53SJani Nikula 	wm->pipe[PIPE_A].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORA);
352894b49d53SJani Nikula 	wm->pipe[PIPE_A].plane[PLANE_SPRITE0] = _FW_WM(tmp, SPRITEA);
352994b49d53SJani Nikula 
353094b49d53SJani Nikula 	tmp = intel_uncore_read(&dev_priv->uncore, DSPFW3);
353194b49d53SJani Nikula 	wm->hpll_en = tmp & DSPFW_HPLL_SR_EN;
353294b49d53SJani Nikula 	wm->sr.cursor = _FW_WM(tmp, CURSOR_SR);
353394b49d53SJani Nikula 	wm->hpll.cursor = _FW_WM(tmp, HPLL_CURSOR);
353494b49d53SJani Nikula 	wm->hpll.plane = _FW_WM(tmp, HPLL_SR);
353594b49d53SJani Nikula }
353694b49d53SJani Nikula 
vlv_read_wm_values(struct drm_i915_private * dev_priv,struct vlv_wm_values * wm)353794b49d53SJani Nikula static void vlv_read_wm_values(struct drm_i915_private *dev_priv,
353894b49d53SJani Nikula 			       struct vlv_wm_values *wm)
353994b49d53SJani Nikula {
354094b49d53SJani Nikula 	enum pipe pipe;
354194b49d53SJani Nikula 	u32 tmp;
354294b49d53SJani Nikula 
354394b49d53SJani Nikula 	for_each_pipe(dev_priv, pipe) {
354494b49d53SJani Nikula 		tmp = intel_uncore_read(&dev_priv->uncore, VLV_DDL(pipe));
354594b49d53SJani Nikula 
354694b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_PRIMARY] =
354794b49d53SJani Nikula 			(tmp >> DDL_PLANE_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
354894b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_CURSOR] =
354994b49d53SJani Nikula 			(tmp >> DDL_CURSOR_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
355094b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_SPRITE0] =
355194b49d53SJani Nikula 			(tmp >> DDL_SPRITE_SHIFT(0)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
355294b49d53SJani Nikula 		wm->ddl[pipe].plane[PLANE_SPRITE1] =
355394b49d53SJani Nikula 			(tmp >> DDL_SPRITE_SHIFT(1)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
355494b49d53SJani Nikula 	}
355594b49d53SJani Nikula 
355694b49d53SJani Nikula 	tmp = intel_uncore_read(&dev_priv->uncore, DSPFW1);
355794b49d53SJani Nikula 	wm->sr.plane = _FW_WM(tmp, SR);
355894b49d53SJani Nikula 	wm->pipe[PIPE_B].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORB);
355994b49d53SJani Nikula 	wm->pipe[PIPE_B].plane[PLANE_PRIMARY] = _FW_WM_VLV(tmp, PLANEB);
356094b49d53SJani Nikula 	wm->pipe[PIPE_A].plane[PLANE_PRIMARY] = _FW_WM_VLV(tmp, PLANEA);
356194b49d53SJani Nikula 
356294b49d53SJani Nikula 	tmp = intel_uncore_read(&dev_priv->uncore, DSPFW2);
356394b49d53SJani Nikula 	wm->pipe[PIPE_A].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITEB);
356494b49d53SJani Nikula 	wm->pipe[PIPE_A].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORA);
356594b49d53SJani Nikula 	wm->pipe[PIPE_A].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEA);
356694b49d53SJani Nikula 
356794b49d53SJani Nikula 	tmp = intel_uncore_read(&dev_priv->uncore, DSPFW3);
356894b49d53SJani Nikula 	wm->sr.cursor = _FW_WM(tmp, CURSOR_SR);
356994b49d53SJani Nikula 
357094b49d53SJani Nikula 	if (IS_CHERRYVIEW(dev_priv)) {
357194b49d53SJani Nikula 		tmp = intel_uncore_read(&dev_priv->uncore, DSPFW7_CHV);
357294b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITED);
357394b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEC);
357494b49d53SJani Nikula 
357594b49d53SJani Nikula 		tmp = intel_uncore_read(&dev_priv->uncore, DSPFW8_CHV);
357694b49d53SJani Nikula 		wm->pipe[PIPE_C].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITEF);
357794b49d53SJani Nikula 		wm->pipe[PIPE_C].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEE);
357894b49d53SJani Nikula 
357994b49d53SJani Nikula 		tmp = intel_uncore_read(&dev_priv->uncore, DSPFW9_CHV);
358094b49d53SJani Nikula 		wm->pipe[PIPE_C].plane[PLANE_PRIMARY] = _FW_WM_VLV(tmp, PLANEC);
358194b49d53SJani Nikula 		wm->pipe[PIPE_C].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORC);
358294b49d53SJani Nikula 
358394b49d53SJani Nikula 		tmp = intel_uncore_read(&dev_priv->uncore, DSPHOWM);
358494b49d53SJani Nikula 		wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9;
358594b49d53SJani Nikula 		wm->pipe[PIPE_C].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITEF_HI) << 8;
358694b49d53SJani Nikula 		wm->pipe[PIPE_C].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEE_HI) << 8;
358794b49d53SJani Nikula 		wm->pipe[PIPE_C].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEC_HI) << 8;
358894b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITED_HI) << 8;
358994b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEC_HI) << 8;
359094b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEB_HI) << 8;
359194b49d53SJani Nikula 		wm->pipe[PIPE_A].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITEB_HI) << 8;
359294b49d53SJani Nikula 		wm->pipe[PIPE_A].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEA_HI) << 8;
359394b49d53SJani Nikula 		wm->pipe[PIPE_A].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEA_HI) << 8;
359494b49d53SJani Nikula 	} else {
359594b49d53SJani Nikula 		tmp = intel_uncore_read(&dev_priv->uncore, DSPFW7);
359694b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITED);
359794b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEC);
359894b49d53SJani Nikula 
359994b49d53SJani Nikula 		tmp = intel_uncore_read(&dev_priv->uncore, DSPHOWM);
360094b49d53SJani Nikula 		wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9;
360194b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITED_HI) << 8;
360294b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEC_HI) << 8;
360394b49d53SJani Nikula 		wm->pipe[PIPE_B].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEB_HI) << 8;
360494b49d53SJani Nikula 		wm->pipe[PIPE_A].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITEB_HI) << 8;
360594b49d53SJani Nikula 		wm->pipe[PIPE_A].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEA_HI) << 8;
360694b49d53SJani Nikula 		wm->pipe[PIPE_A].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEA_HI) << 8;
360794b49d53SJani Nikula 	}
360894b49d53SJani Nikula }
360994b49d53SJani Nikula 
361094b49d53SJani Nikula #undef _FW_WM
361194b49d53SJani Nikula #undef _FW_WM_VLV
361294b49d53SJani Nikula 
g4x_wm_get_hw_state(struct drm_i915_private * dev_priv)36130e7a16f9SJani Nikula static void g4x_wm_get_hw_state(struct drm_i915_private *dev_priv)
361494b49d53SJani Nikula {
361594b49d53SJani Nikula 	struct g4x_wm_values *wm = &dev_priv->display.wm.g4x;
361694b49d53SJani Nikula 	struct intel_crtc *crtc;
361794b49d53SJani Nikula 
361894b49d53SJani Nikula 	g4x_read_wm_values(dev_priv, wm);
361994b49d53SJani Nikula 
362094b49d53SJani Nikula 	wm->cxsr = intel_uncore_read(&dev_priv->uncore, FW_BLC_SELF) & FW_BLC_SELF_EN;
362194b49d53SJani Nikula 
362294b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
362394b49d53SJani Nikula 		struct intel_crtc_state *crtc_state =
362494b49d53SJani Nikula 			to_intel_crtc_state(crtc->base.state);
362594b49d53SJani Nikula 		struct g4x_wm_state *active = &crtc->wm.active.g4x;
362694b49d53SJani Nikula 		struct g4x_pipe_wm *raw;
362794b49d53SJani Nikula 		enum pipe pipe = crtc->pipe;
362894b49d53SJani Nikula 		enum plane_id plane_id;
362994b49d53SJani Nikula 		int level, max_level;
363094b49d53SJani Nikula 
363194b49d53SJani Nikula 		active->cxsr = wm->cxsr;
363294b49d53SJani Nikula 		active->hpll_en = wm->hpll_en;
363394b49d53SJani Nikula 		active->fbc_en = wm->fbc_en;
363494b49d53SJani Nikula 
363594b49d53SJani Nikula 		active->sr = wm->sr;
363694b49d53SJani Nikula 		active->hpll = wm->hpll;
363794b49d53SJani Nikula 
363894b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id) {
363994b49d53SJani Nikula 			active->wm.plane[plane_id] =
364094b49d53SJani Nikula 				wm->pipe[pipe].plane[plane_id];
364194b49d53SJani Nikula 		}
364294b49d53SJani Nikula 
364394b49d53SJani Nikula 		if (wm->cxsr && wm->hpll_en)
364494b49d53SJani Nikula 			max_level = G4X_WM_LEVEL_HPLL;
364594b49d53SJani Nikula 		else if (wm->cxsr)
364694b49d53SJani Nikula 			max_level = G4X_WM_LEVEL_SR;
364794b49d53SJani Nikula 		else
364894b49d53SJani Nikula 			max_level = G4X_WM_LEVEL_NORMAL;
364994b49d53SJani Nikula 
365094b49d53SJani Nikula 		level = G4X_WM_LEVEL_NORMAL;
365194b49d53SJani Nikula 		raw = &crtc_state->wm.g4x.raw[level];
365294b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id)
365394b49d53SJani Nikula 			raw->plane[plane_id] = active->wm.plane[plane_id];
365494b49d53SJani Nikula 
365594b49d53SJani Nikula 		level = G4X_WM_LEVEL_SR;
365694b49d53SJani Nikula 		if (level > max_level)
365794b49d53SJani Nikula 			goto out;
365894b49d53SJani Nikula 
365994b49d53SJani Nikula 		raw = &crtc_state->wm.g4x.raw[level];
366094b49d53SJani Nikula 		raw->plane[PLANE_PRIMARY] = active->sr.plane;
366194b49d53SJani Nikula 		raw->plane[PLANE_CURSOR] = active->sr.cursor;
366294b49d53SJani Nikula 		raw->plane[PLANE_SPRITE0] = 0;
366394b49d53SJani Nikula 		raw->fbc = active->sr.fbc;
366494b49d53SJani Nikula 
366594b49d53SJani Nikula 		level = G4X_WM_LEVEL_HPLL;
366694b49d53SJani Nikula 		if (level > max_level)
366794b49d53SJani Nikula 			goto out;
366894b49d53SJani Nikula 
366994b49d53SJani Nikula 		raw = &crtc_state->wm.g4x.raw[level];
367094b49d53SJani Nikula 		raw->plane[PLANE_PRIMARY] = active->hpll.plane;
367194b49d53SJani Nikula 		raw->plane[PLANE_CURSOR] = active->hpll.cursor;
367294b49d53SJani Nikula 		raw->plane[PLANE_SPRITE0] = 0;
367394b49d53SJani Nikula 		raw->fbc = active->hpll.fbc;
367494b49d53SJani Nikula 
367594b49d53SJani Nikula 		level++;
367694b49d53SJani Nikula 	out:
367794b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id)
367894b49d53SJani Nikula 			g4x_raw_plane_wm_set(crtc_state, level,
367994b49d53SJani Nikula 					     plane_id, USHRT_MAX);
368094b49d53SJani Nikula 		g4x_raw_fbc_wm_set(crtc_state, level, USHRT_MAX);
368194b49d53SJani Nikula 
368294b49d53SJani Nikula 		g4x_invalidate_wms(crtc, active, level);
368394b49d53SJani Nikula 
368494b49d53SJani Nikula 		crtc_state->wm.g4x.optimal = *active;
368594b49d53SJani Nikula 		crtc_state->wm.g4x.intermediate = *active;
368694b49d53SJani Nikula 
368794b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
368894b49d53SJani Nikula 			    "Initial watermarks: pipe %c, plane=%d, cursor=%d, sprite=%d\n",
368994b49d53SJani Nikula 			    pipe_name(pipe),
369094b49d53SJani Nikula 			    wm->pipe[pipe].plane[PLANE_PRIMARY],
369194b49d53SJani Nikula 			    wm->pipe[pipe].plane[PLANE_CURSOR],
369294b49d53SJani Nikula 			    wm->pipe[pipe].plane[PLANE_SPRITE0]);
369394b49d53SJani Nikula 	}
369494b49d53SJani Nikula 
369594b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
369694b49d53SJani Nikula 		    "Initial SR watermarks: plane=%d, cursor=%d fbc=%d\n",
369794b49d53SJani Nikula 		    wm->sr.plane, wm->sr.cursor, wm->sr.fbc);
369894b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
369994b49d53SJani Nikula 		    "Initial HPLL watermarks: plane=%d, SR cursor=%d fbc=%d\n",
370094b49d53SJani Nikula 		    wm->hpll.plane, wm->hpll.cursor, wm->hpll.fbc);
370194b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm, "Initial SR=%s HPLL=%s FBC=%s\n",
370294b49d53SJani Nikula 		    str_yes_no(wm->cxsr), str_yes_no(wm->hpll_en),
370394b49d53SJani Nikula 		    str_yes_no(wm->fbc_en));
370494b49d53SJani Nikula }
370594b49d53SJani Nikula 
g4x_wm_sanitize(struct drm_i915_private * dev_priv)37060e7a16f9SJani Nikula static void g4x_wm_sanitize(struct drm_i915_private *dev_priv)
370794b49d53SJani Nikula {
370894b49d53SJani Nikula 	struct intel_plane *plane;
370994b49d53SJani Nikula 	struct intel_crtc *crtc;
371094b49d53SJani Nikula 
371194b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
371294b49d53SJani Nikula 
371394b49d53SJani Nikula 	for_each_intel_plane(&dev_priv->drm, plane) {
371494b49d53SJani Nikula 		struct intel_crtc *crtc =
371594b49d53SJani Nikula 			intel_crtc_for_pipe(dev_priv, plane->pipe);
371694b49d53SJani Nikula 		struct intel_crtc_state *crtc_state =
371794b49d53SJani Nikula 			to_intel_crtc_state(crtc->base.state);
371894b49d53SJani Nikula 		struct intel_plane_state *plane_state =
371994b49d53SJani Nikula 			to_intel_plane_state(plane->base.state);
372094b49d53SJani Nikula 		enum plane_id plane_id = plane->id;
372194b49d53SJani Nikula 		int level;
372294b49d53SJani Nikula 
372394b49d53SJani Nikula 		if (plane_state->uapi.visible)
372494b49d53SJani Nikula 			continue;
372594b49d53SJani Nikula 
372694b49d53SJani Nikula 		for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
372794b49d53SJani Nikula 			struct g4x_pipe_wm *raw =
372894b49d53SJani Nikula 				&crtc_state->wm.g4x.raw[level];
372994b49d53SJani Nikula 
373094b49d53SJani Nikula 			raw->plane[plane_id] = 0;
373194b49d53SJani Nikula 
373294b49d53SJani Nikula 			if (plane_id == PLANE_PRIMARY)
373394b49d53SJani Nikula 				raw->fbc = 0;
373494b49d53SJani Nikula 		}
373594b49d53SJani Nikula 	}
373694b49d53SJani Nikula 
373794b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
373894b49d53SJani Nikula 		struct intel_crtc_state *crtc_state =
373994b49d53SJani Nikula 			to_intel_crtc_state(crtc->base.state);
374094b49d53SJani Nikula 		int ret;
374194b49d53SJani Nikula 
374294b49d53SJani Nikula 		ret = _g4x_compute_pipe_wm(crtc_state);
374394b49d53SJani Nikula 		drm_WARN_ON(&dev_priv->drm, ret);
374494b49d53SJani Nikula 
374594b49d53SJani Nikula 		crtc_state->wm.g4x.intermediate =
374694b49d53SJani Nikula 			crtc_state->wm.g4x.optimal;
374794b49d53SJani Nikula 		crtc->wm.active.g4x = crtc_state->wm.g4x.optimal;
374894b49d53SJani Nikula 	}
374994b49d53SJani Nikula 
375094b49d53SJani Nikula 	g4x_program_watermarks(dev_priv);
375194b49d53SJani Nikula 
375294b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
375394b49d53SJani Nikula }
375494b49d53SJani Nikula 
g4x_wm_get_hw_state_and_sanitize(struct drm_i915_private * i915)37550e7a16f9SJani Nikula static void g4x_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915)
37560e7a16f9SJani Nikula {
37570e7a16f9SJani Nikula 	g4x_wm_get_hw_state(i915);
37580e7a16f9SJani Nikula 	g4x_wm_sanitize(i915);
37590e7a16f9SJani Nikula }
37600e7a16f9SJani Nikula 
vlv_wm_get_hw_state(struct drm_i915_private * dev_priv)37610e7a16f9SJani Nikula static void vlv_wm_get_hw_state(struct drm_i915_private *dev_priv)
376294b49d53SJani Nikula {
376394b49d53SJani Nikula 	struct vlv_wm_values *wm = &dev_priv->display.wm.vlv;
376494b49d53SJani Nikula 	struct intel_crtc *crtc;
376594b49d53SJani Nikula 	u32 val;
376694b49d53SJani Nikula 
376794b49d53SJani Nikula 	vlv_read_wm_values(dev_priv, wm);
376894b49d53SJani Nikula 
376994b49d53SJani Nikula 	wm->cxsr = intel_uncore_read(&dev_priv->uncore, FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
377094b49d53SJani Nikula 	wm->level = VLV_WM_LEVEL_PM2;
377194b49d53SJani Nikula 
377294b49d53SJani Nikula 	if (IS_CHERRYVIEW(dev_priv)) {
377394b49d53SJani Nikula 		vlv_punit_get(dev_priv);
377494b49d53SJani Nikula 
377594b49d53SJani Nikula 		val = vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM);
377694b49d53SJani Nikula 		if (val & DSP_MAXFIFO_PM5_ENABLE)
377794b49d53SJani Nikula 			wm->level = VLV_WM_LEVEL_PM5;
377894b49d53SJani Nikula 
377994b49d53SJani Nikula 		/*
378094b49d53SJani Nikula 		 * If DDR DVFS is disabled in the BIOS, Punit
378194b49d53SJani Nikula 		 * will never ack the request. So if that happens
378294b49d53SJani Nikula 		 * assume we don't have to enable/disable DDR DVFS
378394b49d53SJani Nikula 		 * dynamically. To test that just set the REQ_ACK
378494b49d53SJani Nikula 		 * bit to poke the Punit, but don't change the
378594b49d53SJani Nikula 		 * HIGH/LOW bits so that we don't actually change
378694b49d53SJani Nikula 		 * the current state.
378794b49d53SJani Nikula 		 */
378894b49d53SJani Nikula 		val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
378994b49d53SJani Nikula 		val |= FORCE_DDR_FREQ_REQ_ACK;
379094b49d53SJani Nikula 		vlv_punit_write(dev_priv, PUNIT_REG_DDR_SETUP2, val);
379194b49d53SJani Nikula 
379294b49d53SJani Nikula 		if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2) &
379394b49d53SJani Nikula 			      FORCE_DDR_FREQ_REQ_ACK) == 0, 3)) {
379494b49d53SJani Nikula 			drm_dbg_kms(&dev_priv->drm,
379594b49d53SJani Nikula 				    "Punit not acking DDR DVFS request, "
379694b49d53SJani Nikula 				    "assuming DDR DVFS is disabled\n");
379794b49d53SJani Nikula 			dev_priv->display.wm.num_levels = VLV_WM_LEVEL_PM5 + 1;
379894b49d53SJani Nikula 		} else {
379994b49d53SJani Nikula 			val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
380094b49d53SJani Nikula 			if ((val & FORCE_DDR_HIGH_FREQ) == 0)
380194b49d53SJani Nikula 				wm->level = VLV_WM_LEVEL_DDR_DVFS;
380294b49d53SJani Nikula 		}
380394b49d53SJani Nikula 
380494b49d53SJani Nikula 		vlv_punit_put(dev_priv);
380594b49d53SJani Nikula 	}
380694b49d53SJani Nikula 
380794b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
380894b49d53SJani Nikula 		struct intel_crtc_state *crtc_state =
380994b49d53SJani Nikula 			to_intel_crtc_state(crtc->base.state);
381094b49d53SJani Nikula 		struct vlv_wm_state *active = &crtc->wm.active.vlv;
381194b49d53SJani Nikula 		const struct vlv_fifo_state *fifo_state =
381294b49d53SJani Nikula 			&crtc_state->wm.vlv.fifo_state;
381394b49d53SJani Nikula 		enum pipe pipe = crtc->pipe;
381494b49d53SJani Nikula 		enum plane_id plane_id;
381594b49d53SJani Nikula 		int level;
381694b49d53SJani Nikula 
381794b49d53SJani Nikula 		vlv_get_fifo_size(crtc_state);
381894b49d53SJani Nikula 
381994b49d53SJani Nikula 		active->num_levels = wm->level + 1;
382094b49d53SJani Nikula 		active->cxsr = wm->cxsr;
382194b49d53SJani Nikula 
382294b49d53SJani Nikula 		for (level = 0; level < active->num_levels; level++) {
382394b49d53SJani Nikula 			struct g4x_pipe_wm *raw =
382494b49d53SJani Nikula 				&crtc_state->wm.vlv.raw[level];
382594b49d53SJani Nikula 
382694b49d53SJani Nikula 			active->sr[level].plane = wm->sr.plane;
382794b49d53SJani Nikula 			active->sr[level].cursor = wm->sr.cursor;
382894b49d53SJani Nikula 
382994b49d53SJani Nikula 			for_each_plane_id_on_crtc(crtc, plane_id) {
383094b49d53SJani Nikula 				active->wm[level].plane[plane_id] =
383194b49d53SJani Nikula 					wm->pipe[pipe].plane[plane_id];
383294b49d53SJani Nikula 
383394b49d53SJani Nikula 				raw->plane[plane_id] =
383494b49d53SJani Nikula 					vlv_invert_wm_value(active->wm[level].plane[plane_id],
383594b49d53SJani Nikula 							    fifo_state->plane[plane_id]);
383694b49d53SJani Nikula 			}
383794b49d53SJani Nikula 		}
383894b49d53SJani Nikula 
383994b49d53SJani Nikula 		for_each_plane_id_on_crtc(crtc, plane_id)
384094b49d53SJani Nikula 			vlv_raw_plane_wm_set(crtc_state, level,
384194b49d53SJani Nikula 					     plane_id, USHRT_MAX);
384294b49d53SJani Nikula 		vlv_invalidate_wms(crtc, active, level);
384394b49d53SJani Nikula 
384494b49d53SJani Nikula 		crtc_state->wm.vlv.optimal = *active;
384594b49d53SJani Nikula 		crtc_state->wm.vlv.intermediate = *active;
384694b49d53SJani Nikula 
384794b49d53SJani Nikula 		drm_dbg_kms(&dev_priv->drm,
384894b49d53SJani Nikula 			    "Initial watermarks: pipe %c, plane=%d, cursor=%d, sprite0=%d, sprite1=%d\n",
384994b49d53SJani Nikula 			    pipe_name(pipe),
385094b49d53SJani Nikula 			    wm->pipe[pipe].plane[PLANE_PRIMARY],
385194b49d53SJani Nikula 			    wm->pipe[pipe].plane[PLANE_CURSOR],
385294b49d53SJani Nikula 			    wm->pipe[pipe].plane[PLANE_SPRITE0],
385394b49d53SJani Nikula 			    wm->pipe[pipe].plane[PLANE_SPRITE1]);
385494b49d53SJani Nikula 	}
385594b49d53SJani Nikula 
385694b49d53SJani Nikula 	drm_dbg_kms(&dev_priv->drm,
385794b49d53SJani Nikula 		    "Initial watermarks: SR plane=%d, SR cursor=%d level=%d cxsr=%d\n",
385894b49d53SJani Nikula 		    wm->sr.plane, wm->sr.cursor, wm->level, wm->cxsr);
385994b49d53SJani Nikula }
386094b49d53SJani Nikula 
vlv_wm_sanitize(struct drm_i915_private * dev_priv)38610e7a16f9SJani Nikula static void vlv_wm_sanitize(struct drm_i915_private *dev_priv)
386294b49d53SJani Nikula {
386394b49d53SJani Nikula 	struct intel_plane *plane;
386494b49d53SJani Nikula 	struct intel_crtc *crtc;
386594b49d53SJani Nikula 
386694b49d53SJani Nikula 	mutex_lock(&dev_priv->display.wm.wm_mutex);
386794b49d53SJani Nikula 
386894b49d53SJani Nikula 	for_each_intel_plane(&dev_priv->drm, plane) {
386994b49d53SJani Nikula 		struct intel_crtc *crtc =
387094b49d53SJani Nikula 			intel_crtc_for_pipe(dev_priv, plane->pipe);
387194b49d53SJani Nikula 		struct intel_crtc_state *crtc_state =
387294b49d53SJani Nikula 			to_intel_crtc_state(crtc->base.state);
387394b49d53SJani Nikula 		struct intel_plane_state *plane_state =
387494b49d53SJani Nikula 			to_intel_plane_state(plane->base.state);
387594b49d53SJani Nikula 		enum plane_id plane_id = plane->id;
387694b49d53SJani Nikula 		int level;
387794b49d53SJani Nikula 
387894b49d53SJani Nikula 		if (plane_state->uapi.visible)
387994b49d53SJani Nikula 			continue;
388094b49d53SJani Nikula 
388194b49d53SJani Nikula 		for (level = 0; level < dev_priv->display.wm.num_levels; level++) {
388294b49d53SJani Nikula 			struct g4x_pipe_wm *raw =
388394b49d53SJani Nikula 				&crtc_state->wm.vlv.raw[level];
388494b49d53SJani Nikula 
388594b49d53SJani Nikula 			raw->plane[plane_id] = 0;
388694b49d53SJani Nikula 		}
388794b49d53SJani Nikula 	}
388894b49d53SJani Nikula 
388994b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc) {
389094b49d53SJani Nikula 		struct intel_crtc_state *crtc_state =
389194b49d53SJani Nikula 			to_intel_crtc_state(crtc->base.state);
389294b49d53SJani Nikula 		int ret;
389394b49d53SJani Nikula 
389494b49d53SJani Nikula 		ret = _vlv_compute_pipe_wm(crtc_state);
389594b49d53SJani Nikula 		drm_WARN_ON(&dev_priv->drm, ret);
389694b49d53SJani Nikula 
389794b49d53SJani Nikula 		crtc_state->wm.vlv.intermediate =
389894b49d53SJani Nikula 			crtc_state->wm.vlv.optimal;
389994b49d53SJani Nikula 		crtc->wm.active.vlv = crtc_state->wm.vlv.optimal;
390094b49d53SJani Nikula 	}
390194b49d53SJani Nikula 
390294b49d53SJani Nikula 	vlv_program_watermarks(dev_priv);
390394b49d53SJani Nikula 
390494b49d53SJani Nikula 	mutex_unlock(&dev_priv->display.wm.wm_mutex);
390594b49d53SJani Nikula }
390694b49d53SJani Nikula 
vlv_wm_get_hw_state_and_sanitize(struct drm_i915_private * i915)39070e7a16f9SJani Nikula static void vlv_wm_get_hw_state_and_sanitize(struct drm_i915_private *i915)
39080e7a16f9SJani Nikula {
39090e7a16f9SJani Nikula 	vlv_wm_get_hw_state(i915);
39100e7a16f9SJani Nikula 	vlv_wm_sanitize(i915);
39110e7a16f9SJani Nikula }
39120e7a16f9SJani Nikula 
391394b49d53SJani Nikula /*
391494b49d53SJani Nikula  * FIXME should probably kill this and improve
391594b49d53SJani Nikula  * the real watermark readout/sanitation instead
391694b49d53SJani Nikula  */
ilk_init_lp_watermarks(struct drm_i915_private * dev_priv)391794b49d53SJani Nikula static void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv)
391894b49d53SJani Nikula {
391994b49d53SJani Nikula 	intel_uncore_rmw(&dev_priv->uncore, WM3_LP_ILK, WM_LP_ENABLE, 0);
392094b49d53SJani Nikula 	intel_uncore_rmw(&dev_priv->uncore, WM2_LP_ILK, WM_LP_ENABLE, 0);
392194b49d53SJani Nikula 	intel_uncore_rmw(&dev_priv->uncore, WM1_LP_ILK, WM_LP_ENABLE, 0);
392294b49d53SJani Nikula 
392394b49d53SJani Nikula 	/*
392494b49d53SJani Nikula 	 * Don't touch WM_LP_SPRITE_ENABLE here.
392594b49d53SJani Nikula 	 * Doing so could cause underruns.
392694b49d53SJani Nikula 	 */
392794b49d53SJani Nikula }
392894b49d53SJani Nikula 
ilk_wm_get_hw_state(struct drm_i915_private * dev_priv)39290e7a16f9SJani Nikula static void ilk_wm_get_hw_state(struct drm_i915_private *dev_priv)
393094b49d53SJani Nikula {
393194b49d53SJani Nikula 	struct ilk_wm_values *hw = &dev_priv->display.wm.hw;
393294b49d53SJani Nikula 	struct intel_crtc *crtc;
393394b49d53SJani Nikula 
393494b49d53SJani Nikula 	ilk_init_lp_watermarks(dev_priv);
393594b49d53SJani Nikula 
393694b49d53SJani Nikula 	for_each_intel_crtc(&dev_priv->drm, crtc)
393794b49d53SJani Nikula 		ilk_pipe_wm_get_hw_state(crtc);
393894b49d53SJani Nikula 
393994b49d53SJani Nikula 	hw->wm_lp[0] = intel_uncore_read(&dev_priv->uncore, WM1_LP_ILK);
394094b49d53SJani Nikula 	hw->wm_lp[1] = intel_uncore_read(&dev_priv->uncore, WM2_LP_ILK);
394194b49d53SJani Nikula 	hw->wm_lp[2] = intel_uncore_read(&dev_priv->uncore, WM3_LP_ILK);
394294b49d53SJani Nikula 
394394b49d53SJani Nikula 	hw->wm_lp_spr[0] = intel_uncore_read(&dev_priv->uncore, WM1S_LP_ILK);
394494b49d53SJani Nikula 	if (DISPLAY_VER(dev_priv) >= 7) {
394594b49d53SJani Nikula 		hw->wm_lp_spr[1] = intel_uncore_read(&dev_priv->uncore, WM2S_LP_IVB);
394694b49d53SJani Nikula 		hw->wm_lp_spr[2] = intel_uncore_read(&dev_priv->uncore, WM3S_LP_IVB);
394794b49d53SJani Nikula 	}
394894b49d53SJani Nikula 
394994b49d53SJani Nikula 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
395094b49d53SJani Nikula 		hw->partitioning = (intel_uncore_read(&dev_priv->uncore, WM_MISC) &
395194b49d53SJani Nikula 				    WM_MISC_DATA_PARTITION_5_6) ?
395294b49d53SJani Nikula 			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
395394b49d53SJani Nikula 	else if (IS_IVYBRIDGE(dev_priv))
395494b49d53SJani Nikula 		hw->partitioning = (intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL2) &
395594b49d53SJani Nikula 				    DISP_DATA_PARTITION_5_6) ?
395694b49d53SJani Nikula 			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
395794b49d53SJani Nikula 
395894b49d53SJani Nikula 	hw->enable_fbc_wm =
395994b49d53SJani Nikula 		!(intel_uncore_read(&dev_priv->uncore, DISP_ARB_CTL) & DISP_FBC_WM_DIS);
396094b49d53SJani Nikula }
396194b49d53SJani Nikula 
396294b49d53SJani Nikula static const struct intel_wm_funcs ilk_wm_funcs = {
396394b49d53SJani Nikula 	.compute_pipe_wm = ilk_compute_pipe_wm,
396494b49d53SJani Nikula 	.compute_intermediate_wm = ilk_compute_intermediate_wm,
396594b49d53SJani Nikula 	.initial_watermarks = ilk_initial_watermarks,
396694b49d53SJani Nikula 	.optimize_watermarks = ilk_optimize_watermarks,
39670e7a16f9SJani Nikula 	.get_hw_state = ilk_wm_get_hw_state,
396894b49d53SJani Nikula };
396994b49d53SJani Nikula 
397094b49d53SJani Nikula static const struct intel_wm_funcs vlv_wm_funcs = {
397194b49d53SJani Nikula 	.compute_pipe_wm = vlv_compute_pipe_wm,
397294b49d53SJani Nikula 	.compute_intermediate_wm = vlv_compute_intermediate_wm,
397394b49d53SJani Nikula 	.initial_watermarks = vlv_initial_watermarks,
397494b49d53SJani Nikula 	.optimize_watermarks = vlv_optimize_watermarks,
397594b49d53SJani Nikula 	.atomic_update_watermarks = vlv_atomic_update_fifo,
39760e7a16f9SJani Nikula 	.get_hw_state = vlv_wm_get_hw_state_and_sanitize,
397794b49d53SJani Nikula };
397894b49d53SJani Nikula 
397994b49d53SJani Nikula static const struct intel_wm_funcs g4x_wm_funcs = {
398094b49d53SJani Nikula 	.compute_pipe_wm = g4x_compute_pipe_wm,
398194b49d53SJani Nikula 	.compute_intermediate_wm = g4x_compute_intermediate_wm,
398294b49d53SJani Nikula 	.initial_watermarks = g4x_initial_watermarks,
398394b49d53SJani Nikula 	.optimize_watermarks = g4x_optimize_watermarks,
39840e7a16f9SJani Nikula 	.get_hw_state = g4x_wm_get_hw_state_and_sanitize,
398594b49d53SJani Nikula };
398694b49d53SJani Nikula 
398794b49d53SJani Nikula static const struct intel_wm_funcs pnv_wm_funcs = {
398894b49d53SJani Nikula 	.update_wm = pnv_update_wm,
398994b49d53SJani Nikula };
399094b49d53SJani Nikula 
399194b49d53SJani Nikula static const struct intel_wm_funcs i965_wm_funcs = {
399294b49d53SJani Nikula 	.update_wm = i965_update_wm,
399394b49d53SJani Nikula };
399494b49d53SJani Nikula 
399594b49d53SJani Nikula static const struct intel_wm_funcs i9xx_wm_funcs = {
399694b49d53SJani Nikula 	.update_wm = i9xx_update_wm,
399794b49d53SJani Nikula };
399894b49d53SJani Nikula 
399994b49d53SJani Nikula static const struct intel_wm_funcs i845_wm_funcs = {
400094b49d53SJani Nikula 	.update_wm = i845_update_wm,
400194b49d53SJani Nikula };
400294b49d53SJani Nikula 
400394b49d53SJani Nikula static const struct intel_wm_funcs nop_funcs = {
400494b49d53SJani Nikula };
400594b49d53SJani Nikula 
i9xx_wm_init(struct drm_i915_private * dev_priv)400694b49d53SJani Nikula void i9xx_wm_init(struct drm_i915_private *dev_priv)
400794b49d53SJani Nikula {
400894b49d53SJani Nikula 	/* For FIFO watermark updates */
400994b49d53SJani Nikula 	if (HAS_PCH_SPLIT(dev_priv)) {
401094b49d53SJani Nikula 		ilk_setup_wm_latency(dev_priv);
401194b49d53SJani Nikula 		dev_priv->display.funcs.wm = &ilk_wm_funcs;
401294b49d53SJani Nikula 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
401394b49d53SJani Nikula 		vlv_setup_wm_latency(dev_priv);
401494b49d53SJani Nikula 		dev_priv->display.funcs.wm = &vlv_wm_funcs;
401594b49d53SJani Nikula 	} else if (IS_G4X(dev_priv)) {
401694b49d53SJani Nikula 		g4x_setup_wm_latency(dev_priv);
401794b49d53SJani Nikula 		dev_priv->display.funcs.wm = &g4x_wm_funcs;
401894b49d53SJani Nikula 	} else if (IS_PINEVIEW(dev_priv)) {
401994b49d53SJani Nikula 		if (!intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
402094b49d53SJani Nikula 					    dev_priv->is_ddr3,
402194b49d53SJani Nikula 					    dev_priv->fsb_freq,
402294b49d53SJani Nikula 					    dev_priv->mem_freq)) {
402394b49d53SJani Nikula 			drm_info(&dev_priv->drm,
402494b49d53SJani Nikula 				 "failed to find known CxSR latency "
402594b49d53SJani Nikula 				 "(found ddr%s fsb freq %d, mem freq %d), "
402694b49d53SJani Nikula 				 "disabling CxSR\n",
402794b49d53SJani Nikula 				 (dev_priv->is_ddr3 == 1) ? "3" : "2",
402894b49d53SJani Nikula 				 dev_priv->fsb_freq, dev_priv->mem_freq);
402994b49d53SJani Nikula 			/* Disable CxSR and never update its watermark again */
403094b49d53SJani Nikula 			intel_set_memory_cxsr(dev_priv, false);
403194b49d53SJani Nikula 			dev_priv->display.funcs.wm = &nop_funcs;
403294b49d53SJani Nikula 		} else {
403394b49d53SJani Nikula 			dev_priv->display.funcs.wm = &pnv_wm_funcs;
403494b49d53SJani Nikula 		}
403594b49d53SJani Nikula 	} else if (DISPLAY_VER(dev_priv) == 4) {
403694b49d53SJani Nikula 		dev_priv->display.funcs.wm = &i965_wm_funcs;
403794b49d53SJani Nikula 	} else if (DISPLAY_VER(dev_priv) == 3) {
403894b49d53SJani Nikula 		dev_priv->display.funcs.wm = &i9xx_wm_funcs;
403994b49d53SJani Nikula 	} else if (DISPLAY_VER(dev_priv) == 2) {
404094b49d53SJani Nikula 		if (INTEL_NUM_PIPES(dev_priv) == 1)
404194b49d53SJani Nikula 			dev_priv->display.funcs.wm = &i845_wm_funcs;
404294b49d53SJani Nikula 		else
404394b49d53SJani Nikula 			dev_priv->display.funcs.wm = &i9xx_wm_funcs;
404494b49d53SJani Nikula 	} else {
404594b49d53SJani Nikula 		drm_err(&dev_priv->drm,
404694b49d53SJani Nikula 			"unexpected fall-through in %s\n", __func__);
404794b49d53SJani Nikula 		dev_priv->display.funcs.wm = &nop_funcs;
404894b49d53SJani Nikula 	}
404994b49d53SJani Nikula }
4050