18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright © 2012 Intel Corporation
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
138c2ecf20Sopenharmony_ci * Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
218c2ecf20Sopenharmony_ci * IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Authors:
248c2ecf20Sopenharmony_ci *    Eugeni Dodonov <eugeni.dodonov@intel.com>
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <linux/module.h>
298c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
328c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h>
338c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include "display/intel_atomic.h"
368c2ecf20Sopenharmony_ci#include "display/intel_bw.h"
378c2ecf20Sopenharmony_ci#include "display/intel_display_types.h"
388c2ecf20Sopenharmony_ci#include "display/intel_fbc.h"
398c2ecf20Sopenharmony_ci#include "display/intel_sprite.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "gt/intel_llc.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#include "i915_drv.h"
448c2ecf20Sopenharmony_ci#include "i915_fixed.h"
458c2ecf20Sopenharmony_ci#include "i915_irq.h"
468c2ecf20Sopenharmony_ci#include "i915_trace.h"
478c2ecf20Sopenharmony_ci#include "intel_pm.h"
488c2ecf20Sopenharmony_ci#include "intel_sideband.h"
498c2ecf20Sopenharmony_ci#include "../../../platform/x86/intel_ips.h"
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Stores plane specific WM parameters */
528c2ecf20Sopenharmony_cistruct skl_wm_params {
538c2ecf20Sopenharmony_ci	bool x_tiled, y_tiled;
548c2ecf20Sopenharmony_ci	bool rc_surface;
558c2ecf20Sopenharmony_ci	bool is_planar;
568c2ecf20Sopenharmony_ci	u32 width;
578c2ecf20Sopenharmony_ci	u8 cpp;
588c2ecf20Sopenharmony_ci	u32 plane_pixel_rate;
598c2ecf20Sopenharmony_ci	u32 y_min_scanlines;
608c2ecf20Sopenharmony_ci	u32 plane_bytes_per_line;
618c2ecf20Sopenharmony_ci	uint_fixed_16_16_t plane_blocks_per_line;
628c2ecf20Sopenharmony_ci	uint_fixed_16_16_t y_tile_minimum;
638c2ecf20Sopenharmony_ci	u32 linetime_us;
648c2ecf20Sopenharmony_ci	u32 dbuf_block_size;
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/* used in computing the new watermarks state */
688c2ecf20Sopenharmony_cistruct intel_wm_config {
698c2ecf20Sopenharmony_ci	unsigned int num_pipes_active;
708c2ecf20Sopenharmony_ci	bool sprites_enabled;
718c2ecf20Sopenharmony_ci	bool sprites_scaled;
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic void gen9_init_clock_gating(struct drm_i915_private *dev_priv)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	if (HAS_LLC(dev_priv)) {
778c2ecf20Sopenharmony_ci		/*
788c2ecf20Sopenharmony_ci		 * WaCompressedResourceDisplayNewHashMode:skl,kbl
798c2ecf20Sopenharmony_ci		 * Display WA #0390: skl,kbl
808c2ecf20Sopenharmony_ci		 *
818c2ecf20Sopenharmony_ci		 * Must match Sampler, Pixel Back End, and Media. See
828c2ecf20Sopenharmony_ci		 * WaCompressedResourceSamplerPbeMediaNewHashMode.
838c2ecf20Sopenharmony_ci		 */
848c2ecf20Sopenharmony_ci		I915_WRITE(CHICKEN_PAR1_1,
858c2ecf20Sopenharmony_ci			   I915_READ(CHICKEN_PAR1_1) |
868c2ecf20Sopenharmony_ci			   SKL_DE_COMPRESSED_HASH_MODE);
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */
908c2ecf20Sopenharmony_ci	I915_WRITE(CHICKEN_PAR1_1,
918c2ecf20Sopenharmony_ci		   I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* WaEnableChickenDCPR:skl,bxt,kbl,glk,cfl */
948c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_CHICKEN_DCPR_1,
958c2ecf20Sopenharmony_ci		   I915_READ(GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/*
988c2ecf20Sopenharmony_ci	 * WaFbcWakeMemOn:skl,bxt,kbl,glk,cfl
998c2ecf20Sopenharmony_ci	 * Display WA #0859: skl,bxt,kbl,glk,cfl
1008c2ecf20Sopenharmony_ci	 */
1018c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
1028c2ecf20Sopenharmony_ci		   DISP_FBC_MEMORY_WAKE);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic void bxt_init_clock_gating(struct drm_i915_private *dev_priv)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	gen9_init_clock_gating(dev_priv);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* WaDisableSDEUnitClockGating:bxt */
1108c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
1118c2ecf20Sopenharmony_ci		   GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/*
1148c2ecf20Sopenharmony_ci	 * FIXME:
1158c2ecf20Sopenharmony_ci	 * GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ applies on 3x6 GT SKUs only.
1168c2ecf20Sopenharmony_ci	 */
1178c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
1188c2ecf20Sopenharmony_ci		   GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/*
1218c2ecf20Sopenharmony_ci	 * Wa: Backlight PWM may stop in the asserted state, causing backlight
1228c2ecf20Sopenharmony_ci	 * to stay fully on.
1238c2ecf20Sopenharmony_ci	 */
1248c2ecf20Sopenharmony_ci	I915_WRITE(GEN9_CLKGATE_DIS_0, I915_READ(GEN9_CLKGATE_DIS_0) |
1258c2ecf20Sopenharmony_ci		   PWM1_GATING_DIS | PWM2_GATING_DIS);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/*
1288c2ecf20Sopenharmony_ci	 * Lower the display internal timeout.
1298c2ecf20Sopenharmony_ci	 * This is needed to avoid any hard hangs when DSI port PLL
1308c2ecf20Sopenharmony_ci	 * is off and a MMIO access is attempted by any privilege
1318c2ecf20Sopenharmony_ci	 * application, using batch buffers or any other means.
1328c2ecf20Sopenharmony_ci	 */
1338c2ecf20Sopenharmony_ci	I915_WRITE(RM_TIMEOUT, MMIO_TIMEOUT_US(950));
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/*
1368c2ecf20Sopenharmony_ci	 * WaFbcTurnOffFbcWatermark:bxt
1378c2ecf20Sopenharmony_ci	 * Display WA #0562: bxt
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
1408c2ecf20Sopenharmony_ci		   DISP_FBC_WM_DIS);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/*
1438c2ecf20Sopenharmony_ci	 * WaFbcHighMemBwCorruptionAvoidance:bxt
1448c2ecf20Sopenharmony_ci	 * Display WA #0883: bxt
1458c2ecf20Sopenharmony_ci	 */
1468c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) |
1478c2ecf20Sopenharmony_ci		   ILK_DPFC_DISABLE_DUMMY0);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void glk_init_clock_gating(struct drm_i915_private *dev_priv)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	gen9_init_clock_gating(dev_priv);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	 * WaDisablePWMClockGating:glk
1568c2ecf20Sopenharmony_ci	 * Backlight PWM may stop in the asserted state, causing backlight
1578c2ecf20Sopenharmony_ci	 * to stay fully on.
1588c2ecf20Sopenharmony_ci	 */
1598c2ecf20Sopenharmony_ci	I915_WRITE(GEN9_CLKGATE_DIS_0, I915_READ(GEN9_CLKGATE_DIS_0) |
1608c2ecf20Sopenharmony_ci		   PWM1_GATING_DIS | PWM2_GATING_DIS);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void pnv_get_mem_freq(struct drm_i915_private *dev_priv)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	u32 tmp;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	tmp = I915_READ(CLKCFG);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	switch (tmp & CLKCFG_FSB_MASK) {
1708c2ecf20Sopenharmony_ci	case CLKCFG_FSB_533:
1718c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 533; /* 133*4 */
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case CLKCFG_FSB_800:
1748c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 800; /* 200*4 */
1758c2ecf20Sopenharmony_ci		break;
1768c2ecf20Sopenharmony_ci	case CLKCFG_FSB_667:
1778c2ecf20Sopenharmony_ci		dev_priv->fsb_freq =  667; /* 167*4 */
1788c2ecf20Sopenharmony_ci		break;
1798c2ecf20Sopenharmony_ci	case CLKCFG_FSB_400:
1808c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 400; /* 100*4 */
1818c2ecf20Sopenharmony_ci		break;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	switch (tmp & CLKCFG_MEM_MASK) {
1858c2ecf20Sopenharmony_ci	case CLKCFG_MEM_533:
1868c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 533;
1878c2ecf20Sopenharmony_ci		break;
1888c2ecf20Sopenharmony_ci	case CLKCFG_MEM_667:
1898c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 667;
1908c2ecf20Sopenharmony_ci		break;
1918c2ecf20Sopenharmony_ci	case CLKCFG_MEM_800:
1928c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 800;
1938c2ecf20Sopenharmony_ci		break;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	/* detect pineview DDR3 setting */
1978c2ecf20Sopenharmony_ci	tmp = I915_READ(CSHRDDR3CTL);
1988c2ecf20Sopenharmony_ci	dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic void ilk_get_mem_freq(struct drm_i915_private *dev_priv)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	u16 ddrpll, csipll;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	ddrpll = intel_uncore_read16(&dev_priv->uncore, DDRMPLL1);
2068c2ecf20Sopenharmony_ci	csipll = intel_uncore_read16(&dev_priv->uncore, CSIPLL0);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	switch (ddrpll & 0xff) {
2098c2ecf20Sopenharmony_ci	case 0xc:
2108c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 800;
2118c2ecf20Sopenharmony_ci		break;
2128c2ecf20Sopenharmony_ci	case 0x10:
2138c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 1066;
2148c2ecf20Sopenharmony_ci		break;
2158c2ecf20Sopenharmony_ci	case 0x14:
2168c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 1333;
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	case 0x18:
2198c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 1600;
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	default:
2228c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "unknown memory frequency 0x%02x\n",
2238c2ecf20Sopenharmony_ci			ddrpll & 0xff);
2248c2ecf20Sopenharmony_ci		dev_priv->mem_freq = 0;
2258c2ecf20Sopenharmony_ci		break;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	switch (csipll & 0x3ff) {
2298c2ecf20Sopenharmony_ci	case 0x00c:
2308c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 3200;
2318c2ecf20Sopenharmony_ci		break;
2328c2ecf20Sopenharmony_ci	case 0x00e:
2338c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 3733;
2348c2ecf20Sopenharmony_ci		break;
2358c2ecf20Sopenharmony_ci	case 0x010:
2368c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 4266;
2378c2ecf20Sopenharmony_ci		break;
2388c2ecf20Sopenharmony_ci	case 0x012:
2398c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 4800;
2408c2ecf20Sopenharmony_ci		break;
2418c2ecf20Sopenharmony_ci	case 0x014:
2428c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 5333;
2438c2ecf20Sopenharmony_ci		break;
2448c2ecf20Sopenharmony_ci	case 0x016:
2458c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 5866;
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci	case 0x018:
2488c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 6400;
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	default:
2518c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "unknown fsb frequency 0x%04x\n",
2528c2ecf20Sopenharmony_ci			csipll & 0x3ff);
2538c2ecf20Sopenharmony_ci		dev_priv->fsb_freq = 0;
2548c2ecf20Sopenharmony_ci		break;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic const struct cxsr_latency cxsr_latency_table[] = {
2598c2ecf20Sopenharmony_ci	{1, 0, 800, 400, 3382, 33382, 3983, 33983},    /* DDR2-400 SC */
2608c2ecf20Sopenharmony_ci	{1, 0, 800, 667, 3354, 33354, 3807, 33807},    /* DDR2-667 SC */
2618c2ecf20Sopenharmony_ci	{1, 0, 800, 800, 3347, 33347, 3763, 33763},    /* DDR2-800 SC */
2628c2ecf20Sopenharmony_ci	{1, 1, 800, 667, 6420, 36420, 6873, 36873},    /* DDR3-667 SC */
2638c2ecf20Sopenharmony_ci	{1, 1, 800, 800, 5902, 35902, 6318, 36318},    /* DDR3-800 SC */
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	{1, 0, 667, 400, 3400, 33400, 4021, 34021},    /* DDR2-400 SC */
2668c2ecf20Sopenharmony_ci	{1, 0, 667, 667, 3372, 33372, 3845, 33845},    /* DDR2-667 SC */
2678c2ecf20Sopenharmony_ci	{1, 0, 667, 800, 3386, 33386, 3822, 33822},    /* DDR2-800 SC */
2688c2ecf20Sopenharmony_ci	{1, 1, 667, 667, 6438, 36438, 6911, 36911},    /* DDR3-667 SC */
2698c2ecf20Sopenharmony_ci	{1, 1, 667, 800, 5941, 35941, 6377, 36377},    /* DDR3-800 SC */
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	{1, 0, 400, 400, 3472, 33472, 4173, 34173},    /* DDR2-400 SC */
2728c2ecf20Sopenharmony_ci	{1, 0, 400, 667, 3443, 33443, 3996, 33996},    /* DDR2-667 SC */
2738c2ecf20Sopenharmony_ci	{1, 0, 400, 800, 3430, 33430, 3946, 33946},    /* DDR2-800 SC */
2748c2ecf20Sopenharmony_ci	{1, 1, 400, 667, 6509, 36509, 7062, 37062},    /* DDR3-667 SC */
2758c2ecf20Sopenharmony_ci	{1, 1, 400, 800, 5985, 35985, 6501, 36501},    /* DDR3-800 SC */
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	{0, 0, 800, 400, 3438, 33438, 4065, 34065},    /* DDR2-400 SC */
2788c2ecf20Sopenharmony_ci	{0, 0, 800, 667, 3410, 33410, 3889, 33889},    /* DDR2-667 SC */
2798c2ecf20Sopenharmony_ci	{0, 0, 800, 800, 3403, 33403, 3845, 33845},    /* DDR2-800 SC */
2808c2ecf20Sopenharmony_ci	{0, 1, 800, 667, 6476, 36476, 6955, 36955},    /* DDR3-667 SC */
2818c2ecf20Sopenharmony_ci	{0, 1, 800, 800, 5958, 35958, 6400, 36400},    /* DDR3-800 SC */
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	{0, 0, 667, 400, 3456, 33456, 4103, 34106},    /* DDR2-400 SC */
2848c2ecf20Sopenharmony_ci	{0, 0, 667, 667, 3428, 33428, 3927, 33927},    /* DDR2-667 SC */
2858c2ecf20Sopenharmony_ci	{0, 0, 667, 800, 3443, 33443, 3905, 33905},    /* DDR2-800 SC */
2868c2ecf20Sopenharmony_ci	{0, 1, 667, 667, 6494, 36494, 6993, 36993},    /* DDR3-667 SC */
2878c2ecf20Sopenharmony_ci	{0, 1, 667, 800, 5998, 35998, 6460, 36460},    /* DDR3-800 SC */
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	{0, 0, 400, 400, 3528, 33528, 4255, 34255},    /* DDR2-400 SC */
2908c2ecf20Sopenharmony_ci	{0, 0, 400, 667, 3500, 33500, 4079, 34079},    /* DDR2-667 SC */
2918c2ecf20Sopenharmony_ci	{0, 0, 400, 800, 3487, 33487, 4029, 34029},    /* DDR2-800 SC */
2928c2ecf20Sopenharmony_ci	{0, 1, 400, 667, 6566, 36566, 7145, 37145},    /* DDR3-667 SC */
2938c2ecf20Sopenharmony_ci	{0, 1, 400, 800, 6042, 36042, 6584, 36584},    /* DDR3-800 SC */
2948c2ecf20Sopenharmony_ci};
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic const struct cxsr_latency *intel_get_cxsr_latency(bool is_desktop,
2978c2ecf20Sopenharmony_ci							 bool is_ddr3,
2988c2ecf20Sopenharmony_ci							 int fsb,
2998c2ecf20Sopenharmony_ci							 int mem)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	const struct cxsr_latency *latency;
3028c2ecf20Sopenharmony_ci	int i;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (fsb == 0 || mem == 0)
3058c2ecf20Sopenharmony_ci		return NULL;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
3088c2ecf20Sopenharmony_ci		latency = &cxsr_latency_table[i];
3098c2ecf20Sopenharmony_ci		if (is_desktop == latency->is_desktop &&
3108c2ecf20Sopenharmony_ci		    is_ddr3 == latency->is_ddr3 &&
3118c2ecf20Sopenharmony_ci		    fsb == latency->fsb_freq && mem == latency->mem_freq)
3128c2ecf20Sopenharmony_ci			return latency;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return NULL;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic void chv_set_memory_dvfs(struct drm_i915_private *dev_priv, bool enable)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	u32 val;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	vlv_punit_get(dev_priv);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
3278c2ecf20Sopenharmony_ci	if (enable)
3288c2ecf20Sopenharmony_ci		val &= ~FORCE_DDR_HIGH_FREQ;
3298c2ecf20Sopenharmony_ci	else
3308c2ecf20Sopenharmony_ci		val |= FORCE_DDR_HIGH_FREQ;
3318c2ecf20Sopenharmony_ci	val &= ~FORCE_DDR_LOW_FREQ;
3328c2ecf20Sopenharmony_ci	val |= FORCE_DDR_FREQ_REQ_ACK;
3338c2ecf20Sopenharmony_ci	vlv_punit_write(dev_priv, PUNIT_REG_DDR_SETUP2, val);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2) &
3368c2ecf20Sopenharmony_ci		      FORCE_DDR_FREQ_REQ_ACK) == 0, 3))
3378c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm,
3388c2ecf20Sopenharmony_ci			"timed out waiting for Punit DDR DVFS request\n");
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	vlv_punit_put(dev_priv);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic void chv_set_memory_pm5(struct drm_i915_private *dev_priv, bool enable)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	u32 val;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	vlv_punit_get(dev_priv);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	val = vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM);
3508c2ecf20Sopenharmony_ci	if (enable)
3518c2ecf20Sopenharmony_ci		val |= DSP_MAXFIFO_PM5_ENABLE;
3528c2ecf20Sopenharmony_ci	else
3538c2ecf20Sopenharmony_ci		val &= ~DSP_MAXFIFO_PM5_ENABLE;
3548c2ecf20Sopenharmony_ci	vlv_punit_write(dev_priv, PUNIT_REG_DSPSSPM, val);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	vlv_punit_put(dev_priv);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci#define FW_WM(value, plane) \
3608c2ecf20Sopenharmony_ci	(((value) << DSPFW_ ## plane ## _SHIFT) & DSPFW_ ## plane ## _MASK)
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic bool _intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	bool was_enabled;
3658c2ecf20Sopenharmony_ci	u32 val;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
3688c2ecf20Sopenharmony_ci		was_enabled = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
3698c2ecf20Sopenharmony_ci		I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0);
3708c2ecf20Sopenharmony_ci		POSTING_READ(FW_BLC_SELF_VLV);
3718c2ecf20Sopenharmony_ci	} else if (IS_G4X(dev_priv) || IS_I965GM(dev_priv)) {
3728c2ecf20Sopenharmony_ci		was_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
3738c2ecf20Sopenharmony_ci		I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0);
3748c2ecf20Sopenharmony_ci		POSTING_READ(FW_BLC_SELF);
3758c2ecf20Sopenharmony_ci	} else if (IS_PINEVIEW(dev_priv)) {
3768c2ecf20Sopenharmony_ci		val = I915_READ(DSPFW3);
3778c2ecf20Sopenharmony_ci		was_enabled = val & PINEVIEW_SELF_REFRESH_EN;
3788c2ecf20Sopenharmony_ci		if (enable)
3798c2ecf20Sopenharmony_ci			val |= PINEVIEW_SELF_REFRESH_EN;
3808c2ecf20Sopenharmony_ci		else
3818c2ecf20Sopenharmony_ci			val &= ~PINEVIEW_SELF_REFRESH_EN;
3828c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW3, val);
3838c2ecf20Sopenharmony_ci		POSTING_READ(DSPFW3);
3848c2ecf20Sopenharmony_ci	} else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv)) {
3858c2ecf20Sopenharmony_ci		was_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
3868c2ecf20Sopenharmony_ci		val = enable ? _MASKED_BIT_ENABLE(FW_BLC_SELF_EN) :
3878c2ecf20Sopenharmony_ci			       _MASKED_BIT_DISABLE(FW_BLC_SELF_EN);
3888c2ecf20Sopenharmony_ci		I915_WRITE(FW_BLC_SELF, val);
3898c2ecf20Sopenharmony_ci		POSTING_READ(FW_BLC_SELF);
3908c2ecf20Sopenharmony_ci	} else if (IS_I915GM(dev_priv)) {
3918c2ecf20Sopenharmony_ci		/*
3928c2ecf20Sopenharmony_ci		 * FIXME can't find a bit like this for 915G, and
3938c2ecf20Sopenharmony_ci		 * and yet it does have the related watermark in
3948c2ecf20Sopenharmony_ci		 * FW_BLC_SELF. What's going on?
3958c2ecf20Sopenharmony_ci		 */
3968c2ecf20Sopenharmony_ci		was_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
3978c2ecf20Sopenharmony_ci		val = enable ? _MASKED_BIT_ENABLE(INSTPM_SELF_EN) :
3988c2ecf20Sopenharmony_ci			       _MASKED_BIT_DISABLE(INSTPM_SELF_EN);
3998c2ecf20Sopenharmony_ci		I915_WRITE(INSTPM, val);
4008c2ecf20Sopenharmony_ci		POSTING_READ(INSTPM);
4018c2ecf20Sopenharmony_ci	} else {
4028c2ecf20Sopenharmony_ci		return false;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	trace_intel_memory_cxsr(dev_priv, was_enabled, enable);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "memory self-refresh is %s (was %s)\n",
4088c2ecf20Sopenharmony_ci		    enableddisabled(enable),
4098c2ecf20Sopenharmony_ci		    enableddisabled(was_enabled));
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	return was_enabled;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci/**
4158c2ecf20Sopenharmony_ci * intel_set_memory_cxsr - Configure CxSR state
4168c2ecf20Sopenharmony_ci * @dev_priv: i915 device
4178c2ecf20Sopenharmony_ci * @enable: Allow vs. disallow CxSR
4188c2ecf20Sopenharmony_ci *
4198c2ecf20Sopenharmony_ci * Allow or disallow the system to enter a special CxSR
4208c2ecf20Sopenharmony_ci * (C-state self refresh) state. What typically happens in CxSR mode
4218c2ecf20Sopenharmony_ci * is that several display FIFOs may get combined into a single larger
4228c2ecf20Sopenharmony_ci * FIFO for a particular plane (so called max FIFO mode) to allow the
4238c2ecf20Sopenharmony_ci * system to defer memory fetches longer, and the memory will enter
4248c2ecf20Sopenharmony_ci * self refresh.
4258c2ecf20Sopenharmony_ci *
4268c2ecf20Sopenharmony_ci * Note that enabling CxSR does not guarantee that the system enter
4278c2ecf20Sopenharmony_ci * this special mode, nor does it guarantee that the system stays
4288c2ecf20Sopenharmony_ci * in that mode once entered. So this just allows/disallows the system
4298c2ecf20Sopenharmony_ci * to autonomously utilize the CxSR mode. Other factors such as core
4308c2ecf20Sopenharmony_ci * C-states will affect when/if the system actually enters/exits the
4318c2ecf20Sopenharmony_ci * CxSR mode.
4328c2ecf20Sopenharmony_ci *
4338c2ecf20Sopenharmony_ci * Note that on VLV/CHV this actually only controls the max FIFO mode,
4348c2ecf20Sopenharmony_ci * and the system is free to enter/exit memory self refresh at any time
4358c2ecf20Sopenharmony_ci * even when the use of CxSR has been disallowed.
4368c2ecf20Sopenharmony_ci *
4378c2ecf20Sopenharmony_ci * While the system is actually in the CxSR/max FIFO mode, some plane
4388c2ecf20Sopenharmony_ci * control registers will not get latched on vblank. Thus in order to
4398c2ecf20Sopenharmony_ci * guarantee the system will respond to changes in the plane registers
4408c2ecf20Sopenharmony_ci * we must always disallow CxSR prior to making changes to those registers.
4418c2ecf20Sopenharmony_ci * Unfortunately the system will re-evaluate the CxSR conditions at
4428c2ecf20Sopenharmony_ci * frame start which happens after vblank start (which is when the plane
4438c2ecf20Sopenharmony_ci * registers would get latched), so we can't proceed with the plane update
4448c2ecf20Sopenharmony_ci * during the same frame where we disallowed CxSR.
4458c2ecf20Sopenharmony_ci *
4468c2ecf20Sopenharmony_ci * Certain platforms also have a deeper HPLL SR mode. Fortunately the
4478c2ecf20Sopenharmony_ci * HPLL SR mode depends on CxSR itself, so we don't have to hand hold
4488c2ecf20Sopenharmony_ci * the hardware w.r.t. HPLL SR when writing to plane registers.
4498c2ecf20Sopenharmony_ci * Disallowing just CxSR is sufficient.
4508c2ecf20Sopenharmony_ci */
4518c2ecf20Sopenharmony_cibool intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	bool ret;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
4568c2ecf20Sopenharmony_ci	ret = _intel_set_memory_cxsr(dev_priv, enable);
4578c2ecf20Sopenharmony_ci	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
4588c2ecf20Sopenharmony_ci		dev_priv->wm.vlv.cxsr = enable;
4598c2ecf20Sopenharmony_ci	else if (IS_G4X(dev_priv))
4608c2ecf20Sopenharmony_ci		dev_priv->wm.g4x.cxsr = enable;
4618c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	return ret;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci/*
4678c2ecf20Sopenharmony_ci * Latency for FIFO fetches is dependent on several factors:
4688c2ecf20Sopenharmony_ci *   - memory configuration (speed, channels)
4698c2ecf20Sopenharmony_ci *   - chipset
4708c2ecf20Sopenharmony_ci *   - current MCH state
4718c2ecf20Sopenharmony_ci * It can be fairly high in some situations, so here we assume a fairly
4728c2ecf20Sopenharmony_ci * pessimal value.  It's a tradeoff between extra memory fetches (if we
4738c2ecf20Sopenharmony_ci * set this value too high, the FIFO will fetch frequently to stay full)
4748c2ecf20Sopenharmony_ci * and power consumption (set it too low to save power and we might see
4758c2ecf20Sopenharmony_ci * FIFO underruns and display "flicker").
4768c2ecf20Sopenharmony_ci *
4778c2ecf20Sopenharmony_ci * A value of 5us seems to be a good balance; safe for very low end
4788c2ecf20Sopenharmony_ci * platforms but not overly aggressive on lower latency configs.
4798c2ecf20Sopenharmony_ci */
4808c2ecf20Sopenharmony_cistatic const int pessimal_latency_ns = 5000;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci#define VLV_FIFO_START(dsparb, dsparb2, lo_shift, hi_shift) \
4838c2ecf20Sopenharmony_ci	((((dsparb) >> (lo_shift)) & 0xff) | ((((dsparb2) >> (hi_shift)) & 0x1) << 8))
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic void vlv_get_fifo_size(struct intel_crtc_state *crtc_state)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
4888c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
4898c2ecf20Sopenharmony_ci	struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state;
4908c2ecf20Sopenharmony_ci	enum pipe pipe = crtc->pipe;
4918c2ecf20Sopenharmony_ci	int sprite0_start, sprite1_start;
4928c2ecf20Sopenharmony_ci	u32 dsparb, dsparb2, dsparb3;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	switch (pipe) {
4958c2ecf20Sopenharmony_ci	case PIPE_A:
4968c2ecf20Sopenharmony_ci		dsparb = I915_READ(DSPARB);
4978c2ecf20Sopenharmony_ci		dsparb2 = I915_READ(DSPARB2);
4988c2ecf20Sopenharmony_ci		sprite0_start = VLV_FIFO_START(dsparb, dsparb2, 0, 0);
4998c2ecf20Sopenharmony_ci		sprite1_start = VLV_FIFO_START(dsparb, dsparb2, 8, 4);
5008c2ecf20Sopenharmony_ci		break;
5018c2ecf20Sopenharmony_ci	case PIPE_B:
5028c2ecf20Sopenharmony_ci		dsparb = I915_READ(DSPARB);
5038c2ecf20Sopenharmony_ci		dsparb2 = I915_READ(DSPARB2);
5048c2ecf20Sopenharmony_ci		sprite0_start = VLV_FIFO_START(dsparb, dsparb2, 16, 8);
5058c2ecf20Sopenharmony_ci		sprite1_start = VLV_FIFO_START(dsparb, dsparb2, 24, 12);
5068c2ecf20Sopenharmony_ci		break;
5078c2ecf20Sopenharmony_ci	case PIPE_C:
5088c2ecf20Sopenharmony_ci		dsparb2 = I915_READ(DSPARB2);
5098c2ecf20Sopenharmony_ci		dsparb3 = I915_READ(DSPARB3);
5108c2ecf20Sopenharmony_ci		sprite0_start = VLV_FIFO_START(dsparb3, dsparb2, 0, 16);
5118c2ecf20Sopenharmony_ci		sprite1_start = VLV_FIFO_START(dsparb3, dsparb2, 8, 20);
5128c2ecf20Sopenharmony_ci		break;
5138c2ecf20Sopenharmony_ci	default:
5148c2ecf20Sopenharmony_ci		MISSING_CASE(pipe);
5158c2ecf20Sopenharmony_ci		return;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	fifo_state->plane[PLANE_PRIMARY] = sprite0_start;
5198c2ecf20Sopenharmony_ci	fifo_state->plane[PLANE_SPRITE0] = sprite1_start - sprite0_start;
5208c2ecf20Sopenharmony_ci	fifo_state->plane[PLANE_SPRITE1] = 511 - sprite1_start;
5218c2ecf20Sopenharmony_ci	fifo_state->plane[PLANE_CURSOR] = 63;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic int i9xx_get_fifo_size(struct drm_i915_private *dev_priv,
5258c2ecf20Sopenharmony_ci			      enum i9xx_plane_id i9xx_plane)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	u32 dsparb = I915_READ(DSPARB);
5288c2ecf20Sopenharmony_ci	int size;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	size = dsparb & 0x7f;
5318c2ecf20Sopenharmony_ci	if (i9xx_plane == PLANE_B)
5328c2ecf20Sopenharmony_ci		size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "FIFO size - (0x%08x) %c: %d\n",
5358c2ecf20Sopenharmony_ci		    dsparb, plane_name(i9xx_plane), size);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	return size;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic int i830_get_fifo_size(struct drm_i915_private *dev_priv,
5418c2ecf20Sopenharmony_ci			      enum i9xx_plane_id i9xx_plane)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	u32 dsparb = I915_READ(DSPARB);
5448c2ecf20Sopenharmony_ci	int size;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	size = dsparb & 0x1ff;
5478c2ecf20Sopenharmony_ci	if (i9xx_plane == PLANE_B)
5488c2ecf20Sopenharmony_ci		size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size;
5498c2ecf20Sopenharmony_ci	size >>= 1; /* Convert to cachelines */
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "FIFO size - (0x%08x) %c: %d\n",
5528c2ecf20Sopenharmony_ci		    dsparb, plane_name(i9xx_plane), size);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return size;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic int i845_get_fifo_size(struct drm_i915_private *dev_priv,
5588c2ecf20Sopenharmony_ci			      enum i9xx_plane_id i9xx_plane)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	u32 dsparb = I915_READ(DSPARB);
5618c2ecf20Sopenharmony_ci	int size;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	size = dsparb & 0x7f;
5648c2ecf20Sopenharmony_ci	size >>= 2; /* Convert to cachelines */
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "FIFO size - (0x%08x) %c: %d\n",
5678c2ecf20Sopenharmony_ci		    dsparb, plane_name(i9xx_plane), size);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	return size;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci/* Pineview has different values for various configs */
5738c2ecf20Sopenharmony_cistatic const struct intel_watermark_params pnv_display_wm = {
5748c2ecf20Sopenharmony_ci	.fifo_size = PINEVIEW_DISPLAY_FIFO,
5758c2ecf20Sopenharmony_ci	.max_wm = PINEVIEW_MAX_WM,
5768c2ecf20Sopenharmony_ci	.default_wm = PINEVIEW_DFT_WM,
5778c2ecf20Sopenharmony_ci	.guard_size = PINEVIEW_GUARD_WM,
5788c2ecf20Sopenharmony_ci	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
5798c2ecf20Sopenharmony_ci};
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic const struct intel_watermark_params pnv_display_hplloff_wm = {
5828c2ecf20Sopenharmony_ci	.fifo_size = PINEVIEW_DISPLAY_FIFO,
5838c2ecf20Sopenharmony_ci	.max_wm = PINEVIEW_MAX_WM,
5848c2ecf20Sopenharmony_ci	.default_wm = PINEVIEW_DFT_HPLLOFF_WM,
5858c2ecf20Sopenharmony_ci	.guard_size = PINEVIEW_GUARD_WM,
5868c2ecf20Sopenharmony_ci	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
5878c2ecf20Sopenharmony_ci};
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic const struct intel_watermark_params pnv_cursor_wm = {
5908c2ecf20Sopenharmony_ci	.fifo_size = PINEVIEW_CURSOR_FIFO,
5918c2ecf20Sopenharmony_ci	.max_wm = PINEVIEW_CURSOR_MAX_WM,
5928c2ecf20Sopenharmony_ci	.default_wm = PINEVIEW_CURSOR_DFT_WM,
5938c2ecf20Sopenharmony_ci	.guard_size = PINEVIEW_CURSOR_GUARD_WM,
5948c2ecf20Sopenharmony_ci	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
5958c2ecf20Sopenharmony_ci};
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic const struct intel_watermark_params pnv_cursor_hplloff_wm = {
5988c2ecf20Sopenharmony_ci	.fifo_size = PINEVIEW_CURSOR_FIFO,
5998c2ecf20Sopenharmony_ci	.max_wm = PINEVIEW_CURSOR_MAX_WM,
6008c2ecf20Sopenharmony_ci	.default_wm = PINEVIEW_CURSOR_DFT_WM,
6018c2ecf20Sopenharmony_ci	.guard_size = PINEVIEW_CURSOR_GUARD_WM,
6028c2ecf20Sopenharmony_ci	.cacheline_size = PINEVIEW_FIFO_LINE_SIZE,
6038c2ecf20Sopenharmony_ci};
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic const struct intel_watermark_params i965_cursor_wm_info = {
6068c2ecf20Sopenharmony_ci	.fifo_size = I965_CURSOR_FIFO,
6078c2ecf20Sopenharmony_ci	.max_wm = I965_CURSOR_MAX_WM,
6088c2ecf20Sopenharmony_ci	.default_wm = I965_CURSOR_DFT_WM,
6098c2ecf20Sopenharmony_ci	.guard_size = 2,
6108c2ecf20Sopenharmony_ci	.cacheline_size = I915_FIFO_LINE_SIZE,
6118c2ecf20Sopenharmony_ci};
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic const struct intel_watermark_params i945_wm_info = {
6148c2ecf20Sopenharmony_ci	.fifo_size = I945_FIFO_SIZE,
6158c2ecf20Sopenharmony_ci	.max_wm = I915_MAX_WM,
6168c2ecf20Sopenharmony_ci	.default_wm = 1,
6178c2ecf20Sopenharmony_ci	.guard_size = 2,
6188c2ecf20Sopenharmony_ci	.cacheline_size = I915_FIFO_LINE_SIZE,
6198c2ecf20Sopenharmony_ci};
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic const struct intel_watermark_params i915_wm_info = {
6228c2ecf20Sopenharmony_ci	.fifo_size = I915_FIFO_SIZE,
6238c2ecf20Sopenharmony_ci	.max_wm = I915_MAX_WM,
6248c2ecf20Sopenharmony_ci	.default_wm = 1,
6258c2ecf20Sopenharmony_ci	.guard_size = 2,
6268c2ecf20Sopenharmony_ci	.cacheline_size = I915_FIFO_LINE_SIZE,
6278c2ecf20Sopenharmony_ci};
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic const struct intel_watermark_params i830_a_wm_info = {
6308c2ecf20Sopenharmony_ci	.fifo_size = I855GM_FIFO_SIZE,
6318c2ecf20Sopenharmony_ci	.max_wm = I915_MAX_WM,
6328c2ecf20Sopenharmony_ci	.default_wm = 1,
6338c2ecf20Sopenharmony_ci	.guard_size = 2,
6348c2ecf20Sopenharmony_ci	.cacheline_size = I830_FIFO_LINE_SIZE,
6358c2ecf20Sopenharmony_ci};
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic const struct intel_watermark_params i830_bc_wm_info = {
6388c2ecf20Sopenharmony_ci	.fifo_size = I855GM_FIFO_SIZE,
6398c2ecf20Sopenharmony_ci	.max_wm = I915_MAX_WM/2,
6408c2ecf20Sopenharmony_ci	.default_wm = 1,
6418c2ecf20Sopenharmony_ci	.guard_size = 2,
6428c2ecf20Sopenharmony_ci	.cacheline_size = I830_FIFO_LINE_SIZE,
6438c2ecf20Sopenharmony_ci};
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_cistatic const struct intel_watermark_params i845_wm_info = {
6468c2ecf20Sopenharmony_ci	.fifo_size = I830_FIFO_SIZE,
6478c2ecf20Sopenharmony_ci	.max_wm = I915_MAX_WM,
6488c2ecf20Sopenharmony_ci	.default_wm = 1,
6498c2ecf20Sopenharmony_ci	.guard_size = 2,
6508c2ecf20Sopenharmony_ci	.cacheline_size = I830_FIFO_LINE_SIZE,
6518c2ecf20Sopenharmony_ci};
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci/**
6548c2ecf20Sopenharmony_ci * intel_wm_method1 - Method 1 / "small buffer" watermark formula
6558c2ecf20Sopenharmony_ci * @pixel_rate: Pipe pixel rate in kHz
6568c2ecf20Sopenharmony_ci * @cpp: Plane bytes per pixel
6578c2ecf20Sopenharmony_ci * @latency: Memory wakeup latency in 0.1us units
6588c2ecf20Sopenharmony_ci *
6598c2ecf20Sopenharmony_ci * Compute the watermark using the method 1 or "small buffer"
6608c2ecf20Sopenharmony_ci * formula. The caller may additonally add extra cachelines
6618c2ecf20Sopenharmony_ci * to account for TLB misses and clock crossings.
6628c2ecf20Sopenharmony_ci *
6638c2ecf20Sopenharmony_ci * This method is concerned with the short term drain rate
6648c2ecf20Sopenharmony_ci * of the FIFO, ie. it does not account for blanking periods
6658c2ecf20Sopenharmony_ci * which would effectively reduce the average drain rate across
6668c2ecf20Sopenharmony_ci * a longer period. The name "small" refers to the fact the
6678c2ecf20Sopenharmony_ci * FIFO is relatively small compared to the amount of data
6688c2ecf20Sopenharmony_ci * fetched.
6698c2ecf20Sopenharmony_ci *
6708c2ecf20Sopenharmony_ci * The FIFO level vs. time graph might look something like:
6718c2ecf20Sopenharmony_ci *
6728c2ecf20Sopenharmony_ci *   |\   |\
6738c2ecf20Sopenharmony_ci *   | \  | \
6748c2ecf20Sopenharmony_ci * __---__---__ (- plane active, _ blanking)
6758c2ecf20Sopenharmony_ci * -> time
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * or perhaps like this:
6788c2ecf20Sopenharmony_ci *
6798c2ecf20Sopenharmony_ci *   |\|\  |\|\
6808c2ecf20Sopenharmony_ci * __----__----__ (- plane active, _ blanking)
6818c2ecf20Sopenharmony_ci * -> time
6828c2ecf20Sopenharmony_ci *
6838c2ecf20Sopenharmony_ci * Returns:
6848c2ecf20Sopenharmony_ci * The watermark in bytes
6858c2ecf20Sopenharmony_ci */
6868c2ecf20Sopenharmony_cistatic unsigned int intel_wm_method1(unsigned int pixel_rate,
6878c2ecf20Sopenharmony_ci				     unsigned int cpp,
6888c2ecf20Sopenharmony_ci				     unsigned int latency)
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	u64 ret;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	ret = mul_u32_u32(pixel_rate, cpp * latency);
6938c2ecf20Sopenharmony_ci	ret = DIV_ROUND_UP_ULL(ret, 10000);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	return ret;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci/**
6998c2ecf20Sopenharmony_ci * intel_wm_method2 - Method 2 / "large buffer" watermark formula
7008c2ecf20Sopenharmony_ci * @pixel_rate: Pipe pixel rate in kHz
7018c2ecf20Sopenharmony_ci * @htotal: Pipe horizontal total
7028c2ecf20Sopenharmony_ci * @width: Plane width in pixels
7038c2ecf20Sopenharmony_ci * @cpp: Plane bytes per pixel
7048c2ecf20Sopenharmony_ci * @latency: Memory wakeup latency in 0.1us units
7058c2ecf20Sopenharmony_ci *
7068c2ecf20Sopenharmony_ci * Compute the watermark using the method 2 or "large buffer"
7078c2ecf20Sopenharmony_ci * formula. The caller may additonally add extra cachelines
7088c2ecf20Sopenharmony_ci * to account for TLB misses and clock crossings.
7098c2ecf20Sopenharmony_ci *
7108c2ecf20Sopenharmony_ci * This method is concerned with the long term drain rate
7118c2ecf20Sopenharmony_ci * of the FIFO, ie. it does account for blanking periods
7128c2ecf20Sopenharmony_ci * which effectively reduce the average drain rate across
7138c2ecf20Sopenharmony_ci * a longer period. The name "large" refers to the fact the
7148c2ecf20Sopenharmony_ci * FIFO is relatively large compared to the amount of data
7158c2ecf20Sopenharmony_ci * fetched.
7168c2ecf20Sopenharmony_ci *
7178c2ecf20Sopenharmony_ci * The FIFO level vs. time graph might look something like:
7188c2ecf20Sopenharmony_ci *
7198c2ecf20Sopenharmony_ci *    |\___       |\___
7208c2ecf20Sopenharmony_ci *    |    \___   |    \___
7218c2ecf20Sopenharmony_ci *    |        \  |        \
7228c2ecf20Sopenharmony_ci * __ --__--__--__--__--__--__ (- plane active, _ blanking)
7238c2ecf20Sopenharmony_ci * -> time
7248c2ecf20Sopenharmony_ci *
7258c2ecf20Sopenharmony_ci * Returns:
7268c2ecf20Sopenharmony_ci * The watermark in bytes
7278c2ecf20Sopenharmony_ci */
7288c2ecf20Sopenharmony_cistatic unsigned int intel_wm_method2(unsigned int pixel_rate,
7298c2ecf20Sopenharmony_ci				     unsigned int htotal,
7308c2ecf20Sopenharmony_ci				     unsigned int width,
7318c2ecf20Sopenharmony_ci				     unsigned int cpp,
7328c2ecf20Sopenharmony_ci				     unsigned int latency)
7338c2ecf20Sopenharmony_ci{
7348c2ecf20Sopenharmony_ci	unsigned int ret;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	/*
7378c2ecf20Sopenharmony_ci	 * FIXME remove once all users are computing
7388c2ecf20Sopenharmony_ci	 * watermarks in the correct place.
7398c2ecf20Sopenharmony_ci	 */
7408c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(htotal == 0))
7418c2ecf20Sopenharmony_ci		htotal = 1;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	ret = (latency * pixel_rate) / (htotal * 10000);
7448c2ecf20Sopenharmony_ci	ret = (ret + 1) * width * cpp;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return ret;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci/**
7508c2ecf20Sopenharmony_ci * intel_calculate_wm - calculate watermark level
7518c2ecf20Sopenharmony_ci * @pixel_rate: pixel clock
7528c2ecf20Sopenharmony_ci * @wm: chip FIFO params
7538c2ecf20Sopenharmony_ci * @fifo_size: size of the FIFO buffer
7548c2ecf20Sopenharmony_ci * @cpp: bytes per pixel
7558c2ecf20Sopenharmony_ci * @latency_ns: memory latency for the platform
7568c2ecf20Sopenharmony_ci *
7578c2ecf20Sopenharmony_ci * Calculate the watermark level (the level at which the display plane will
7588c2ecf20Sopenharmony_ci * start fetching from memory again).  Each chip has a different display
7598c2ecf20Sopenharmony_ci * FIFO size and allocation, so the caller needs to figure that out and pass
7608c2ecf20Sopenharmony_ci * in the correct intel_watermark_params structure.
7618c2ecf20Sopenharmony_ci *
7628c2ecf20Sopenharmony_ci * As the pixel clock runs, the FIFO will be drained at a rate that depends
7638c2ecf20Sopenharmony_ci * on the pixel size.  When it reaches the watermark level, it'll start
7648c2ecf20Sopenharmony_ci * fetching FIFO line sized based chunks from memory until the FIFO fills
7658c2ecf20Sopenharmony_ci * past the watermark point.  If the FIFO drains completely, a FIFO underrun
7668c2ecf20Sopenharmony_ci * will occur, and a display engine hang could result.
7678c2ecf20Sopenharmony_ci */
7688c2ecf20Sopenharmony_cistatic unsigned int intel_calculate_wm(int pixel_rate,
7698c2ecf20Sopenharmony_ci				       const struct intel_watermark_params *wm,
7708c2ecf20Sopenharmony_ci				       int fifo_size, int cpp,
7718c2ecf20Sopenharmony_ci				       unsigned int latency_ns)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	int entries, wm_size;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	/*
7768c2ecf20Sopenharmony_ci	 * Note: we need to make sure we don't overflow for various clock &
7778c2ecf20Sopenharmony_ci	 * latency values.
7788c2ecf20Sopenharmony_ci	 * clocks go from a few thousand to several hundred thousand.
7798c2ecf20Sopenharmony_ci	 * latency is usually a few thousand
7808c2ecf20Sopenharmony_ci	 */
7818c2ecf20Sopenharmony_ci	entries = intel_wm_method1(pixel_rate, cpp,
7828c2ecf20Sopenharmony_ci				   latency_ns / 100);
7838c2ecf20Sopenharmony_ci	entries = DIV_ROUND_UP(entries, wm->cacheline_size) +
7848c2ecf20Sopenharmony_ci		wm->guard_size;
7858c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	wm_size = fifo_size - entries;
7888c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/* Don't promote wm_size to unsigned... */
7918c2ecf20Sopenharmony_ci	if (wm_size > wm->max_wm)
7928c2ecf20Sopenharmony_ci		wm_size = wm->max_wm;
7938c2ecf20Sopenharmony_ci	if (wm_size <= 0)
7948c2ecf20Sopenharmony_ci		wm_size = wm->default_wm;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/*
7978c2ecf20Sopenharmony_ci	 * Bspec seems to indicate that the value shouldn't be lower than
7988c2ecf20Sopenharmony_ci	 * 'burst size + 1'. Certainly 830 is quite unhappy with low values.
7998c2ecf20Sopenharmony_ci	 * Lets go for 8 which is the burst size since certain platforms
8008c2ecf20Sopenharmony_ci	 * already use a hardcoded 8 (which is what the spec says should be
8018c2ecf20Sopenharmony_ci	 * done).
8028c2ecf20Sopenharmony_ci	 */
8038c2ecf20Sopenharmony_ci	if (wm_size <= 8)
8048c2ecf20Sopenharmony_ci		wm_size = 8;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	return wm_size;
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cistatic bool is_disabling(int old, int new, int threshold)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	return old >= threshold && new < threshold;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_cistatic bool is_enabling(int old, int new, int threshold)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	return old < threshold && new >= threshold;
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic int intel_wm_num_levels(struct drm_i915_private *dev_priv)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	return dev_priv->wm.max_level + 1;
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_cistatic bool intel_wm_plane_visible(const struct intel_crtc_state *crtc_state,
8258c2ecf20Sopenharmony_ci				   const struct intel_plane_state *plane_state)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/* FIXME check the 'enable' instead */
8308c2ecf20Sopenharmony_ci	if (!crtc_state->hw.active)
8318c2ecf20Sopenharmony_ci		return false;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	/*
8348c2ecf20Sopenharmony_ci	 * Treat cursor with fb as always visible since cursor updates
8358c2ecf20Sopenharmony_ci	 * can happen faster than the vrefresh rate, and the current
8368c2ecf20Sopenharmony_ci	 * watermark code doesn't handle that correctly. Cursor updates
8378c2ecf20Sopenharmony_ci	 * which set/clear the fb or change the cursor size are going
8388c2ecf20Sopenharmony_ci	 * to get throttled by intel_legacy_cursor_update() to work
8398c2ecf20Sopenharmony_ci	 * around this problem with the watermark code.
8408c2ecf20Sopenharmony_ci	 */
8418c2ecf20Sopenharmony_ci	if (plane->id == PLANE_CURSOR)
8428c2ecf20Sopenharmony_ci		return plane_state->hw.fb != NULL;
8438c2ecf20Sopenharmony_ci	else
8448c2ecf20Sopenharmony_ci		return plane_state->uapi.visible;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic bool intel_crtc_active(struct intel_crtc *crtc)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	/* Be paranoid as we can arrive here with only partial
8508c2ecf20Sopenharmony_ci	 * state retrieved from the hardware during setup.
8518c2ecf20Sopenharmony_ci	 *
8528c2ecf20Sopenharmony_ci	 * We can ditch the adjusted_mode.crtc_clock check as soon
8538c2ecf20Sopenharmony_ci	 * as Haswell has gained clock readout/fastboot support.
8548c2ecf20Sopenharmony_ci	 *
8558c2ecf20Sopenharmony_ci	 * We can ditch the crtc->primary->state->fb check as soon as we can
8568c2ecf20Sopenharmony_ci	 * properly reconstruct framebuffers.
8578c2ecf20Sopenharmony_ci	 *
8588c2ecf20Sopenharmony_ci	 * FIXME: The intel_crtc->active here should be switched to
8598c2ecf20Sopenharmony_ci	 * crtc->state->active once we have proper CRTC states wired up
8608c2ecf20Sopenharmony_ci	 * for atomic.
8618c2ecf20Sopenharmony_ci	 */
8628c2ecf20Sopenharmony_ci	return crtc->active && crtc->base.primary->state->fb &&
8638c2ecf20Sopenharmony_ci		crtc->config->hw.adjusted_mode.crtc_clock;
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic struct intel_crtc *single_enabled_crtc(struct drm_i915_private *dev_priv)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	struct intel_crtc *crtc, *enabled = NULL;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
8718c2ecf20Sopenharmony_ci		if (intel_crtc_active(crtc)) {
8728c2ecf20Sopenharmony_ci			if (enabled)
8738c2ecf20Sopenharmony_ci				return NULL;
8748c2ecf20Sopenharmony_ci			enabled = crtc;
8758c2ecf20Sopenharmony_ci		}
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	return enabled;
8798c2ecf20Sopenharmony_ci}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_cistatic void pnv_update_wm(struct intel_crtc *unused_crtc)
8828c2ecf20Sopenharmony_ci{
8838c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
8848c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
8858c2ecf20Sopenharmony_ci	const struct cxsr_latency *latency;
8868c2ecf20Sopenharmony_ci	u32 reg;
8878c2ecf20Sopenharmony_ci	unsigned int wm;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	latency = intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
8908c2ecf20Sopenharmony_ci					 dev_priv->is_ddr3,
8918c2ecf20Sopenharmony_ci					 dev_priv->fsb_freq,
8928c2ecf20Sopenharmony_ci					 dev_priv->mem_freq);
8938c2ecf20Sopenharmony_ci	if (!latency) {
8948c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
8958c2ecf20Sopenharmony_ci			    "Unknown FSB/MEM found, disable CxSR\n");
8968c2ecf20Sopenharmony_ci		intel_set_memory_cxsr(dev_priv, false);
8978c2ecf20Sopenharmony_ci		return;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	crtc = single_enabled_crtc(dev_priv);
9018c2ecf20Sopenharmony_ci	if (crtc) {
9028c2ecf20Sopenharmony_ci		const struct drm_display_mode *adjusted_mode =
9038c2ecf20Sopenharmony_ci			&crtc->config->hw.adjusted_mode;
9048c2ecf20Sopenharmony_ci		const struct drm_framebuffer *fb =
9058c2ecf20Sopenharmony_ci			crtc->base.primary->state->fb;
9068c2ecf20Sopenharmony_ci		int cpp = fb->format->cpp[0];
9078c2ecf20Sopenharmony_ci		int clock = adjusted_mode->crtc_clock;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci		/* Display SR */
9108c2ecf20Sopenharmony_ci		wm = intel_calculate_wm(clock, &pnv_display_wm,
9118c2ecf20Sopenharmony_ci					pnv_display_wm.fifo_size,
9128c2ecf20Sopenharmony_ci					cpp, latency->display_sr);
9138c2ecf20Sopenharmony_ci		reg = I915_READ(DSPFW1);
9148c2ecf20Sopenharmony_ci		reg &= ~DSPFW_SR_MASK;
9158c2ecf20Sopenharmony_ci		reg |= FW_WM(wm, SR);
9168c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW1, reg);
9178c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "DSPFW1 register is %x\n", reg);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci		/* cursor SR */
9208c2ecf20Sopenharmony_ci		wm = intel_calculate_wm(clock, &pnv_cursor_wm,
9218c2ecf20Sopenharmony_ci					pnv_display_wm.fifo_size,
9228c2ecf20Sopenharmony_ci					4, latency->cursor_sr);
9238c2ecf20Sopenharmony_ci		reg = I915_READ(DSPFW3);
9248c2ecf20Sopenharmony_ci		reg &= ~DSPFW_CURSOR_SR_MASK;
9258c2ecf20Sopenharmony_ci		reg |= FW_WM(wm, CURSOR_SR);
9268c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW3, reg);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		/* Display HPLL off SR */
9298c2ecf20Sopenharmony_ci		wm = intel_calculate_wm(clock, &pnv_display_hplloff_wm,
9308c2ecf20Sopenharmony_ci					pnv_display_hplloff_wm.fifo_size,
9318c2ecf20Sopenharmony_ci					cpp, latency->display_hpll_disable);
9328c2ecf20Sopenharmony_ci		reg = I915_READ(DSPFW3);
9338c2ecf20Sopenharmony_ci		reg &= ~DSPFW_HPLL_SR_MASK;
9348c2ecf20Sopenharmony_ci		reg |= FW_WM(wm, HPLL_SR);
9358c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW3, reg);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci		/* cursor HPLL off SR */
9388c2ecf20Sopenharmony_ci		wm = intel_calculate_wm(clock, &pnv_cursor_hplloff_wm,
9398c2ecf20Sopenharmony_ci					pnv_display_hplloff_wm.fifo_size,
9408c2ecf20Sopenharmony_ci					4, latency->cursor_hpll_disable);
9418c2ecf20Sopenharmony_ci		reg = I915_READ(DSPFW3);
9428c2ecf20Sopenharmony_ci		reg &= ~DSPFW_HPLL_CURSOR_MASK;
9438c2ecf20Sopenharmony_ci		reg |= FW_WM(wm, HPLL_CURSOR);
9448c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW3, reg);
9458c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "DSPFW3 register is %x\n", reg);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		intel_set_memory_cxsr(dev_priv, true);
9488c2ecf20Sopenharmony_ci	} else {
9498c2ecf20Sopenharmony_ci		intel_set_memory_cxsr(dev_priv, false);
9508c2ecf20Sopenharmony_ci	}
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci/*
9548c2ecf20Sopenharmony_ci * Documentation says:
9558c2ecf20Sopenharmony_ci * "If the line size is small, the TLB fetches can get in the way of the
9568c2ecf20Sopenharmony_ci *  data fetches, causing some lag in the pixel data return which is not
9578c2ecf20Sopenharmony_ci *  accounted for in the above formulas. The following adjustment only
9588c2ecf20Sopenharmony_ci *  needs to be applied if eight whole lines fit in the buffer at once.
9598c2ecf20Sopenharmony_ci *  The WM is adjusted upwards by the difference between the FIFO size
9608c2ecf20Sopenharmony_ci *  and the size of 8 whole lines. This adjustment is always performed
9618c2ecf20Sopenharmony_ci *  in the actual pixel depth regardless of whether FBC is enabled or not."
9628c2ecf20Sopenharmony_ci */
9638c2ecf20Sopenharmony_cistatic unsigned int g4x_tlb_miss_wa(int fifo_size, int width, int cpp)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	int tlb_miss = fifo_size * 64 - width * cpp * 8;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	return max(0, tlb_miss);
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_cistatic void g4x_write_wm_values(struct drm_i915_private *dev_priv,
9718c2ecf20Sopenharmony_ci				const struct g4x_wm_values *wm)
9728c2ecf20Sopenharmony_ci{
9738c2ecf20Sopenharmony_ci	enum pipe pipe;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe)
9768c2ecf20Sopenharmony_ci		trace_g4x_wm(intel_get_crtc_for_pipe(dev_priv, pipe), wm);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW1,
9798c2ecf20Sopenharmony_ci		   FW_WM(wm->sr.plane, SR) |
9808c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_B].plane[PLANE_CURSOR], CURSORB) |
9818c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_B].plane[PLANE_PRIMARY], PLANEB) |
9828c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_A].plane[PLANE_PRIMARY], PLANEA));
9838c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW2,
9848c2ecf20Sopenharmony_ci		   (wm->fbc_en ? DSPFW_FBC_SR_EN : 0) |
9858c2ecf20Sopenharmony_ci		   FW_WM(wm->sr.fbc, FBC_SR) |
9868c2ecf20Sopenharmony_ci		   FW_WM(wm->hpll.fbc, FBC_HPLL_SR) |
9878c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE0], SPRITEB) |
9888c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_A].plane[PLANE_CURSOR], CURSORA) |
9898c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE0], SPRITEA));
9908c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW3,
9918c2ecf20Sopenharmony_ci		   (wm->hpll_en ? DSPFW_HPLL_SR_EN : 0) |
9928c2ecf20Sopenharmony_ci		   FW_WM(wm->sr.cursor, CURSOR_SR) |
9938c2ecf20Sopenharmony_ci		   FW_WM(wm->hpll.cursor, HPLL_CURSOR) |
9948c2ecf20Sopenharmony_ci		   FW_WM(wm->hpll.plane, HPLL_SR));
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	POSTING_READ(DSPFW1);
9978c2ecf20Sopenharmony_ci}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci#define FW_WM_VLV(value, plane) \
10008c2ecf20Sopenharmony_ci	(((value) << DSPFW_ ## plane ## _SHIFT) & DSPFW_ ## plane ## _MASK_VLV)
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_cistatic void vlv_write_wm_values(struct drm_i915_private *dev_priv,
10038c2ecf20Sopenharmony_ci				const struct vlv_wm_values *wm)
10048c2ecf20Sopenharmony_ci{
10058c2ecf20Sopenharmony_ci	enum pipe pipe;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
10088c2ecf20Sopenharmony_ci		trace_vlv_wm(intel_get_crtc_for_pipe(dev_priv, pipe), wm);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci		I915_WRITE(VLV_DDL(pipe),
10118c2ecf20Sopenharmony_ci			   (wm->ddl[pipe].plane[PLANE_CURSOR] << DDL_CURSOR_SHIFT) |
10128c2ecf20Sopenharmony_ci			   (wm->ddl[pipe].plane[PLANE_SPRITE1] << DDL_SPRITE_SHIFT(1)) |
10138c2ecf20Sopenharmony_ci			   (wm->ddl[pipe].plane[PLANE_SPRITE0] << DDL_SPRITE_SHIFT(0)) |
10148c2ecf20Sopenharmony_ci			   (wm->ddl[pipe].plane[PLANE_PRIMARY] << DDL_PLANE_SHIFT));
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/*
10188c2ecf20Sopenharmony_ci	 * Zero the (unused) WM1 watermarks, and also clear all the
10198c2ecf20Sopenharmony_ci	 * high order bits so that there are no out of bounds values
10208c2ecf20Sopenharmony_ci	 * present in the registers during the reprogramming.
10218c2ecf20Sopenharmony_ci	 */
10228c2ecf20Sopenharmony_ci	I915_WRITE(DSPHOWM, 0);
10238c2ecf20Sopenharmony_ci	I915_WRITE(DSPHOWM1, 0);
10248c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW4, 0);
10258c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW5, 0);
10268c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW6, 0);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW1,
10298c2ecf20Sopenharmony_ci		   FW_WM(wm->sr.plane, SR) |
10308c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_B].plane[PLANE_CURSOR], CURSORB) |
10318c2ecf20Sopenharmony_ci		   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_PRIMARY], PLANEB) |
10328c2ecf20Sopenharmony_ci		   FW_WM_VLV(wm->pipe[PIPE_A].plane[PLANE_PRIMARY], PLANEA));
10338c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW2,
10348c2ecf20Sopenharmony_ci		   FW_WM_VLV(wm->pipe[PIPE_A].plane[PLANE_SPRITE1], SPRITEB) |
10358c2ecf20Sopenharmony_ci		   FW_WM(wm->pipe[PIPE_A].plane[PLANE_CURSOR], CURSORA) |
10368c2ecf20Sopenharmony_ci		   FW_WM_VLV(wm->pipe[PIPE_A].plane[PLANE_SPRITE0], SPRITEA));
10378c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW3,
10388c2ecf20Sopenharmony_ci		   FW_WM(wm->sr.cursor, CURSOR_SR));
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	if (IS_CHERRYVIEW(dev_priv)) {
10418c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW7_CHV,
10428c2ecf20Sopenharmony_ci			   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE1], SPRITED) |
10438c2ecf20Sopenharmony_ci			   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE0], SPRITEC));
10448c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW8_CHV,
10458c2ecf20Sopenharmony_ci			   FW_WM_VLV(wm->pipe[PIPE_C].plane[PLANE_SPRITE1], SPRITEF) |
10468c2ecf20Sopenharmony_ci			   FW_WM_VLV(wm->pipe[PIPE_C].plane[PLANE_SPRITE0], SPRITEE));
10478c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW9_CHV,
10488c2ecf20Sopenharmony_ci			   FW_WM_VLV(wm->pipe[PIPE_C].plane[PLANE_PRIMARY], PLANEC) |
10498c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_C].plane[PLANE_CURSOR], CURSORC));
10508c2ecf20Sopenharmony_ci		I915_WRITE(DSPHOWM,
10518c2ecf20Sopenharmony_ci			   FW_WM(wm->sr.plane >> 9, SR_HI) |
10528c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_C].plane[PLANE_SPRITE1] >> 8, SPRITEF_HI) |
10538c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_C].plane[PLANE_SPRITE0] >> 8, SPRITEE_HI) |
10548c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_C].plane[PLANE_PRIMARY] >> 8, PLANEC_HI) |
10558c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE1] >> 8, SPRITED_HI) |
10568c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE0] >> 8, SPRITEC_HI) |
10578c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_PRIMARY] >> 8, PLANEB_HI) |
10588c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE1] >> 8, SPRITEB_HI) |
10598c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE0] >> 8, SPRITEA_HI) |
10608c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_PRIMARY] >> 8, PLANEA_HI));
10618c2ecf20Sopenharmony_ci	} else {
10628c2ecf20Sopenharmony_ci		I915_WRITE(DSPFW7,
10638c2ecf20Sopenharmony_ci			   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE1], SPRITED) |
10648c2ecf20Sopenharmony_ci			   FW_WM_VLV(wm->pipe[PIPE_B].plane[PLANE_SPRITE0], SPRITEC));
10658c2ecf20Sopenharmony_ci		I915_WRITE(DSPHOWM,
10668c2ecf20Sopenharmony_ci			   FW_WM(wm->sr.plane >> 9, SR_HI) |
10678c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE1] >> 8, SPRITED_HI) |
10688c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_SPRITE0] >> 8, SPRITEC_HI) |
10698c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_B].plane[PLANE_PRIMARY] >> 8, PLANEB_HI) |
10708c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE1] >> 8, SPRITEB_HI) |
10718c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_SPRITE0] >> 8, SPRITEA_HI) |
10728c2ecf20Sopenharmony_ci			   FW_WM(wm->pipe[PIPE_A].plane[PLANE_PRIMARY] >> 8, PLANEA_HI));
10738c2ecf20Sopenharmony_ci	}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	POSTING_READ(DSPFW1);
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci#undef FW_WM_VLV
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic void g4x_setup_wm_latency(struct drm_i915_private *dev_priv)
10818c2ecf20Sopenharmony_ci{
10828c2ecf20Sopenharmony_ci	/* all latencies in usec */
10838c2ecf20Sopenharmony_ci	dev_priv->wm.pri_latency[G4X_WM_LEVEL_NORMAL] = 5;
10848c2ecf20Sopenharmony_ci	dev_priv->wm.pri_latency[G4X_WM_LEVEL_SR] = 12;
10858c2ecf20Sopenharmony_ci	dev_priv->wm.pri_latency[G4X_WM_LEVEL_HPLL] = 35;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	dev_priv->wm.max_level = G4X_WM_LEVEL_HPLL;
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_cistatic int g4x_plane_fifo_size(enum plane_id plane_id, int level)
10918c2ecf20Sopenharmony_ci{
10928c2ecf20Sopenharmony_ci	/*
10938c2ecf20Sopenharmony_ci	 * DSPCNTR[13] supposedly controls whether the
10948c2ecf20Sopenharmony_ci	 * primary plane can use the FIFO space otherwise
10958c2ecf20Sopenharmony_ci	 * reserved for the sprite plane. It's not 100% clear
10968c2ecf20Sopenharmony_ci	 * what the actual FIFO size is, but it looks like we
10978c2ecf20Sopenharmony_ci	 * can happily set both primary and sprite watermarks
10988c2ecf20Sopenharmony_ci	 * up to 127 cachelines. So that would seem to mean
10998c2ecf20Sopenharmony_ci	 * that either DSPCNTR[13] doesn't do anything, or that
11008c2ecf20Sopenharmony_ci	 * the total FIFO is >= 256 cachelines in size. Either
11018c2ecf20Sopenharmony_ci	 * way, we don't seem to have to worry about this
11028c2ecf20Sopenharmony_ci	 * repartitioning as the maximum watermark value the
11038c2ecf20Sopenharmony_ci	 * register can hold for each plane is lower than the
11048c2ecf20Sopenharmony_ci	 * minimum FIFO size.
11058c2ecf20Sopenharmony_ci	 */
11068c2ecf20Sopenharmony_ci	switch (plane_id) {
11078c2ecf20Sopenharmony_ci	case PLANE_CURSOR:
11088c2ecf20Sopenharmony_ci		return 63;
11098c2ecf20Sopenharmony_ci	case PLANE_PRIMARY:
11108c2ecf20Sopenharmony_ci		return level == G4X_WM_LEVEL_NORMAL ? 127 : 511;
11118c2ecf20Sopenharmony_ci	case PLANE_SPRITE0:
11128c2ecf20Sopenharmony_ci		return level == G4X_WM_LEVEL_NORMAL ? 127 : 0;
11138c2ecf20Sopenharmony_ci	default:
11148c2ecf20Sopenharmony_ci		MISSING_CASE(plane_id);
11158c2ecf20Sopenharmony_ci		return 0;
11168c2ecf20Sopenharmony_ci	}
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_cistatic int g4x_fbc_fifo_size(int level)
11208c2ecf20Sopenharmony_ci{
11218c2ecf20Sopenharmony_ci	switch (level) {
11228c2ecf20Sopenharmony_ci	case G4X_WM_LEVEL_SR:
11238c2ecf20Sopenharmony_ci		return 7;
11248c2ecf20Sopenharmony_ci	case G4X_WM_LEVEL_HPLL:
11258c2ecf20Sopenharmony_ci		return 15;
11268c2ecf20Sopenharmony_ci	default:
11278c2ecf20Sopenharmony_ci		MISSING_CASE(level);
11288c2ecf20Sopenharmony_ci		return 0;
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic u16 g4x_compute_wm(const struct intel_crtc_state *crtc_state,
11338c2ecf20Sopenharmony_ci			  const struct intel_plane_state *plane_state,
11348c2ecf20Sopenharmony_ci			  int level)
11358c2ecf20Sopenharmony_ci{
11368c2ecf20Sopenharmony_ci	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
11378c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
11388c2ecf20Sopenharmony_ci	const struct drm_display_mode *adjusted_mode =
11398c2ecf20Sopenharmony_ci		&crtc_state->hw.adjusted_mode;
11408c2ecf20Sopenharmony_ci	unsigned int latency = dev_priv->wm.pri_latency[level] * 10;
11418c2ecf20Sopenharmony_ci	unsigned int clock, htotal, cpp, width, wm;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	if (latency == 0)
11448c2ecf20Sopenharmony_ci		return USHRT_MAX;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state))
11478c2ecf20Sopenharmony_ci		return 0;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	cpp = plane_state->hw.fb->format->cpp[0];
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	/*
11528c2ecf20Sopenharmony_ci	 * Not 100% sure which way ELK should go here as the
11538c2ecf20Sopenharmony_ci	 * spec only says CL/CTG should assume 32bpp and BW
11548c2ecf20Sopenharmony_ci	 * doesn't need to. But as these things followed the
11558c2ecf20Sopenharmony_ci	 * mobile vs. desktop lines on gen3 as well, let's
11568c2ecf20Sopenharmony_ci	 * assume ELK doesn't need this.
11578c2ecf20Sopenharmony_ci	 *
11588c2ecf20Sopenharmony_ci	 * The spec also fails to list such a restriction for
11598c2ecf20Sopenharmony_ci	 * the HPLL watermark, which seems a little strange.
11608c2ecf20Sopenharmony_ci	 * Let's use 32bpp for the HPLL watermark as well.
11618c2ecf20Sopenharmony_ci	 */
11628c2ecf20Sopenharmony_ci	if (IS_GM45(dev_priv) && plane->id == PLANE_PRIMARY &&
11638c2ecf20Sopenharmony_ci	    level != G4X_WM_LEVEL_NORMAL)
11648c2ecf20Sopenharmony_ci		cpp = max(cpp, 4u);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	clock = adjusted_mode->crtc_clock;
11678c2ecf20Sopenharmony_ci	htotal = adjusted_mode->crtc_htotal;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	width = drm_rect_width(&plane_state->uapi.dst);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	if (plane->id == PLANE_CURSOR) {
11728c2ecf20Sopenharmony_ci		wm = intel_wm_method2(clock, htotal, width, cpp, latency);
11738c2ecf20Sopenharmony_ci	} else if (plane->id == PLANE_PRIMARY &&
11748c2ecf20Sopenharmony_ci		   level == G4X_WM_LEVEL_NORMAL) {
11758c2ecf20Sopenharmony_ci		wm = intel_wm_method1(clock, cpp, latency);
11768c2ecf20Sopenharmony_ci	} else {
11778c2ecf20Sopenharmony_ci		unsigned int small, large;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci		small = intel_wm_method1(clock, cpp, latency);
11808c2ecf20Sopenharmony_ci		large = intel_wm_method2(clock, htotal, width, cpp, latency);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci		wm = min(small, large);
11838c2ecf20Sopenharmony_ci	}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	wm += g4x_tlb_miss_wa(g4x_plane_fifo_size(plane->id, level),
11868c2ecf20Sopenharmony_ci			      width, cpp);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	wm = DIV_ROUND_UP(wm, 64) + 2;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	return min_t(unsigned int, wm, USHRT_MAX);
11918c2ecf20Sopenharmony_ci}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_cistatic bool g4x_raw_plane_wm_set(struct intel_crtc_state *crtc_state,
11948c2ecf20Sopenharmony_ci				 int level, enum plane_id plane_id, u16 value)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
11978c2ecf20Sopenharmony_ci	bool dirty = false;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	for (; level < intel_wm_num_levels(dev_priv); level++) {
12008c2ecf20Sopenharmony_ci		struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci		dirty |= raw->plane[plane_id] != value;
12038c2ecf20Sopenharmony_ci		raw->plane[plane_id] = value;
12048c2ecf20Sopenharmony_ci	}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	return dirty;
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cistatic bool g4x_raw_fbc_wm_set(struct intel_crtc_state *crtc_state,
12108c2ecf20Sopenharmony_ci			       int level, u16 value)
12118c2ecf20Sopenharmony_ci{
12128c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
12138c2ecf20Sopenharmony_ci	bool dirty = false;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	/* NORMAL level doesn't have an FBC watermark */
12168c2ecf20Sopenharmony_ci	level = max(level, G4X_WM_LEVEL_SR);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	for (; level < intel_wm_num_levels(dev_priv); level++) {
12198c2ecf20Sopenharmony_ci		struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci		dirty |= raw->fbc != value;
12228c2ecf20Sopenharmony_ci		raw->fbc = value;
12238c2ecf20Sopenharmony_ci	}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	return dirty;
12268c2ecf20Sopenharmony_ci}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_cistatic u32 ilk_compute_fbc_wm(const struct intel_crtc_state *crtc_state,
12298c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state,
12308c2ecf20Sopenharmony_ci			      u32 pri_val);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_cistatic bool g4x_raw_plane_wm_compute(struct intel_crtc_state *crtc_state,
12338c2ecf20Sopenharmony_ci				     const struct intel_plane_state *plane_state)
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
12368c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
12378c2ecf20Sopenharmony_ci	int num_levels = intel_wm_num_levels(to_i915(plane->base.dev));
12388c2ecf20Sopenharmony_ci	enum plane_id plane_id = plane->id;
12398c2ecf20Sopenharmony_ci	bool dirty = false;
12408c2ecf20Sopenharmony_ci	int level;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state)) {
12438c2ecf20Sopenharmony_ci		dirty |= g4x_raw_plane_wm_set(crtc_state, 0, plane_id, 0);
12448c2ecf20Sopenharmony_ci		if (plane_id == PLANE_PRIMARY)
12458c2ecf20Sopenharmony_ci			dirty |= g4x_raw_fbc_wm_set(crtc_state, 0, 0);
12468c2ecf20Sopenharmony_ci		goto out;
12478c2ecf20Sopenharmony_ci	}
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	for (level = 0; level < num_levels; level++) {
12508c2ecf20Sopenharmony_ci		struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
12518c2ecf20Sopenharmony_ci		int wm, max_wm;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci		wm = g4x_compute_wm(crtc_state, plane_state, level);
12548c2ecf20Sopenharmony_ci		max_wm = g4x_plane_fifo_size(plane_id, level);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci		if (wm > max_wm)
12578c2ecf20Sopenharmony_ci			break;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci		dirty |= raw->plane[plane_id] != wm;
12608c2ecf20Sopenharmony_ci		raw->plane[plane_id] = wm;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci		if (plane_id != PLANE_PRIMARY ||
12638c2ecf20Sopenharmony_ci		    level == G4X_WM_LEVEL_NORMAL)
12648c2ecf20Sopenharmony_ci			continue;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci		wm = ilk_compute_fbc_wm(crtc_state, plane_state,
12678c2ecf20Sopenharmony_ci					raw->plane[plane_id]);
12688c2ecf20Sopenharmony_ci		max_wm = g4x_fbc_fifo_size(level);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		/*
12718c2ecf20Sopenharmony_ci		 * FBC wm is not mandatory as we
12728c2ecf20Sopenharmony_ci		 * can always just disable its use.
12738c2ecf20Sopenharmony_ci		 */
12748c2ecf20Sopenharmony_ci		if (wm > max_wm)
12758c2ecf20Sopenharmony_ci			wm = USHRT_MAX;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci		dirty |= raw->fbc != wm;
12788c2ecf20Sopenharmony_ci		raw->fbc = wm;
12798c2ecf20Sopenharmony_ci	}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	/* mark watermarks as invalid */
12828c2ecf20Sopenharmony_ci	dirty |= g4x_raw_plane_wm_set(crtc_state, level, plane_id, USHRT_MAX);
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	if (plane_id == PLANE_PRIMARY)
12858c2ecf20Sopenharmony_ci		dirty |= g4x_raw_fbc_wm_set(crtc_state, level, USHRT_MAX);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci out:
12888c2ecf20Sopenharmony_ci	if (dirty) {
12898c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
12908c2ecf20Sopenharmony_ci			    "%s watermarks: normal=%d, SR=%d, HPLL=%d\n",
12918c2ecf20Sopenharmony_ci			    plane->base.name,
12928c2ecf20Sopenharmony_ci			    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_NORMAL].plane[plane_id],
12938c2ecf20Sopenharmony_ci			    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_SR].plane[plane_id],
12948c2ecf20Sopenharmony_ci			    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_HPLL].plane[plane_id]);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		if (plane_id == PLANE_PRIMARY)
12978c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
12988c2ecf20Sopenharmony_ci				    "FBC watermarks: SR=%d, HPLL=%d\n",
12998c2ecf20Sopenharmony_ci				    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_SR].fbc,
13008c2ecf20Sopenharmony_ci				    crtc_state->wm.g4x.raw[G4X_WM_LEVEL_HPLL].fbc);
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	return dirty;
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_cistatic bool g4x_raw_plane_wm_is_valid(const struct intel_crtc_state *crtc_state,
13078c2ecf20Sopenharmony_ci				      enum plane_id plane_id, int level)
13088c2ecf20Sopenharmony_ci{
13098c2ecf20Sopenharmony_ci	const struct g4x_pipe_wm *raw = &crtc_state->wm.g4x.raw[level];
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	return raw->plane[plane_id] <= g4x_plane_fifo_size(plane_id, level);
13128c2ecf20Sopenharmony_ci}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_cistatic bool g4x_raw_crtc_wm_is_valid(const struct intel_crtc_state *crtc_state,
13158c2ecf20Sopenharmony_ci				     int level)
13168c2ecf20Sopenharmony_ci{
13178c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	if (level > dev_priv->wm.max_level)
13208c2ecf20Sopenharmony_ci		return false;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	return g4x_raw_plane_wm_is_valid(crtc_state, PLANE_PRIMARY, level) &&
13238c2ecf20Sopenharmony_ci		g4x_raw_plane_wm_is_valid(crtc_state, PLANE_SPRITE0, level) &&
13248c2ecf20Sopenharmony_ci		g4x_raw_plane_wm_is_valid(crtc_state, PLANE_CURSOR, level);
13258c2ecf20Sopenharmony_ci}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci/* mark all levels starting from 'level' as invalid */
13288c2ecf20Sopenharmony_cistatic void g4x_invalidate_wms(struct intel_crtc *crtc,
13298c2ecf20Sopenharmony_ci			       struct g4x_wm_state *wm_state, int level)
13308c2ecf20Sopenharmony_ci{
13318c2ecf20Sopenharmony_ci	if (level <= G4X_WM_LEVEL_NORMAL) {
13328c2ecf20Sopenharmony_ci		enum plane_id plane_id;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id)
13358c2ecf20Sopenharmony_ci			wm_state->wm.plane[plane_id] = USHRT_MAX;
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	if (level <= G4X_WM_LEVEL_SR) {
13398c2ecf20Sopenharmony_ci		wm_state->cxsr = false;
13408c2ecf20Sopenharmony_ci		wm_state->sr.cursor = USHRT_MAX;
13418c2ecf20Sopenharmony_ci		wm_state->sr.plane = USHRT_MAX;
13428c2ecf20Sopenharmony_ci		wm_state->sr.fbc = USHRT_MAX;
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	if (level <= G4X_WM_LEVEL_HPLL) {
13468c2ecf20Sopenharmony_ci		wm_state->hpll_en = false;
13478c2ecf20Sopenharmony_ci		wm_state->hpll.cursor = USHRT_MAX;
13488c2ecf20Sopenharmony_ci		wm_state->hpll.plane = USHRT_MAX;
13498c2ecf20Sopenharmony_ci		wm_state->hpll.fbc = USHRT_MAX;
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_cistatic bool g4x_compute_fbc_en(const struct g4x_wm_state *wm_state,
13548c2ecf20Sopenharmony_ci			       int level)
13558c2ecf20Sopenharmony_ci{
13568c2ecf20Sopenharmony_ci	if (level < G4X_WM_LEVEL_SR)
13578c2ecf20Sopenharmony_ci		return false;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	if (level >= G4X_WM_LEVEL_SR &&
13608c2ecf20Sopenharmony_ci	    wm_state->sr.fbc > g4x_fbc_fifo_size(G4X_WM_LEVEL_SR))
13618c2ecf20Sopenharmony_ci		return false;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	if (level >= G4X_WM_LEVEL_HPLL &&
13648c2ecf20Sopenharmony_ci	    wm_state->hpll.fbc > g4x_fbc_fifo_size(G4X_WM_LEVEL_HPLL))
13658c2ecf20Sopenharmony_ci		return false;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	return true;
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_cistatic int g4x_compute_pipe_wm(struct intel_crtc_state *crtc_state)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
13738c2ecf20Sopenharmony_ci	struct intel_atomic_state *state =
13748c2ecf20Sopenharmony_ci		to_intel_atomic_state(crtc_state->uapi.state);
13758c2ecf20Sopenharmony_ci	struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal;
13768c2ecf20Sopenharmony_ci	int num_active_planes = hweight8(crtc_state->active_planes &
13778c2ecf20Sopenharmony_ci					 ~BIT(PLANE_CURSOR));
13788c2ecf20Sopenharmony_ci	const struct g4x_pipe_wm *raw;
13798c2ecf20Sopenharmony_ci	const struct intel_plane_state *old_plane_state;
13808c2ecf20Sopenharmony_ci	const struct intel_plane_state *new_plane_state;
13818c2ecf20Sopenharmony_ci	struct intel_plane *plane;
13828c2ecf20Sopenharmony_ci	enum plane_id plane_id;
13838c2ecf20Sopenharmony_ci	int i, level;
13848c2ecf20Sopenharmony_ci	unsigned int dirty = 0;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	for_each_oldnew_intel_plane_in_state(state, plane,
13878c2ecf20Sopenharmony_ci					     old_plane_state,
13888c2ecf20Sopenharmony_ci					     new_plane_state, i) {
13898c2ecf20Sopenharmony_ci		if (new_plane_state->hw.crtc != &crtc->base &&
13908c2ecf20Sopenharmony_ci		    old_plane_state->hw.crtc != &crtc->base)
13918c2ecf20Sopenharmony_ci			continue;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci		if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state))
13948c2ecf20Sopenharmony_ci			dirty |= BIT(plane->id);
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	if (!dirty)
13988c2ecf20Sopenharmony_ci		return 0;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	level = G4X_WM_LEVEL_NORMAL;
14018c2ecf20Sopenharmony_ci	if (!g4x_raw_crtc_wm_is_valid(crtc_state, level))
14028c2ecf20Sopenharmony_ci		goto out;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	raw = &crtc_state->wm.g4x.raw[level];
14058c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id)
14068c2ecf20Sopenharmony_ci		wm_state->wm.plane[plane_id] = raw->plane[plane_id];
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	level = G4X_WM_LEVEL_SR;
14098c2ecf20Sopenharmony_ci	if (!g4x_raw_crtc_wm_is_valid(crtc_state, level))
14108c2ecf20Sopenharmony_ci		goto out;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	raw = &crtc_state->wm.g4x.raw[level];
14138c2ecf20Sopenharmony_ci	wm_state->sr.plane = raw->plane[PLANE_PRIMARY];
14148c2ecf20Sopenharmony_ci	wm_state->sr.cursor = raw->plane[PLANE_CURSOR];
14158c2ecf20Sopenharmony_ci	wm_state->sr.fbc = raw->fbc;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	wm_state->cxsr = num_active_planes == BIT(PLANE_PRIMARY);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	level = G4X_WM_LEVEL_HPLL;
14208c2ecf20Sopenharmony_ci	if (!g4x_raw_crtc_wm_is_valid(crtc_state, level))
14218c2ecf20Sopenharmony_ci		goto out;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	raw = &crtc_state->wm.g4x.raw[level];
14248c2ecf20Sopenharmony_ci	wm_state->hpll.plane = raw->plane[PLANE_PRIMARY];
14258c2ecf20Sopenharmony_ci	wm_state->hpll.cursor = raw->plane[PLANE_CURSOR];
14268c2ecf20Sopenharmony_ci	wm_state->hpll.fbc = raw->fbc;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	wm_state->hpll_en = wm_state->cxsr;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	level++;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci out:
14338c2ecf20Sopenharmony_ci	if (level == G4X_WM_LEVEL_NORMAL)
14348c2ecf20Sopenharmony_ci		return -EINVAL;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	/* invalidate the higher levels */
14378c2ecf20Sopenharmony_ci	g4x_invalidate_wms(crtc, wm_state, level);
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	/*
14408c2ecf20Sopenharmony_ci	 * Determine if the FBC watermark(s) can be used. IF
14418c2ecf20Sopenharmony_ci	 * this isn't the case we prefer to disable the FBC
14428c2ecf20Sopenharmony_ci	 * watermark(s) rather than disable the SR/HPLL
14438c2ecf20Sopenharmony_ci	 * level(s) entirely. 'level-1' is the highest valid
14448c2ecf20Sopenharmony_ci	 * level here.
14458c2ecf20Sopenharmony_ci	 */
14468c2ecf20Sopenharmony_ci	wm_state->fbc_en = g4x_compute_fbc_en(wm_state, level - 1);
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	return 0;
14498c2ecf20Sopenharmony_ci}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_cistatic int g4x_compute_intermediate_wm(struct intel_crtc_state *new_crtc_state)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
14548c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
14558c2ecf20Sopenharmony_ci	struct g4x_wm_state *intermediate = &new_crtc_state->wm.g4x.intermediate;
14568c2ecf20Sopenharmony_ci	const struct g4x_wm_state *optimal = &new_crtc_state->wm.g4x.optimal;
14578c2ecf20Sopenharmony_ci	struct intel_atomic_state *intel_state =
14588c2ecf20Sopenharmony_ci		to_intel_atomic_state(new_crtc_state->uapi.state);
14598c2ecf20Sopenharmony_ci	const struct intel_crtc_state *old_crtc_state =
14608c2ecf20Sopenharmony_ci		intel_atomic_get_old_crtc_state(intel_state, crtc);
14618c2ecf20Sopenharmony_ci	const struct g4x_wm_state *active = &old_crtc_state->wm.g4x.optimal;
14628c2ecf20Sopenharmony_ci	enum plane_id plane_id;
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (!new_crtc_state->hw.active || drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) {
14658c2ecf20Sopenharmony_ci		*intermediate = *optimal;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		intermediate->cxsr = false;
14688c2ecf20Sopenharmony_ci		intermediate->hpll_en = false;
14698c2ecf20Sopenharmony_ci		goto out;
14708c2ecf20Sopenharmony_ci	}
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	intermediate->cxsr = optimal->cxsr && active->cxsr &&
14738c2ecf20Sopenharmony_ci		!new_crtc_state->disable_cxsr;
14748c2ecf20Sopenharmony_ci	intermediate->hpll_en = optimal->hpll_en && active->hpll_en &&
14758c2ecf20Sopenharmony_ci		!new_crtc_state->disable_cxsr;
14768c2ecf20Sopenharmony_ci	intermediate->fbc_en = optimal->fbc_en && active->fbc_en;
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
14798c2ecf20Sopenharmony_ci		intermediate->wm.plane[plane_id] =
14808c2ecf20Sopenharmony_ci			max(optimal->wm.plane[plane_id],
14818c2ecf20Sopenharmony_ci			    active->wm.plane[plane_id]);
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, intermediate->wm.plane[plane_id] >
14848c2ecf20Sopenharmony_ci			    g4x_plane_fifo_size(plane_id, G4X_WM_LEVEL_NORMAL));
14858c2ecf20Sopenharmony_ci	}
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	intermediate->sr.plane = max(optimal->sr.plane,
14888c2ecf20Sopenharmony_ci				     active->sr.plane);
14898c2ecf20Sopenharmony_ci	intermediate->sr.cursor = max(optimal->sr.cursor,
14908c2ecf20Sopenharmony_ci				      active->sr.cursor);
14918c2ecf20Sopenharmony_ci	intermediate->sr.fbc = max(optimal->sr.fbc,
14928c2ecf20Sopenharmony_ci				   active->sr.fbc);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	intermediate->hpll.plane = max(optimal->hpll.plane,
14958c2ecf20Sopenharmony_ci				       active->hpll.plane);
14968c2ecf20Sopenharmony_ci	intermediate->hpll.cursor = max(optimal->hpll.cursor,
14978c2ecf20Sopenharmony_ci					active->hpll.cursor);
14988c2ecf20Sopenharmony_ci	intermediate->hpll.fbc = max(optimal->hpll.fbc,
14998c2ecf20Sopenharmony_ci				     active->hpll.fbc);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm,
15028c2ecf20Sopenharmony_ci		    (intermediate->sr.plane >
15038c2ecf20Sopenharmony_ci		     g4x_plane_fifo_size(PLANE_PRIMARY, G4X_WM_LEVEL_SR) ||
15048c2ecf20Sopenharmony_ci		     intermediate->sr.cursor >
15058c2ecf20Sopenharmony_ci		     g4x_plane_fifo_size(PLANE_CURSOR, G4X_WM_LEVEL_SR)) &&
15068c2ecf20Sopenharmony_ci		    intermediate->cxsr);
15078c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm,
15088c2ecf20Sopenharmony_ci		    (intermediate->sr.plane >
15098c2ecf20Sopenharmony_ci		     g4x_plane_fifo_size(PLANE_PRIMARY, G4X_WM_LEVEL_HPLL) ||
15108c2ecf20Sopenharmony_ci		     intermediate->sr.cursor >
15118c2ecf20Sopenharmony_ci		     g4x_plane_fifo_size(PLANE_CURSOR, G4X_WM_LEVEL_HPLL)) &&
15128c2ecf20Sopenharmony_ci		    intermediate->hpll_en);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm,
15158c2ecf20Sopenharmony_ci		    intermediate->sr.fbc > g4x_fbc_fifo_size(1) &&
15168c2ecf20Sopenharmony_ci		    intermediate->fbc_en && intermediate->cxsr);
15178c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm,
15188c2ecf20Sopenharmony_ci		    intermediate->hpll.fbc > g4x_fbc_fifo_size(2) &&
15198c2ecf20Sopenharmony_ci		    intermediate->fbc_en && intermediate->hpll_en);
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ciout:
15228c2ecf20Sopenharmony_ci	/*
15238c2ecf20Sopenharmony_ci	 * If our intermediate WM are identical to the final WM, then we can
15248c2ecf20Sopenharmony_ci	 * omit the post-vblank programming; only update if it's different.
15258c2ecf20Sopenharmony_ci	 */
15268c2ecf20Sopenharmony_ci	if (memcmp(intermediate, optimal, sizeof(*intermediate)) != 0)
15278c2ecf20Sopenharmony_ci		new_crtc_state->wm.need_postvbl_update = true;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	return 0;
15308c2ecf20Sopenharmony_ci}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_cistatic void g4x_merge_wm(struct drm_i915_private *dev_priv,
15338c2ecf20Sopenharmony_ci			 struct g4x_wm_values *wm)
15348c2ecf20Sopenharmony_ci{
15358c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
15368c2ecf20Sopenharmony_ci	int num_active_pipes = 0;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	wm->cxsr = true;
15398c2ecf20Sopenharmony_ci	wm->hpll_en = true;
15408c2ecf20Sopenharmony_ci	wm->fbc_en = true;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
15438c2ecf20Sopenharmony_ci		const struct g4x_wm_state *wm_state = &crtc->wm.active.g4x;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci		if (!crtc->active)
15468c2ecf20Sopenharmony_ci			continue;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci		if (!wm_state->cxsr)
15498c2ecf20Sopenharmony_ci			wm->cxsr = false;
15508c2ecf20Sopenharmony_ci		if (!wm_state->hpll_en)
15518c2ecf20Sopenharmony_ci			wm->hpll_en = false;
15528c2ecf20Sopenharmony_ci		if (!wm_state->fbc_en)
15538c2ecf20Sopenharmony_ci			wm->fbc_en = false;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci		num_active_pipes++;
15568c2ecf20Sopenharmony_ci	}
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	if (num_active_pipes != 1) {
15598c2ecf20Sopenharmony_ci		wm->cxsr = false;
15608c2ecf20Sopenharmony_ci		wm->hpll_en = false;
15618c2ecf20Sopenharmony_ci		wm->fbc_en = false;
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
15658c2ecf20Sopenharmony_ci		const struct g4x_wm_state *wm_state = &crtc->wm.active.g4x;
15668c2ecf20Sopenharmony_ci		enum pipe pipe = crtc->pipe;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci		wm->pipe[pipe] = wm_state->wm;
15698c2ecf20Sopenharmony_ci		if (crtc->active && wm->cxsr)
15708c2ecf20Sopenharmony_ci			wm->sr = wm_state->sr;
15718c2ecf20Sopenharmony_ci		if (crtc->active && wm->hpll_en)
15728c2ecf20Sopenharmony_ci			wm->hpll = wm_state->hpll;
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci}
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_cistatic void g4x_program_watermarks(struct drm_i915_private *dev_priv)
15778c2ecf20Sopenharmony_ci{
15788c2ecf20Sopenharmony_ci	struct g4x_wm_values *old_wm = &dev_priv->wm.g4x;
15798c2ecf20Sopenharmony_ci	struct g4x_wm_values new_wm = {};
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	g4x_merge_wm(dev_priv, &new_wm);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	if (memcmp(old_wm, &new_wm, sizeof(new_wm)) == 0)
15848c2ecf20Sopenharmony_ci		return;
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	if (is_disabling(old_wm->cxsr, new_wm.cxsr, true))
15878c2ecf20Sopenharmony_ci		_intel_set_memory_cxsr(dev_priv, false);
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	g4x_write_wm_values(dev_priv, &new_wm);
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	if (is_enabling(old_wm->cxsr, new_wm.cxsr, true))
15928c2ecf20Sopenharmony_ci		_intel_set_memory_cxsr(dev_priv, true);
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	*old_wm = new_wm;
15958c2ecf20Sopenharmony_ci}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_cistatic void g4x_initial_watermarks(struct intel_atomic_state *state,
15988c2ecf20Sopenharmony_ci				   struct intel_crtc *crtc)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
16018c2ecf20Sopenharmony_ci	const struct intel_crtc_state *crtc_state =
16028c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
16058c2ecf20Sopenharmony_ci	crtc->wm.active.g4x = crtc_state->wm.g4x.intermediate;
16068c2ecf20Sopenharmony_ci	g4x_program_watermarks(dev_priv);
16078c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
16088c2ecf20Sopenharmony_ci}
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_cistatic void g4x_optimize_watermarks(struct intel_atomic_state *state,
16118c2ecf20Sopenharmony_ci				    struct intel_crtc *crtc)
16128c2ecf20Sopenharmony_ci{
16138c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
16148c2ecf20Sopenharmony_ci	const struct intel_crtc_state *crtc_state =
16158c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	if (!crtc_state->wm.need_postvbl_update)
16188c2ecf20Sopenharmony_ci		return;
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
16218c2ecf20Sopenharmony_ci	crtc->wm.active.g4x = crtc_state->wm.g4x.optimal;
16228c2ecf20Sopenharmony_ci	g4x_program_watermarks(dev_priv);
16238c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
16248c2ecf20Sopenharmony_ci}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci/* latency must be in 0.1us units. */
16278c2ecf20Sopenharmony_cistatic unsigned int vlv_wm_method2(unsigned int pixel_rate,
16288c2ecf20Sopenharmony_ci				   unsigned int htotal,
16298c2ecf20Sopenharmony_ci				   unsigned int width,
16308c2ecf20Sopenharmony_ci				   unsigned int cpp,
16318c2ecf20Sopenharmony_ci				   unsigned int latency)
16328c2ecf20Sopenharmony_ci{
16338c2ecf20Sopenharmony_ci	unsigned int ret;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	ret = intel_wm_method2(pixel_rate, htotal,
16368c2ecf20Sopenharmony_ci			       width, cpp, latency);
16378c2ecf20Sopenharmony_ci	ret = DIV_ROUND_UP(ret, 64);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	return ret;
16408c2ecf20Sopenharmony_ci}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_cistatic void vlv_setup_wm_latency(struct drm_i915_private *dev_priv)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	/* all latencies in usec */
16458c2ecf20Sopenharmony_ci	dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM2] = 3;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	dev_priv->wm.max_level = VLV_WM_LEVEL_PM2;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	if (IS_CHERRYVIEW(dev_priv)) {
16508c2ecf20Sopenharmony_ci		dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM5] = 12;
16518c2ecf20Sopenharmony_ci		dev_priv->wm.pri_latency[VLV_WM_LEVEL_DDR_DVFS] = 33;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci		dev_priv->wm.max_level = VLV_WM_LEVEL_DDR_DVFS;
16548c2ecf20Sopenharmony_ci	}
16558c2ecf20Sopenharmony_ci}
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_cistatic u16 vlv_compute_wm_level(const struct intel_crtc_state *crtc_state,
16588c2ecf20Sopenharmony_ci				const struct intel_plane_state *plane_state,
16598c2ecf20Sopenharmony_ci				int level)
16608c2ecf20Sopenharmony_ci{
16618c2ecf20Sopenharmony_ci	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
16628c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
16638c2ecf20Sopenharmony_ci	const struct drm_display_mode *adjusted_mode =
16648c2ecf20Sopenharmony_ci		&crtc_state->hw.adjusted_mode;
16658c2ecf20Sopenharmony_ci	unsigned int clock, htotal, cpp, width, wm;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	if (dev_priv->wm.pri_latency[level] == 0)
16688c2ecf20Sopenharmony_ci		return USHRT_MAX;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state))
16718c2ecf20Sopenharmony_ci		return 0;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	cpp = plane_state->hw.fb->format->cpp[0];
16748c2ecf20Sopenharmony_ci	clock = adjusted_mode->crtc_clock;
16758c2ecf20Sopenharmony_ci	htotal = adjusted_mode->crtc_htotal;
16768c2ecf20Sopenharmony_ci	width = crtc_state->pipe_src_w;
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	if (plane->id == PLANE_CURSOR) {
16798c2ecf20Sopenharmony_ci		/*
16808c2ecf20Sopenharmony_ci		 * FIXME the formula gives values that are
16818c2ecf20Sopenharmony_ci		 * too big for the cursor FIFO, and hence we
16828c2ecf20Sopenharmony_ci		 * would never be able to use cursors. For
16838c2ecf20Sopenharmony_ci		 * now just hardcode the watermark.
16848c2ecf20Sopenharmony_ci		 */
16858c2ecf20Sopenharmony_ci		wm = 63;
16868c2ecf20Sopenharmony_ci	} else {
16878c2ecf20Sopenharmony_ci		wm = vlv_wm_method2(clock, htotal, width, cpp,
16888c2ecf20Sopenharmony_ci				    dev_priv->wm.pri_latency[level] * 10);
16898c2ecf20Sopenharmony_ci	}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	return min_t(unsigned int, wm, USHRT_MAX);
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic bool vlv_need_sprite0_fifo_workaround(unsigned int active_planes)
16958c2ecf20Sopenharmony_ci{
16968c2ecf20Sopenharmony_ci	return (active_planes & (BIT(PLANE_SPRITE0) |
16978c2ecf20Sopenharmony_ci				 BIT(PLANE_SPRITE1))) == BIT(PLANE_SPRITE1);
16988c2ecf20Sopenharmony_ci}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_cistatic int vlv_compute_fifo(struct intel_crtc_state *crtc_state)
17018c2ecf20Sopenharmony_ci{
17028c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
17038c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
17048c2ecf20Sopenharmony_ci	const struct g4x_pipe_wm *raw =
17058c2ecf20Sopenharmony_ci		&crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2];
17068c2ecf20Sopenharmony_ci	struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state;
17078c2ecf20Sopenharmony_ci	unsigned int active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
17088c2ecf20Sopenharmony_ci	int num_active_planes = hweight8(active_planes);
17098c2ecf20Sopenharmony_ci	const int fifo_size = 511;
17108c2ecf20Sopenharmony_ci	int fifo_extra, fifo_left = fifo_size;
17118c2ecf20Sopenharmony_ci	int sprite0_fifo_extra = 0;
17128c2ecf20Sopenharmony_ci	unsigned int total_rate;
17138c2ecf20Sopenharmony_ci	enum plane_id plane_id;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	/*
17168c2ecf20Sopenharmony_ci	 * When enabling sprite0 after sprite1 has already been enabled
17178c2ecf20Sopenharmony_ci	 * we tend to get an underrun unless sprite0 already has some
17188c2ecf20Sopenharmony_ci	 * FIFO space allcoated. Hence we always allocate at least one
17198c2ecf20Sopenharmony_ci	 * cacheline for sprite0 whenever sprite1 is enabled.
17208c2ecf20Sopenharmony_ci	 *
17218c2ecf20Sopenharmony_ci	 * All other plane enable sequences appear immune to this problem.
17228c2ecf20Sopenharmony_ci	 */
17238c2ecf20Sopenharmony_ci	if (vlv_need_sprite0_fifo_workaround(active_planes))
17248c2ecf20Sopenharmony_ci		sprite0_fifo_extra = 1;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	total_rate = raw->plane[PLANE_PRIMARY] +
17278c2ecf20Sopenharmony_ci		raw->plane[PLANE_SPRITE0] +
17288c2ecf20Sopenharmony_ci		raw->plane[PLANE_SPRITE1] +
17298c2ecf20Sopenharmony_ci		sprite0_fifo_extra;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	if (total_rate > fifo_size)
17328c2ecf20Sopenharmony_ci		return -EINVAL;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	if (total_rate == 0)
17358c2ecf20Sopenharmony_ci		total_rate = 1;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
17388c2ecf20Sopenharmony_ci		unsigned int rate;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci		if ((active_planes & BIT(plane_id)) == 0) {
17418c2ecf20Sopenharmony_ci			fifo_state->plane[plane_id] = 0;
17428c2ecf20Sopenharmony_ci			continue;
17438c2ecf20Sopenharmony_ci		}
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci		rate = raw->plane[plane_id];
17468c2ecf20Sopenharmony_ci		fifo_state->plane[plane_id] = fifo_size * rate / total_rate;
17478c2ecf20Sopenharmony_ci		fifo_left -= fifo_state->plane[plane_id];
17488c2ecf20Sopenharmony_ci	}
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	fifo_state->plane[PLANE_SPRITE0] += sprite0_fifo_extra;
17518c2ecf20Sopenharmony_ci	fifo_left -= sprite0_fifo_extra;
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	fifo_state->plane[PLANE_CURSOR] = 63;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	fifo_extra = DIV_ROUND_UP(fifo_left, num_active_planes ?: 1);
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	/* spread the remainder evenly */
17588c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
17598c2ecf20Sopenharmony_ci		int plane_extra;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci		if (fifo_left == 0)
17628c2ecf20Sopenharmony_ci			break;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci		if ((active_planes & BIT(plane_id)) == 0)
17658c2ecf20Sopenharmony_ci			continue;
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci		plane_extra = min(fifo_extra, fifo_left);
17688c2ecf20Sopenharmony_ci		fifo_state->plane[plane_id] += plane_extra;
17698c2ecf20Sopenharmony_ci		fifo_left -= plane_extra;
17708c2ecf20Sopenharmony_ci	}
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, active_planes != 0 && fifo_left != 0);
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	/* give it all to the first plane if none are active */
17758c2ecf20Sopenharmony_ci	if (active_planes == 0) {
17768c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, fifo_left != fifo_size);
17778c2ecf20Sopenharmony_ci		fifo_state->plane[PLANE_PRIMARY] = fifo_left;
17788c2ecf20Sopenharmony_ci	}
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	return 0;
17818c2ecf20Sopenharmony_ci}
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci/* mark all levels starting from 'level' as invalid */
17848c2ecf20Sopenharmony_cistatic void vlv_invalidate_wms(struct intel_crtc *crtc,
17858c2ecf20Sopenharmony_ci			       struct vlv_wm_state *wm_state, int level)
17868c2ecf20Sopenharmony_ci{
17878c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	for (; level < intel_wm_num_levels(dev_priv); level++) {
17908c2ecf20Sopenharmony_ci		enum plane_id plane_id;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id)
17938c2ecf20Sopenharmony_ci			wm_state->wm[level].plane[plane_id] = USHRT_MAX;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci		wm_state->sr[level].cursor = USHRT_MAX;
17968c2ecf20Sopenharmony_ci		wm_state->sr[level].plane = USHRT_MAX;
17978c2ecf20Sopenharmony_ci	}
17988c2ecf20Sopenharmony_ci}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_cistatic u16 vlv_invert_wm_value(u16 wm, u16 fifo_size)
18018c2ecf20Sopenharmony_ci{
18028c2ecf20Sopenharmony_ci	if (wm > fifo_size)
18038c2ecf20Sopenharmony_ci		return USHRT_MAX;
18048c2ecf20Sopenharmony_ci	else
18058c2ecf20Sopenharmony_ci		return fifo_size - wm;
18068c2ecf20Sopenharmony_ci}
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci/*
18098c2ecf20Sopenharmony_ci * Starting from 'level' set all higher
18108c2ecf20Sopenharmony_ci * levels to 'value' in the "raw" watermarks.
18118c2ecf20Sopenharmony_ci */
18128c2ecf20Sopenharmony_cistatic bool vlv_raw_plane_wm_set(struct intel_crtc_state *crtc_state,
18138c2ecf20Sopenharmony_ci				 int level, enum plane_id plane_id, u16 value)
18148c2ecf20Sopenharmony_ci{
18158c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
18168c2ecf20Sopenharmony_ci	int num_levels = intel_wm_num_levels(dev_priv);
18178c2ecf20Sopenharmony_ci	bool dirty = false;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	for (; level < num_levels; level++) {
18208c2ecf20Sopenharmony_ci		struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci		dirty |= raw->plane[plane_id] != value;
18238c2ecf20Sopenharmony_ci		raw->plane[plane_id] = value;
18248c2ecf20Sopenharmony_ci	}
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	return dirty;
18278c2ecf20Sopenharmony_ci}
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_cistatic bool vlv_raw_plane_wm_compute(struct intel_crtc_state *crtc_state,
18308c2ecf20Sopenharmony_ci				     const struct intel_plane_state *plane_state)
18318c2ecf20Sopenharmony_ci{
18328c2ecf20Sopenharmony_ci	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
18338c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
18348c2ecf20Sopenharmony_ci	enum plane_id plane_id = plane->id;
18358c2ecf20Sopenharmony_ci	int num_levels = intel_wm_num_levels(to_i915(plane->base.dev));
18368c2ecf20Sopenharmony_ci	int level;
18378c2ecf20Sopenharmony_ci	bool dirty = false;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state)) {
18408c2ecf20Sopenharmony_ci		dirty |= vlv_raw_plane_wm_set(crtc_state, 0, plane_id, 0);
18418c2ecf20Sopenharmony_ci		goto out;
18428c2ecf20Sopenharmony_ci	}
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	for (level = 0; level < num_levels; level++) {
18458c2ecf20Sopenharmony_ci		struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
18468c2ecf20Sopenharmony_ci		int wm = vlv_compute_wm_level(crtc_state, plane_state, level);
18478c2ecf20Sopenharmony_ci		int max_wm = plane_id == PLANE_CURSOR ? 63 : 511;
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci		if (wm > max_wm)
18508c2ecf20Sopenharmony_ci			break;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci		dirty |= raw->plane[plane_id] != wm;
18538c2ecf20Sopenharmony_ci		raw->plane[plane_id] = wm;
18548c2ecf20Sopenharmony_ci	}
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	/* mark all higher levels as invalid */
18578c2ecf20Sopenharmony_ci	dirty |= vlv_raw_plane_wm_set(crtc_state, level, plane_id, USHRT_MAX);
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ciout:
18608c2ecf20Sopenharmony_ci	if (dirty)
18618c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
18628c2ecf20Sopenharmony_ci			    "%s watermarks: PM2=%d, PM5=%d, DDR DVFS=%d\n",
18638c2ecf20Sopenharmony_ci			    plane->base.name,
18648c2ecf20Sopenharmony_ci			    crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM2].plane[plane_id],
18658c2ecf20Sopenharmony_ci			    crtc_state->wm.vlv.raw[VLV_WM_LEVEL_PM5].plane[plane_id],
18668c2ecf20Sopenharmony_ci			    crtc_state->wm.vlv.raw[VLV_WM_LEVEL_DDR_DVFS].plane[plane_id]);
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	return dirty;
18698c2ecf20Sopenharmony_ci}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_cistatic bool vlv_raw_plane_wm_is_valid(const struct intel_crtc_state *crtc_state,
18728c2ecf20Sopenharmony_ci				      enum plane_id plane_id, int level)
18738c2ecf20Sopenharmony_ci{
18748c2ecf20Sopenharmony_ci	const struct g4x_pipe_wm *raw =
18758c2ecf20Sopenharmony_ci		&crtc_state->wm.vlv.raw[level];
18768c2ecf20Sopenharmony_ci	const struct vlv_fifo_state *fifo_state =
18778c2ecf20Sopenharmony_ci		&crtc_state->wm.vlv.fifo_state;
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	return raw->plane[plane_id] <= fifo_state->plane[plane_id];
18808c2ecf20Sopenharmony_ci}
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_cistatic bool vlv_raw_crtc_wm_is_valid(const struct intel_crtc_state *crtc_state, int level)
18838c2ecf20Sopenharmony_ci{
18848c2ecf20Sopenharmony_ci	return vlv_raw_plane_wm_is_valid(crtc_state, PLANE_PRIMARY, level) &&
18858c2ecf20Sopenharmony_ci		vlv_raw_plane_wm_is_valid(crtc_state, PLANE_SPRITE0, level) &&
18868c2ecf20Sopenharmony_ci		vlv_raw_plane_wm_is_valid(crtc_state, PLANE_SPRITE1, level) &&
18878c2ecf20Sopenharmony_ci		vlv_raw_plane_wm_is_valid(crtc_state, PLANE_CURSOR, level);
18888c2ecf20Sopenharmony_ci}
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_cistatic int vlv_compute_pipe_wm(struct intel_crtc_state *crtc_state)
18918c2ecf20Sopenharmony_ci{
18928c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
18938c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
18948c2ecf20Sopenharmony_ci	struct intel_atomic_state *state =
18958c2ecf20Sopenharmony_ci		to_intel_atomic_state(crtc_state->uapi.state);
18968c2ecf20Sopenharmony_ci	struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
18978c2ecf20Sopenharmony_ci	const struct vlv_fifo_state *fifo_state =
18988c2ecf20Sopenharmony_ci		&crtc_state->wm.vlv.fifo_state;
18998c2ecf20Sopenharmony_ci	int num_active_planes = hweight8(crtc_state->active_planes &
19008c2ecf20Sopenharmony_ci					 ~BIT(PLANE_CURSOR));
19018c2ecf20Sopenharmony_ci	bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->uapi);
19028c2ecf20Sopenharmony_ci	const struct intel_plane_state *old_plane_state;
19038c2ecf20Sopenharmony_ci	const struct intel_plane_state *new_plane_state;
19048c2ecf20Sopenharmony_ci	struct intel_plane *plane;
19058c2ecf20Sopenharmony_ci	enum plane_id plane_id;
19068c2ecf20Sopenharmony_ci	int level, ret, i;
19078c2ecf20Sopenharmony_ci	unsigned int dirty = 0;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	for_each_oldnew_intel_plane_in_state(state, plane,
19108c2ecf20Sopenharmony_ci					     old_plane_state,
19118c2ecf20Sopenharmony_ci					     new_plane_state, i) {
19128c2ecf20Sopenharmony_ci		if (new_plane_state->hw.crtc != &crtc->base &&
19138c2ecf20Sopenharmony_ci		    old_plane_state->hw.crtc != &crtc->base)
19148c2ecf20Sopenharmony_ci			continue;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci		if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state))
19178c2ecf20Sopenharmony_ci			dirty |= BIT(plane->id);
19188c2ecf20Sopenharmony_ci	}
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	/*
19218c2ecf20Sopenharmony_ci	 * DSPARB registers may have been reset due to the
19228c2ecf20Sopenharmony_ci	 * power well being turned off. Make sure we restore
19238c2ecf20Sopenharmony_ci	 * them to a consistent state even if no primary/sprite
19248c2ecf20Sopenharmony_ci	 * planes are initially active.
19258c2ecf20Sopenharmony_ci	 */
19268c2ecf20Sopenharmony_ci	if (needs_modeset)
19278c2ecf20Sopenharmony_ci		crtc_state->fifo_changed = true;
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	if (!dirty)
19308c2ecf20Sopenharmony_ci		return 0;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	/* cursor changes don't warrant a FIFO recompute */
19338c2ecf20Sopenharmony_ci	if (dirty & ~BIT(PLANE_CURSOR)) {
19348c2ecf20Sopenharmony_ci		const struct intel_crtc_state *old_crtc_state =
19358c2ecf20Sopenharmony_ci			intel_atomic_get_old_crtc_state(state, crtc);
19368c2ecf20Sopenharmony_ci		const struct vlv_fifo_state *old_fifo_state =
19378c2ecf20Sopenharmony_ci			&old_crtc_state->wm.vlv.fifo_state;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci		ret = vlv_compute_fifo(crtc_state);
19408c2ecf20Sopenharmony_ci		if (ret)
19418c2ecf20Sopenharmony_ci			return ret;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci		if (needs_modeset ||
19448c2ecf20Sopenharmony_ci		    memcmp(old_fifo_state, fifo_state,
19458c2ecf20Sopenharmony_ci			   sizeof(*fifo_state)) != 0)
19468c2ecf20Sopenharmony_ci			crtc_state->fifo_changed = true;
19478c2ecf20Sopenharmony_ci	}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	/* initially allow all levels */
19508c2ecf20Sopenharmony_ci	wm_state->num_levels = intel_wm_num_levels(dev_priv);
19518c2ecf20Sopenharmony_ci	/*
19528c2ecf20Sopenharmony_ci	 * Note that enabling cxsr with no primary/sprite planes
19538c2ecf20Sopenharmony_ci	 * enabled can wedge the pipe. Hence we only allow cxsr
19548c2ecf20Sopenharmony_ci	 * with exactly one enabled primary/sprite plane.
19558c2ecf20Sopenharmony_ci	 */
19568c2ecf20Sopenharmony_ci	wm_state->cxsr = crtc->pipe != PIPE_C && num_active_planes == 1;
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	for (level = 0; level < wm_state->num_levels; level++) {
19598c2ecf20Sopenharmony_ci		const struct g4x_pipe_wm *raw = &crtc_state->wm.vlv.raw[level];
19608c2ecf20Sopenharmony_ci		const int sr_fifo_size = INTEL_NUM_PIPES(dev_priv) * 512 - 1;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci		if (!vlv_raw_crtc_wm_is_valid(crtc_state, level))
19638c2ecf20Sopenharmony_ci			break;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id) {
19668c2ecf20Sopenharmony_ci			wm_state->wm[level].plane[plane_id] =
19678c2ecf20Sopenharmony_ci				vlv_invert_wm_value(raw->plane[plane_id],
19688c2ecf20Sopenharmony_ci						    fifo_state->plane[plane_id]);
19698c2ecf20Sopenharmony_ci		}
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci		wm_state->sr[level].plane =
19728c2ecf20Sopenharmony_ci			vlv_invert_wm_value(max3(raw->plane[PLANE_PRIMARY],
19738c2ecf20Sopenharmony_ci						 raw->plane[PLANE_SPRITE0],
19748c2ecf20Sopenharmony_ci						 raw->plane[PLANE_SPRITE1]),
19758c2ecf20Sopenharmony_ci					    sr_fifo_size);
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci		wm_state->sr[level].cursor =
19788c2ecf20Sopenharmony_ci			vlv_invert_wm_value(raw->plane[PLANE_CURSOR],
19798c2ecf20Sopenharmony_ci					    63);
19808c2ecf20Sopenharmony_ci	}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	if (level == 0)
19838c2ecf20Sopenharmony_ci		return -EINVAL;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci	/* limit to only levels we can actually handle */
19868c2ecf20Sopenharmony_ci	wm_state->num_levels = level;
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	/* invalidate the higher levels */
19898c2ecf20Sopenharmony_ci	vlv_invalidate_wms(crtc, wm_state, level);
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	return 0;
19928c2ecf20Sopenharmony_ci}
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci#define VLV_FIFO(plane, value) \
19958c2ecf20Sopenharmony_ci	(((value) << DSPARB_ ## plane ## _SHIFT_VLV) & DSPARB_ ## plane ## _MASK_VLV)
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_cistatic void vlv_atomic_update_fifo(struct intel_atomic_state *state,
19988c2ecf20Sopenharmony_ci				   struct intel_crtc *crtc)
19998c2ecf20Sopenharmony_ci{
20008c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
20018c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
20028c2ecf20Sopenharmony_ci	const struct intel_crtc_state *crtc_state =
20038c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
20048c2ecf20Sopenharmony_ci	const struct vlv_fifo_state *fifo_state =
20058c2ecf20Sopenharmony_ci		&crtc_state->wm.vlv.fifo_state;
20068c2ecf20Sopenharmony_ci	int sprite0_start, sprite1_start, fifo_size;
20078c2ecf20Sopenharmony_ci	u32 dsparb, dsparb2, dsparb3;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	if (!crtc_state->fifo_changed)
20108c2ecf20Sopenharmony_ci		return;
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	sprite0_start = fifo_state->plane[PLANE_PRIMARY];
20138c2ecf20Sopenharmony_ci	sprite1_start = fifo_state->plane[PLANE_SPRITE0] + sprite0_start;
20148c2ecf20Sopenharmony_ci	fifo_size = fifo_state->plane[PLANE_SPRITE1] + sprite1_start;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, fifo_state->plane[PLANE_CURSOR] != 63);
20178c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, fifo_size != 511);
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	trace_vlv_fifo_size(crtc, sprite0_start, sprite1_start, fifo_size);
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	/*
20228c2ecf20Sopenharmony_ci	 * uncore.lock serves a double purpose here. It allows us to
20238c2ecf20Sopenharmony_ci	 * use the less expensive I915_{READ,WRITE}_FW() functions, and
20248c2ecf20Sopenharmony_ci	 * it protects the DSPARB registers from getting clobbered by
20258c2ecf20Sopenharmony_ci	 * parallel updates from multiple pipes.
20268c2ecf20Sopenharmony_ci	 *
20278c2ecf20Sopenharmony_ci	 * intel_pipe_update_start() has already disabled interrupts
20288c2ecf20Sopenharmony_ci	 * for us, so a plain spin_lock() is sufficient here.
20298c2ecf20Sopenharmony_ci	 */
20308c2ecf20Sopenharmony_ci	spin_lock(&uncore->lock);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	switch (crtc->pipe) {
20338c2ecf20Sopenharmony_ci	case PIPE_A:
20348c2ecf20Sopenharmony_ci		dsparb = intel_uncore_read_fw(uncore, DSPARB);
20358c2ecf20Sopenharmony_ci		dsparb2 = intel_uncore_read_fw(uncore, DSPARB2);
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_ci		dsparb &= ~(VLV_FIFO(SPRITEA, 0xff) |
20388c2ecf20Sopenharmony_ci			    VLV_FIFO(SPRITEB, 0xff));
20398c2ecf20Sopenharmony_ci		dsparb |= (VLV_FIFO(SPRITEA, sprite0_start) |
20408c2ecf20Sopenharmony_ci			   VLV_FIFO(SPRITEB, sprite1_start));
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci		dsparb2 &= ~(VLV_FIFO(SPRITEA_HI, 0x1) |
20438c2ecf20Sopenharmony_ci			     VLV_FIFO(SPRITEB_HI, 0x1));
20448c2ecf20Sopenharmony_ci		dsparb2 |= (VLV_FIFO(SPRITEA_HI, sprite0_start >> 8) |
20458c2ecf20Sopenharmony_ci			   VLV_FIFO(SPRITEB_HI, sprite1_start >> 8));
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci		intel_uncore_write_fw(uncore, DSPARB, dsparb);
20488c2ecf20Sopenharmony_ci		intel_uncore_write_fw(uncore, DSPARB2, dsparb2);
20498c2ecf20Sopenharmony_ci		break;
20508c2ecf20Sopenharmony_ci	case PIPE_B:
20518c2ecf20Sopenharmony_ci		dsparb = intel_uncore_read_fw(uncore, DSPARB);
20528c2ecf20Sopenharmony_ci		dsparb2 = intel_uncore_read_fw(uncore, DSPARB2);
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci		dsparb &= ~(VLV_FIFO(SPRITEC, 0xff) |
20558c2ecf20Sopenharmony_ci			    VLV_FIFO(SPRITED, 0xff));
20568c2ecf20Sopenharmony_ci		dsparb |= (VLV_FIFO(SPRITEC, sprite0_start) |
20578c2ecf20Sopenharmony_ci			   VLV_FIFO(SPRITED, sprite1_start));
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci		dsparb2 &= ~(VLV_FIFO(SPRITEC_HI, 0xff) |
20608c2ecf20Sopenharmony_ci			     VLV_FIFO(SPRITED_HI, 0xff));
20618c2ecf20Sopenharmony_ci		dsparb2 |= (VLV_FIFO(SPRITEC_HI, sprite0_start >> 8) |
20628c2ecf20Sopenharmony_ci			   VLV_FIFO(SPRITED_HI, sprite1_start >> 8));
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci		intel_uncore_write_fw(uncore, DSPARB, dsparb);
20658c2ecf20Sopenharmony_ci		intel_uncore_write_fw(uncore, DSPARB2, dsparb2);
20668c2ecf20Sopenharmony_ci		break;
20678c2ecf20Sopenharmony_ci	case PIPE_C:
20688c2ecf20Sopenharmony_ci		dsparb3 = intel_uncore_read_fw(uncore, DSPARB3);
20698c2ecf20Sopenharmony_ci		dsparb2 = intel_uncore_read_fw(uncore, DSPARB2);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci		dsparb3 &= ~(VLV_FIFO(SPRITEE, 0xff) |
20728c2ecf20Sopenharmony_ci			     VLV_FIFO(SPRITEF, 0xff));
20738c2ecf20Sopenharmony_ci		dsparb3 |= (VLV_FIFO(SPRITEE, sprite0_start) |
20748c2ecf20Sopenharmony_ci			    VLV_FIFO(SPRITEF, sprite1_start));
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci		dsparb2 &= ~(VLV_FIFO(SPRITEE_HI, 0xff) |
20778c2ecf20Sopenharmony_ci			     VLV_FIFO(SPRITEF_HI, 0xff));
20788c2ecf20Sopenharmony_ci		dsparb2 |= (VLV_FIFO(SPRITEE_HI, sprite0_start >> 8) |
20798c2ecf20Sopenharmony_ci			   VLV_FIFO(SPRITEF_HI, sprite1_start >> 8));
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci		intel_uncore_write_fw(uncore, DSPARB3, dsparb3);
20828c2ecf20Sopenharmony_ci		intel_uncore_write_fw(uncore, DSPARB2, dsparb2);
20838c2ecf20Sopenharmony_ci		break;
20848c2ecf20Sopenharmony_ci	default:
20858c2ecf20Sopenharmony_ci		break;
20868c2ecf20Sopenharmony_ci	}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	intel_uncore_posting_read_fw(uncore, DSPARB);
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	spin_unlock(&uncore->lock);
20918c2ecf20Sopenharmony_ci}
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci#undef VLV_FIFO
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_cistatic int vlv_compute_intermediate_wm(struct intel_crtc_state *new_crtc_state)
20968c2ecf20Sopenharmony_ci{
20978c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
20988c2ecf20Sopenharmony_ci	struct vlv_wm_state *intermediate = &new_crtc_state->wm.vlv.intermediate;
20998c2ecf20Sopenharmony_ci	const struct vlv_wm_state *optimal = &new_crtc_state->wm.vlv.optimal;
21008c2ecf20Sopenharmony_ci	struct intel_atomic_state *intel_state =
21018c2ecf20Sopenharmony_ci		to_intel_atomic_state(new_crtc_state->uapi.state);
21028c2ecf20Sopenharmony_ci	const struct intel_crtc_state *old_crtc_state =
21038c2ecf20Sopenharmony_ci		intel_atomic_get_old_crtc_state(intel_state, crtc);
21048c2ecf20Sopenharmony_ci	const struct vlv_wm_state *active = &old_crtc_state->wm.vlv.optimal;
21058c2ecf20Sopenharmony_ci	int level;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	if (!new_crtc_state->hw.active || drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi)) {
21088c2ecf20Sopenharmony_ci		*intermediate = *optimal;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci		intermediate->cxsr = false;
21118c2ecf20Sopenharmony_ci		goto out;
21128c2ecf20Sopenharmony_ci	}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	intermediate->num_levels = min(optimal->num_levels, active->num_levels);
21158c2ecf20Sopenharmony_ci	intermediate->cxsr = optimal->cxsr && active->cxsr &&
21168c2ecf20Sopenharmony_ci		!new_crtc_state->disable_cxsr;
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	for (level = 0; level < intermediate->num_levels; level++) {
21198c2ecf20Sopenharmony_ci		enum plane_id plane_id;
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id) {
21228c2ecf20Sopenharmony_ci			intermediate->wm[level].plane[plane_id] =
21238c2ecf20Sopenharmony_ci				min(optimal->wm[level].plane[plane_id],
21248c2ecf20Sopenharmony_ci				    active->wm[level].plane[plane_id]);
21258c2ecf20Sopenharmony_ci		}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci		intermediate->sr[level].plane = min(optimal->sr[level].plane,
21288c2ecf20Sopenharmony_ci						    active->sr[level].plane);
21298c2ecf20Sopenharmony_ci		intermediate->sr[level].cursor = min(optimal->sr[level].cursor,
21308c2ecf20Sopenharmony_ci						     active->sr[level].cursor);
21318c2ecf20Sopenharmony_ci	}
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	vlv_invalidate_wms(crtc, intermediate, level);
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ciout:
21368c2ecf20Sopenharmony_ci	/*
21378c2ecf20Sopenharmony_ci	 * If our intermediate WM are identical to the final WM, then we can
21388c2ecf20Sopenharmony_ci	 * omit the post-vblank programming; only update if it's different.
21398c2ecf20Sopenharmony_ci	 */
21408c2ecf20Sopenharmony_ci	if (memcmp(intermediate, optimal, sizeof(*intermediate)) != 0)
21418c2ecf20Sopenharmony_ci		new_crtc_state->wm.need_postvbl_update = true;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci	return 0;
21448c2ecf20Sopenharmony_ci}
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_cistatic void vlv_merge_wm(struct drm_i915_private *dev_priv,
21478c2ecf20Sopenharmony_ci			 struct vlv_wm_values *wm)
21488c2ecf20Sopenharmony_ci{
21498c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
21508c2ecf20Sopenharmony_ci	int num_active_pipes = 0;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	wm->level = dev_priv->wm.max_level;
21538c2ecf20Sopenharmony_ci	wm->cxsr = true;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
21568c2ecf20Sopenharmony_ci		const struct vlv_wm_state *wm_state = &crtc->wm.active.vlv;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci		if (!crtc->active)
21598c2ecf20Sopenharmony_ci			continue;
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci		if (!wm_state->cxsr)
21628c2ecf20Sopenharmony_ci			wm->cxsr = false;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci		num_active_pipes++;
21658c2ecf20Sopenharmony_ci		wm->level = min_t(int, wm->level, wm_state->num_levels - 1);
21668c2ecf20Sopenharmony_ci	}
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	if (num_active_pipes != 1)
21698c2ecf20Sopenharmony_ci		wm->cxsr = false;
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	if (num_active_pipes > 1)
21728c2ecf20Sopenharmony_ci		wm->level = VLV_WM_LEVEL_PM2;
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
21758c2ecf20Sopenharmony_ci		const struct vlv_wm_state *wm_state = &crtc->wm.active.vlv;
21768c2ecf20Sopenharmony_ci		enum pipe pipe = crtc->pipe;
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci		wm->pipe[pipe] = wm_state->wm[wm->level];
21798c2ecf20Sopenharmony_ci		if (crtc->active && wm->cxsr)
21808c2ecf20Sopenharmony_ci			wm->sr = wm_state->sr[wm->level];
21818c2ecf20Sopenharmony_ci
21828c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_PRIMARY] = DDL_PRECISION_HIGH | 2;
21838c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_SPRITE0] = DDL_PRECISION_HIGH | 2;
21848c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_SPRITE1] = DDL_PRECISION_HIGH | 2;
21858c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_CURSOR] = DDL_PRECISION_HIGH | 2;
21868c2ecf20Sopenharmony_ci	}
21878c2ecf20Sopenharmony_ci}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_cistatic void vlv_program_watermarks(struct drm_i915_private *dev_priv)
21908c2ecf20Sopenharmony_ci{
21918c2ecf20Sopenharmony_ci	struct vlv_wm_values *old_wm = &dev_priv->wm.vlv;
21928c2ecf20Sopenharmony_ci	struct vlv_wm_values new_wm = {};
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	vlv_merge_wm(dev_priv, &new_wm);
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	if (memcmp(old_wm, &new_wm, sizeof(new_wm)) == 0)
21978c2ecf20Sopenharmony_ci		return;
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	if (is_disabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_DDR_DVFS))
22008c2ecf20Sopenharmony_ci		chv_set_memory_dvfs(dev_priv, false);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	if (is_disabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_PM5))
22038c2ecf20Sopenharmony_ci		chv_set_memory_pm5(dev_priv, false);
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	if (is_disabling(old_wm->cxsr, new_wm.cxsr, true))
22068c2ecf20Sopenharmony_ci		_intel_set_memory_cxsr(dev_priv, false);
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	vlv_write_wm_values(dev_priv, &new_wm);
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	if (is_enabling(old_wm->cxsr, new_wm.cxsr, true))
22118c2ecf20Sopenharmony_ci		_intel_set_memory_cxsr(dev_priv, true);
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	if (is_enabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_PM5))
22148c2ecf20Sopenharmony_ci		chv_set_memory_pm5(dev_priv, true);
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	if (is_enabling(old_wm->level, new_wm.level, VLV_WM_LEVEL_DDR_DVFS))
22178c2ecf20Sopenharmony_ci		chv_set_memory_dvfs(dev_priv, true);
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	*old_wm = new_wm;
22208c2ecf20Sopenharmony_ci}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_cistatic void vlv_initial_watermarks(struct intel_atomic_state *state,
22238c2ecf20Sopenharmony_ci				   struct intel_crtc *crtc)
22248c2ecf20Sopenharmony_ci{
22258c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
22268c2ecf20Sopenharmony_ci	const struct intel_crtc_state *crtc_state =
22278c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
22308c2ecf20Sopenharmony_ci	crtc->wm.active.vlv = crtc_state->wm.vlv.intermediate;
22318c2ecf20Sopenharmony_ci	vlv_program_watermarks(dev_priv);
22328c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
22338c2ecf20Sopenharmony_ci}
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_cistatic void vlv_optimize_watermarks(struct intel_atomic_state *state,
22368c2ecf20Sopenharmony_ci				    struct intel_crtc *crtc)
22378c2ecf20Sopenharmony_ci{
22388c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
22398c2ecf20Sopenharmony_ci	const struct intel_crtc_state *crtc_state =
22408c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	if (!crtc_state->wm.need_postvbl_update)
22438c2ecf20Sopenharmony_ci		return;
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
22468c2ecf20Sopenharmony_ci	crtc->wm.active.vlv = crtc_state->wm.vlv.optimal;
22478c2ecf20Sopenharmony_ci	vlv_program_watermarks(dev_priv);
22488c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_cistatic void i965_update_wm(struct intel_crtc *unused_crtc)
22528c2ecf20Sopenharmony_ci{
22538c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
22548c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
22558c2ecf20Sopenharmony_ci	int srwm = 1;
22568c2ecf20Sopenharmony_ci	int cursor_sr = 16;
22578c2ecf20Sopenharmony_ci	bool cxsr_enabled;
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	/* Calc sr entries for one plane configs */
22608c2ecf20Sopenharmony_ci	crtc = single_enabled_crtc(dev_priv);
22618c2ecf20Sopenharmony_ci	if (crtc) {
22628c2ecf20Sopenharmony_ci		/* self-refresh has much higher latency */
22638c2ecf20Sopenharmony_ci		static const int sr_latency_ns = 12000;
22648c2ecf20Sopenharmony_ci		const struct drm_display_mode *adjusted_mode =
22658c2ecf20Sopenharmony_ci			&crtc->config->hw.adjusted_mode;
22668c2ecf20Sopenharmony_ci		const struct drm_framebuffer *fb =
22678c2ecf20Sopenharmony_ci			crtc->base.primary->state->fb;
22688c2ecf20Sopenharmony_ci		int clock = adjusted_mode->crtc_clock;
22698c2ecf20Sopenharmony_ci		int htotal = adjusted_mode->crtc_htotal;
22708c2ecf20Sopenharmony_ci		int hdisplay = crtc->config->pipe_src_w;
22718c2ecf20Sopenharmony_ci		int cpp = fb->format->cpp[0];
22728c2ecf20Sopenharmony_ci		int entries;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci		entries = intel_wm_method2(clock, htotal,
22758c2ecf20Sopenharmony_ci					   hdisplay, cpp, sr_latency_ns / 100);
22768c2ecf20Sopenharmony_ci		entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
22778c2ecf20Sopenharmony_ci		srwm = I965_FIFO_SIZE - entries;
22788c2ecf20Sopenharmony_ci		if (srwm < 0)
22798c2ecf20Sopenharmony_ci			srwm = 1;
22808c2ecf20Sopenharmony_ci		srwm &= 0x1ff;
22818c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
22828c2ecf20Sopenharmony_ci			    "self-refresh entries: %d, wm: %d\n",
22838c2ecf20Sopenharmony_ci			    entries, srwm);
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci		entries = intel_wm_method2(clock, htotal,
22868c2ecf20Sopenharmony_ci					   crtc->base.cursor->state->crtc_w, 4,
22878c2ecf20Sopenharmony_ci					   sr_latency_ns / 100);
22888c2ecf20Sopenharmony_ci		entries = DIV_ROUND_UP(entries,
22898c2ecf20Sopenharmony_ci				       i965_cursor_wm_info.cacheline_size) +
22908c2ecf20Sopenharmony_ci			i965_cursor_wm_info.guard_size;
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci		cursor_sr = i965_cursor_wm_info.fifo_size - entries;
22938c2ecf20Sopenharmony_ci		if (cursor_sr > i965_cursor_wm_info.max_wm)
22948c2ecf20Sopenharmony_ci			cursor_sr = i965_cursor_wm_info.max_wm;
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
22978c2ecf20Sopenharmony_ci			    "self-refresh watermark: display plane %d "
22988c2ecf20Sopenharmony_ci			    "cursor %d\n", srwm, cursor_sr);
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci		cxsr_enabled = true;
23018c2ecf20Sopenharmony_ci	} else {
23028c2ecf20Sopenharmony_ci		cxsr_enabled = false;
23038c2ecf20Sopenharmony_ci		/* Turn off self refresh if both pipes are enabled */
23048c2ecf20Sopenharmony_ci		intel_set_memory_cxsr(dev_priv, false);
23058c2ecf20Sopenharmony_ci	}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
23088c2ecf20Sopenharmony_ci		    "Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
23098c2ecf20Sopenharmony_ci		    srwm);
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	/* 965 has limitations... */
23128c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW1, FW_WM(srwm, SR) |
23138c2ecf20Sopenharmony_ci		   FW_WM(8, CURSORB) |
23148c2ecf20Sopenharmony_ci		   FW_WM(8, PLANEB) |
23158c2ecf20Sopenharmony_ci		   FW_WM(8, PLANEA));
23168c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW2, FW_WM(8, CURSORA) |
23178c2ecf20Sopenharmony_ci		   FW_WM(8, PLANEC_OLD));
23188c2ecf20Sopenharmony_ci	/* update cursor SR watermark */
23198c2ecf20Sopenharmony_ci	I915_WRITE(DSPFW3, FW_WM(cursor_sr, CURSOR_SR));
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	if (cxsr_enabled)
23228c2ecf20Sopenharmony_ci		intel_set_memory_cxsr(dev_priv, true);
23238c2ecf20Sopenharmony_ci}
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci#undef FW_WM
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_cistatic void i9xx_update_wm(struct intel_crtc *unused_crtc)
23288c2ecf20Sopenharmony_ci{
23298c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
23308c2ecf20Sopenharmony_ci	const struct intel_watermark_params *wm_info;
23318c2ecf20Sopenharmony_ci	u32 fwater_lo;
23328c2ecf20Sopenharmony_ci	u32 fwater_hi;
23338c2ecf20Sopenharmony_ci	int cwm, srwm = 1;
23348c2ecf20Sopenharmony_ci	int fifo_size;
23358c2ecf20Sopenharmony_ci	int planea_wm, planeb_wm;
23368c2ecf20Sopenharmony_ci	struct intel_crtc *crtc, *enabled = NULL;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	if (IS_I945GM(dev_priv))
23398c2ecf20Sopenharmony_ci		wm_info = &i945_wm_info;
23408c2ecf20Sopenharmony_ci	else if (!IS_GEN(dev_priv, 2))
23418c2ecf20Sopenharmony_ci		wm_info = &i915_wm_info;
23428c2ecf20Sopenharmony_ci	else
23438c2ecf20Sopenharmony_ci		wm_info = &i830_a_wm_info;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_A);
23468c2ecf20Sopenharmony_ci	crtc = intel_get_crtc_for_plane(dev_priv, PLANE_A);
23478c2ecf20Sopenharmony_ci	if (intel_crtc_active(crtc)) {
23488c2ecf20Sopenharmony_ci		const struct drm_display_mode *adjusted_mode =
23498c2ecf20Sopenharmony_ci			&crtc->config->hw.adjusted_mode;
23508c2ecf20Sopenharmony_ci		const struct drm_framebuffer *fb =
23518c2ecf20Sopenharmony_ci			crtc->base.primary->state->fb;
23528c2ecf20Sopenharmony_ci		int cpp;
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci		if (IS_GEN(dev_priv, 2))
23558c2ecf20Sopenharmony_ci			cpp = 4;
23568c2ecf20Sopenharmony_ci		else
23578c2ecf20Sopenharmony_ci			cpp = fb->format->cpp[0];
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci		planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
23608c2ecf20Sopenharmony_ci					       wm_info, fifo_size, cpp,
23618c2ecf20Sopenharmony_ci					       pessimal_latency_ns);
23628c2ecf20Sopenharmony_ci		enabled = crtc;
23638c2ecf20Sopenharmony_ci	} else {
23648c2ecf20Sopenharmony_ci		planea_wm = fifo_size - wm_info->guard_size;
23658c2ecf20Sopenharmony_ci		if (planea_wm > (long)wm_info->max_wm)
23668c2ecf20Sopenharmony_ci			planea_wm = wm_info->max_wm;
23678c2ecf20Sopenharmony_ci	}
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 2))
23708c2ecf20Sopenharmony_ci		wm_info = &i830_bc_wm_info;
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	fifo_size = dev_priv->display.get_fifo_size(dev_priv, PLANE_B);
23738c2ecf20Sopenharmony_ci	crtc = intel_get_crtc_for_plane(dev_priv, PLANE_B);
23748c2ecf20Sopenharmony_ci	if (intel_crtc_active(crtc)) {
23758c2ecf20Sopenharmony_ci		const struct drm_display_mode *adjusted_mode =
23768c2ecf20Sopenharmony_ci			&crtc->config->hw.adjusted_mode;
23778c2ecf20Sopenharmony_ci		const struct drm_framebuffer *fb =
23788c2ecf20Sopenharmony_ci			crtc->base.primary->state->fb;
23798c2ecf20Sopenharmony_ci		int cpp;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci		if (IS_GEN(dev_priv, 2))
23828c2ecf20Sopenharmony_ci			cpp = 4;
23838c2ecf20Sopenharmony_ci		else
23848c2ecf20Sopenharmony_ci			cpp = fb->format->cpp[0];
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci		planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
23878c2ecf20Sopenharmony_ci					       wm_info, fifo_size, cpp,
23888c2ecf20Sopenharmony_ci					       pessimal_latency_ns);
23898c2ecf20Sopenharmony_ci		if (enabled == NULL)
23908c2ecf20Sopenharmony_ci			enabled = crtc;
23918c2ecf20Sopenharmony_ci		else
23928c2ecf20Sopenharmony_ci			enabled = NULL;
23938c2ecf20Sopenharmony_ci	} else {
23948c2ecf20Sopenharmony_ci		planeb_wm = fifo_size - wm_info->guard_size;
23958c2ecf20Sopenharmony_ci		if (planeb_wm > (long)wm_info->max_wm)
23968c2ecf20Sopenharmony_ci			planeb_wm = wm_info->max_wm;
23978c2ecf20Sopenharmony_ci	}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
24008c2ecf20Sopenharmony_ci		    "FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	if (IS_I915GM(dev_priv) && enabled) {
24038c2ecf20Sopenharmony_ci		struct drm_i915_gem_object *obj;
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci		obj = intel_fb_obj(enabled->base.primary->state->fb);
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci		/* self-refresh seems busted with untiled */
24088c2ecf20Sopenharmony_ci		if (!i915_gem_object_is_tiled(obj))
24098c2ecf20Sopenharmony_ci			enabled = NULL;
24108c2ecf20Sopenharmony_ci	}
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	/*
24138c2ecf20Sopenharmony_ci	 * Overlay gets an aggressive default since video jitter is bad.
24148c2ecf20Sopenharmony_ci	 */
24158c2ecf20Sopenharmony_ci	cwm = 2;
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	/* Play safe and disable self-refresh before adjusting watermarks. */
24188c2ecf20Sopenharmony_ci	intel_set_memory_cxsr(dev_priv, false);
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	/* Calc sr entries for one plane configs */
24218c2ecf20Sopenharmony_ci	if (HAS_FW_BLC(dev_priv) && enabled) {
24228c2ecf20Sopenharmony_ci		/* self-refresh has much higher latency */
24238c2ecf20Sopenharmony_ci		static const int sr_latency_ns = 6000;
24248c2ecf20Sopenharmony_ci		const struct drm_display_mode *adjusted_mode =
24258c2ecf20Sopenharmony_ci			&enabled->config->hw.adjusted_mode;
24268c2ecf20Sopenharmony_ci		const struct drm_framebuffer *fb =
24278c2ecf20Sopenharmony_ci			enabled->base.primary->state->fb;
24288c2ecf20Sopenharmony_ci		int clock = adjusted_mode->crtc_clock;
24298c2ecf20Sopenharmony_ci		int htotal = adjusted_mode->crtc_htotal;
24308c2ecf20Sopenharmony_ci		int hdisplay = enabled->config->pipe_src_w;
24318c2ecf20Sopenharmony_ci		int cpp;
24328c2ecf20Sopenharmony_ci		int entries;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci		if (IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
24358c2ecf20Sopenharmony_ci			cpp = 4;
24368c2ecf20Sopenharmony_ci		else
24378c2ecf20Sopenharmony_ci			cpp = fb->format->cpp[0];
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci		entries = intel_wm_method2(clock, htotal, hdisplay, cpp,
24408c2ecf20Sopenharmony_ci					   sr_latency_ns / 100);
24418c2ecf20Sopenharmony_ci		entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
24428c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
24438c2ecf20Sopenharmony_ci			    "self-refresh entries: %d\n", entries);
24448c2ecf20Sopenharmony_ci		srwm = wm_info->fifo_size - entries;
24458c2ecf20Sopenharmony_ci		if (srwm < 0)
24468c2ecf20Sopenharmony_ci			srwm = 1;
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci		if (IS_I945G(dev_priv) || IS_I945GM(dev_priv))
24498c2ecf20Sopenharmony_ci			I915_WRITE(FW_BLC_SELF,
24508c2ecf20Sopenharmony_ci				   FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
24518c2ecf20Sopenharmony_ci		else
24528c2ecf20Sopenharmony_ci			I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
24538c2ecf20Sopenharmony_ci	}
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
24568c2ecf20Sopenharmony_ci		    "Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
24578c2ecf20Sopenharmony_ci		     planea_wm, planeb_wm, cwm, srwm);
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
24608c2ecf20Sopenharmony_ci	fwater_hi = (cwm & 0x1f);
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	/* Set request length to 8 cachelines per fetch */
24638c2ecf20Sopenharmony_ci	fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
24648c2ecf20Sopenharmony_ci	fwater_hi = fwater_hi | (1 << 8);
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	I915_WRITE(FW_BLC, fwater_lo);
24678c2ecf20Sopenharmony_ci	I915_WRITE(FW_BLC2, fwater_hi);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	if (enabled)
24708c2ecf20Sopenharmony_ci		intel_set_memory_cxsr(dev_priv, true);
24718c2ecf20Sopenharmony_ci}
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_cistatic void i845_update_wm(struct intel_crtc *unused_crtc)
24748c2ecf20Sopenharmony_ci{
24758c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
24768c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
24778c2ecf20Sopenharmony_ci	const struct drm_display_mode *adjusted_mode;
24788c2ecf20Sopenharmony_ci	u32 fwater_lo;
24798c2ecf20Sopenharmony_ci	int planea_wm;
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci	crtc = single_enabled_crtc(dev_priv);
24828c2ecf20Sopenharmony_ci	if (crtc == NULL)
24838c2ecf20Sopenharmony_ci		return;
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	adjusted_mode = &crtc->config->hw.adjusted_mode;
24868c2ecf20Sopenharmony_ci	planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
24878c2ecf20Sopenharmony_ci				       &i845_wm_info,
24888c2ecf20Sopenharmony_ci				       dev_priv->display.get_fifo_size(dev_priv, PLANE_A),
24898c2ecf20Sopenharmony_ci				       4, pessimal_latency_ns);
24908c2ecf20Sopenharmony_ci	fwater_lo = I915_READ(FW_BLC) & ~0xfff;
24918c2ecf20Sopenharmony_ci	fwater_lo |= (3<<8) | planea_wm;
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
24948c2ecf20Sopenharmony_ci		    "Setting FIFO watermarks - A: %d\n", planea_wm);
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	I915_WRITE(FW_BLC, fwater_lo);
24978c2ecf20Sopenharmony_ci}
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci/* latency must be in 0.1us units. */
25008c2ecf20Sopenharmony_cistatic unsigned int ilk_wm_method1(unsigned int pixel_rate,
25018c2ecf20Sopenharmony_ci				   unsigned int cpp,
25028c2ecf20Sopenharmony_ci				   unsigned int latency)
25038c2ecf20Sopenharmony_ci{
25048c2ecf20Sopenharmony_ci	unsigned int ret;
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci	ret = intel_wm_method1(pixel_rate, cpp, latency);
25078c2ecf20Sopenharmony_ci	ret = DIV_ROUND_UP(ret, 64) + 2;
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci	return ret;
25108c2ecf20Sopenharmony_ci}
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci/* latency must be in 0.1us units. */
25138c2ecf20Sopenharmony_cistatic unsigned int ilk_wm_method2(unsigned int pixel_rate,
25148c2ecf20Sopenharmony_ci				   unsigned int htotal,
25158c2ecf20Sopenharmony_ci				   unsigned int width,
25168c2ecf20Sopenharmony_ci				   unsigned int cpp,
25178c2ecf20Sopenharmony_ci				   unsigned int latency)
25188c2ecf20Sopenharmony_ci{
25198c2ecf20Sopenharmony_ci	unsigned int ret;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	ret = intel_wm_method2(pixel_rate, htotal,
25228c2ecf20Sopenharmony_ci			       width, cpp, latency);
25238c2ecf20Sopenharmony_ci	ret = DIV_ROUND_UP(ret, 64) + 2;
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci	return ret;
25268c2ecf20Sopenharmony_ci}
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_cistatic u32 ilk_wm_fbc(u32 pri_val, u32 horiz_pixels, u8 cpp)
25298c2ecf20Sopenharmony_ci{
25308c2ecf20Sopenharmony_ci	/*
25318c2ecf20Sopenharmony_ci	 * Neither of these should be possible since this function shouldn't be
25328c2ecf20Sopenharmony_ci	 * called if the CRTC is off or the plane is invisible.  But let's be
25338c2ecf20Sopenharmony_ci	 * extra paranoid to avoid a potential divide-by-zero if we screw up
25348c2ecf20Sopenharmony_ci	 * elsewhere in the driver.
25358c2ecf20Sopenharmony_ci	 */
25368c2ecf20Sopenharmony_ci	if (WARN_ON(!cpp))
25378c2ecf20Sopenharmony_ci		return 0;
25388c2ecf20Sopenharmony_ci	if (WARN_ON(!horiz_pixels))
25398c2ecf20Sopenharmony_ci		return 0;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(pri_val * 64, horiz_pixels * cpp) + 2;
25428c2ecf20Sopenharmony_ci}
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_cistruct ilk_wm_maximums {
25458c2ecf20Sopenharmony_ci	u16 pri;
25468c2ecf20Sopenharmony_ci	u16 spr;
25478c2ecf20Sopenharmony_ci	u16 cur;
25488c2ecf20Sopenharmony_ci	u16 fbc;
25498c2ecf20Sopenharmony_ci};
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci/*
25528c2ecf20Sopenharmony_ci * For both WM_PIPE and WM_LP.
25538c2ecf20Sopenharmony_ci * mem_value must be in 0.1us units.
25548c2ecf20Sopenharmony_ci */
25558c2ecf20Sopenharmony_cistatic u32 ilk_compute_pri_wm(const struct intel_crtc_state *crtc_state,
25568c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state,
25578c2ecf20Sopenharmony_ci			      u32 mem_value, bool is_lp)
25588c2ecf20Sopenharmony_ci{
25598c2ecf20Sopenharmony_ci	u32 method1, method2;
25608c2ecf20Sopenharmony_ci	int cpp;
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	if (mem_value == 0)
25638c2ecf20Sopenharmony_ci		return U32_MAX;
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state))
25668c2ecf20Sopenharmony_ci		return 0;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	cpp = plane_state->hw.fb->format->cpp[0];
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ci	method1 = ilk_wm_method1(crtc_state->pixel_rate, cpp, mem_value);
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci	if (!is_lp)
25738c2ecf20Sopenharmony_ci		return method1;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	method2 = ilk_wm_method2(crtc_state->pixel_rate,
25768c2ecf20Sopenharmony_ci				 crtc_state->hw.adjusted_mode.crtc_htotal,
25778c2ecf20Sopenharmony_ci				 drm_rect_width(&plane_state->uapi.dst),
25788c2ecf20Sopenharmony_ci				 cpp, mem_value);
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	return min(method1, method2);
25818c2ecf20Sopenharmony_ci}
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci/*
25848c2ecf20Sopenharmony_ci * For both WM_PIPE and WM_LP.
25858c2ecf20Sopenharmony_ci * mem_value must be in 0.1us units.
25868c2ecf20Sopenharmony_ci */
25878c2ecf20Sopenharmony_cistatic u32 ilk_compute_spr_wm(const struct intel_crtc_state *crtc_state,
25888c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state,
25898c2ecf20Sopenharmony_ci			      u32 mem_value)
25908c2ecf20Sopenharmony_ci{
25918c2ecf20Sopenharmony_ci	u32 method1, method2;
25928c2ecf20Sopenharmony_ci	int cpp;
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	if (mem_value == 0)
25958c2ecf20Sopenharmony_ci		return U32_MAX;
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state))
25988c2ecf20Sopenharmony_ci		return 0;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	cpp = plane_state->hw.fb->format->cpp[0];
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci	method1 = ilk_wm_method1(crtc_state->pixel_rate, cpp, mem_value);
26038c2ecf20Sopenharmony_ci	method2 = ilk_wm_method2(crtc_state->pixel_rate,
26048c2ecf20Sopenharmony_ci				 crtc_state->hw.adjusted_mode.crtc_htotal,
26058c2ecf20Sopenharmony_ci				 drm_rect_width(&plane_state->uapi.dst),
26068c2ecf20Sopenharmony_ci				 cpp, mem_value);
26078c2ecf20Sopenharmony_ci	return min(method1, method2);
26088c2ecf20Sopenharmony_ci}
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci/*
26118c2ecf20Sopenharmony_ci * For both WM_PIPE and WM_LP.
26128c2ecf20Sopenharmony_ci * mem_value must be in 0.1us units.
26138c2ecf20Sopenharmony_ci */
26148c2ecf20Sopenharmony_cistatic u32 ilk_compute_cur_wm(const struct intel_crtc_state *crtc_state,
26158c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state,
26168c2ecf20Sopenharmony_ci			      u32 mem_value)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	int cpp;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	if (mem_value == 0)
26218c2ecf20Sopenharmony_ci		return U32_MAX;
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state))
26248c2ecf20Sopenharmony_ci		return 0;
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	cpp = plane_state->hw.fb->format->cpp[0];
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	return ilk_wm_method2(crtc_state->pixel_rate,
26298c2ecf20Sopenharmony_ci			      crtc_state->hw.adjusted_mode.crtc_htotal,
26308c2ecf20Sopenharmony_ci			      drm_rect_width(&plane_state->uapi.dst),
26318c2ecf20Sopenharmony_ci			      cpp, mem_value);
26328c2ecf20Sopenharmony_ci}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci/* Only for WM_LP. */
26358c2ecf20Sopenharmony_cistatic u32 ilk_compute_fbc_wm(const struct intel_crtc_state *crtc_state,
26368c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state,
26378c2ecf20Sopenharmony_ci			      u32 pri_val)
26388c2ecf20Sopenharmony_ci{
26398c2ecf20Sopenharmony_ci	int cpp;
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state))
26428c2ecf20Sopenharmony_ci		return 0;
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	cpp = plane_state->hw.fb->format->cpp[0];
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	return ilk_wm_fbc(pri_val, drm_rect_width(&plane_state->uapi.dst),
26478c2ecf20Sopenharmony_ci			  cpp);
26488c2ecf20Sopenharmony_ci}
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_cistatic unsigned int
26518c2ecf20Sopenharmony_ciilk_display_fifo_size(const struct drm_i915_private *dev_priv)
26528c2ecf20Sopenharmony_ci{
26538c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 8)
26548c2ecf20Sopenharmony_ci		return 3072;
26558c2ecf20Sopenharmony_ci	else if (INTEL_GEN(dev_priv) >= 7)
26568c2ecf20Sopenharmony_ci		return 768;
26578c2ecf20Sopenharmony_ci	else
26588c2ecf20Sopenharmony_ci		return 512;
26598c2ecf20Sopenharmony_ci}
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_cistatic unsigned int
26628c2ecf20Sopenharmony_ciilk_plane_wm_reg_max(const struct drm_i915_private *dev_priv,
26638c2ecf20Sopenharmony_ci		     int level, bool is_sprite)
26648c2ecf20Sopenharmony_ci{
26658c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 8)
26668c2ecf20Sopenharmony_ci		/* BDW primary/sprite plane watermarks */
26678c2ecf20Sopenharmony_ci		return level == 0 ? 255 : 2047;
26688c2ecf20Sopenharmony_ci	else if (INTEL_GEN(dev_priv) >= 7)
26698c2ecf20Sopenharmony_ci		/* IVB/HSW primary/sprite plane watermarks */
26708c2ecf20Sopenharmony_ci		return level == 0 ? 127 : 1023;
26718c2ecf20Sopenharmony_ci	else if (!is_sprite)
26728c2ecf20Sopenharmony_ci		/* ILK/SNB primary plane watermarks */
26738c2ecf20Sopenharmony_ci		return level == 0 ? 127 : 511;
26748c2ecf20Sopenharmony_ci	else
26758c2ecf20Sopenharmony_ci		/* ILK/SNB sprite plane watermarks */
26768c2ecf20Sopenharmony_ci		return level == 0 ? 63 : 255;
26778c2ecf20Sopenharmony_ci}
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_cistatic unsigned int
26808c2ecf20Sopenharmony_ciilk_cursor_wm_reg_max(const struct drm_i915_private *dev_priv, int level)
26818c2ecf20Sopenharmony_ci{
26828c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 7)
26838c2ecf20Sopenharmony_ci		return level == 0 ? 63 : 255;
26848c2ecf20Sopenharmony_ci	else
26858c2ecf20Sopenharmony_ci		return level == 0 ? 31 : 63;
26868c2ecf20Sopenharmony_ci}
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_cistatic unsigned int ilk_fbc_wm_reg_max(const struct drm_i915_private *dev_priv)
26898c2ecf20Sopenharmony_ci{
26908c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 8)
26918c2ecf20Sopenharmony_ci		return 31;
26928c2ecf20Sopenharmony_ci	else
26938c2ecf20Sopenharmony_ci		return 15;
26948c2ecf20Sopenharmony_ci}
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci/* Calculate the maximum primary/sprite plane watermark */
26978c2ecf20Sopenharmony_cistatic unsigned int ilk_plane_wm_max(const struct drm_i915_private *dev_priv,
26988c2ecf20Sopenharmony_ci				     int level,
26998c2ecf20Sopenharmony_ci				     const struct intel_wm_config *config,
27008c2ecf20Sopenharmony_ci				     enum intel_ddb_partitioning ddb_partitioning,
27018c2ecf20Sopenharmony_ci				     bool is_sprite)
27028c2ecf20Sopenharmony_ci{
27038c2ecf20Sopenharmony_ci	unsigned int fifo_size = ilk_display_fifo_size(dev_priv);
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci	/* if sprites aren't enabled, sprites get nothing */
27068c2ecf20Sopenharmony_ci	if (is_sprite && !config->sprites_enabled)
27078c2ecf20Sopenharmony_ci		return 0;
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	/* HSW allows LP1+ watermarks even with multiple pipes */
27108c2ecf20Sopenharmony_ci	if (level == 0 || config->num_pipes_active > 1) {
27118c2ecf20Sopenharmony_ci		fifo_size /= INTEL_NUM_PIPES(dev_priv);
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci		/*
27148c2ecf20Sopenharmony_ci		 * For some reason the non self refresh
27158c2ecf20Sopenharmony_ci		 * FIFO size is only half of the self
27168c2ecf20Sopenharmony_ci		 * refresh FIFO size on ILK/SNB.
27178c2ecf20Sopenharmony_ci		 */
27188c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) <= 6)
27198c2ecf20Sopenharmony_ci			fifo_size /= 2;
27208c2ecf20Sopenharmony_ci	}
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	if (config->sprites_enabled) {
27238c2ecf20Sopenharmony_ci		/* level 0 is always calculated with 1:1 split */
27248c2ecf20Sopenharmony_ci		if (level > 0 && ddb_partitioning == INTEL_DDB_PART_5_6) {
27258c2ecf20Sopenharmony_ci			if (is_sprite)
27268c2ecf20Sopenharmony_ci				fifo_size *= 5;
27278c2ecf20Sopenharmony_ci			fifo_size /= 6;
27288c2ecf20Sopenharmony_ci		} else {
27298c2ecf20Sopenharmony_ci			fifo_size /= 2;
27308c2ecf20Sopenharmony_ci		}
27318c2ecf20Sopenharmony_ci	}
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	/* clamp to max that the registers can hold */
27348c2ecf20Sopenharmony_ci	return min(fifo_size, ilk_plane_wm_reg_max(dev_priv, level, is_sprite));
27358c2ecf20Sopenharmony_ci}
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci/* Calculate the maximum cursor plane watermark */
27388c2ecf20Sopenharmony_cistatic unsigned int ilk_cursor_wm_max(const struct drm_i915_private *dev_priv,
27398c2ecf20Sopenharmony_ci				      int level,
27408c2ecf20Sopenharmony_ci				      const struct intel_wm_config *config)
27418c2ecf20Sopenharmony_ci{
27428c2ecf20Sopenharmony_ci	/* HSW LP1+ watermarks w/ multiple pipes */
27438c2ecf20Sopenharmony_ci	if (level > 0 && config->num_pipes_active > 1)
27448c2ecf20Sopenharmony_ci		return 64;
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci	/* otherwise just report max that registers can hold */
27478c2ecf20Sopenharmony_ci	return ilk_cursor_wm_reg_max(dev_priv, level);
27488c2ecf20Sopenharmony_ci}
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_cistatic void ilk_compute_wm_maximums(const struct drm_i915_private *dev_priv,
27518c2ecf20Sopenharmony_ci				    int level,
27528c2ecf20Sopenharmony_ci				    const struct intel_wm_config *config,
27538c2ecf20Sopenharmony_ci				    enum intel_ddb_partitioning ddb_partitioning,
27548c2ecf20Sopenharmony_ci				    struct ilk_wm_maximums *max)
27558c2ecf20Sopenharmony_ci{
27568c2ecf20Sopenharmony_ci	max->pri = ilk_plane_wm_max(dev_priv, level, config, ddb_partitioning, false);
27578c2ecf20Sopenharmony_ci	max->spr = ilk_plane_wm_max(dev_priv, level, config, ddb_partitioning, true);
27588c2ecf20Sopenharmony_ci	max->cur = ilk_cursor_wm_max(dev_priv, level, config);
27598c2ecf20Sopenharmony_ci	max->fbc = ilk_fbc_wm_reg_max(dev_priv);
27608c2ecf20Sopenharmony_ci}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_cistatic void ilk_compute_wm_reg_maximums(const struct drm_i915_private *dev_priv,
27638c2ecf20Sopenharmony_ci					int level,
27648c2ecf20Sopenharmony_ci					struct ilk_wm_maximums *max)
27658c2ecf20Sopenharmony_ci{
27668c2ecf20Sopenharmony_ci	max->pri = ilk_plane_wm_reg_max(dev_priv, level, false);
27678c2ecf20Sopenharmony_ci	max->spr = ilk_plane_wm_reg_max(dev_priv, level, true);
27688c2ecf20Sopenharmony_ci	max->cur = ilk_cursor_wm_reg_max(dev_priv, level);
27698c2ecf20Sopenharmony_ci	max->fbc = ilk_fbc_wm_reg_max(dev_priv);
27708c2ecf20Sopenharmony_ci}
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_cistatic bool ilk_validate_wm_level(int level,
27738c2ecf20Sopenharmony_ci				  const struct ilk_wm_maximums *max,
27748c2ecf20Sopenharmony_ci				  struct intel_wm_level *result)
27758c2ecf20Sopenharmony_ci{
27768c2ecf20Sopenharmony_ci	bool ret;
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci	/* already determined to be invalid? */
27798c2ecf20Sopenharmony_ci	if (!result->enable)
27808c2ecf20Sopenharmony_ci		return false;
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	result->enable = result->pri_val <= max->pri &&
27838c2ecf20Sopenharmony_ci			 result->spr_val <= max->spr &&
27848c2ecf20Sopenharmony_ci			 result->cur_val <= max->cur;
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ci	ret = result->enable;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	/*
27898c2ecf20Sopenharmony_ci	 * HACK until we can pre-compute everything,
27908c2ecf20Sopenharmony_ci	 * and thus fail gracefully if LP0 watermarks
27918c2ecf20Sopenharmony_ci	 * are exceeded...
27928c2ecf20Sopenharmony_ci	 */
27938c2ecf20Sopenharmony_ci	if (level == 0 && !result->enable) {
27948c2ecf20Sopenharmony_ci		if (result->pri_val > max->pri)
27958c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("Primary WM%d too large %u (max %u)\n",
27968c2ecf20Sopenharmony_ci				      level, result->pri_val, max->pri);
27978c2ecf20Sopenharmony_ci		if (result->spr_val > max->spr)
27988c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("Sprite WM%d too large %u (max %u)\n",
27998c2ecf20Sopenharmony_ci				      level, result->spr_val, max->spr);
28008c2ecf20Sopenharmony_ci		if (result->cur_val > max->cur)
28018c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("Cursor WM%d too large %u (max %u)\n",
28028c2ecf20Sopenharmony_ci				      level, result->cur_val, max->cur);
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ci		result->pri_val = min_t(u32, result->pri_val, max->pri);
28058c2ecf20Sopenharmony_ci		result->spr_val = min_t(u32, result->spr_val, max->spr);
28068c2ecf20Sopenharmony_ci		result->cur_val = min_t(u32, result->cur_val, max->cur);
28078c2ecf20Sopenharmony_ci		result->enable = true;
28088c2ecf20Sopenharmony_ci	}
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	return ret;
28118c2ecf20Sopenharmony_ci}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_cistatic void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
28148c2ecf20Sopenharmony_ci				 const struct intel_crtc *crtc,
28158c2ecf20Sopenharmony_ci				 int level,
28168c2ecf20Sopenharmony_ci				 struct intel_crtc_state *crtc_state,
28178c2ecf20Sopenharmony_ci				 const struct intel_plane_state *pristate,
28188c2ecf20Sopenharmony_ci				 const struct intel_plane_state *sprstate,
28198c2ecf20Sopenharmony_ci				 const struct intel_plane_state *curstate,
28208c2ecf20Sopenharmony_ci				 struct intel_wm_level *result)
28218c2ecf20Sopenharmony_ci{
28228c2ecf20Sopenharmony_ci	u16 pri_latency = dev_priv->wm.pri_latency[level];
28238c2ecf20Sopenharmony_ci	u16 spr_latency = dev_priv->wm.spr_latency[level];
28248c2ecf20Sopenharmony_ci	u16 cur_latency = dev_priv->wm.cur_latency[level];
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	/* WM1+ latency values stored in 0.5us units */
28278c2ecf20Sopenharmony_ci	if (level > 0) {
28288c2ecf20Sopenharmony_ci		pri_latency *= 5;
28298c2ecf20Sopenharmony_ci		spr_latency *= 5;
28308c2ecf20Sopenharmony_ci		cur_latency *= 5;
28318c2ecf20Sopenharmony_ci	}
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	if (pristate) {
28348c2ecf20Sopenharmony_ci		result->pri_val = ilk_compute_pri_wm(crtc_state, pristate,
28358c2ecf20Sopenharmony_ci						     pri_latency, level);
28368c2ecf20Sopenharmony_ci		result->fbc_val = ilk_compute_fbc_wm(crtc_state, pristate, result->pri_val);
28378c2ecf20Sopenharmony_ci	}
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci	if (sprstate)
28408c2ecf20Sopenharmony_ci		result->spr_val = ilk_compute_spr_wm(crtc_state, sprstate, spr_latency);
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_ci	if (curstate)
28438c2ecf20Sopenharmony_ci		result->cur_val = ilk_compute_cur_wm(crtc_state, curstate, cur_latency);
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci	result->enable = true;
28468c2ecf20Sopenharmony_ci}
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_cistatic void intel_read_wm_latency(struct drm_i915_private *dev_priv,
28498c2ecf20Sopenharmony_ci				  u16 wm[])
28508c2ecf20Sopenharmony_ci{
28518c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 9) {
28548c2ecf20Sopenharmony_ci		u32 val;
28558c2ecf20Sopenharmony_ci		int ret, i;
28568c2ecf20Sopenharmony_ci		int level, max_level = ilk_wm_max_level(dev_priv);
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci		/* read the first set of memory latencies[0:3] */
28598c2ecf20Sopenharmony_ci		val = 0; /* data0 to be programmed to 0 for first set */
28608c2ecf20Sopenharmony_ci		ret = sandybridge_pcode_read(dev_priv,
28618c2ecf20Sopenharmony_ci					     GEN9_PCODE_READ_MEM_LATENCY,
28628c2ecf20Sopenharmony_ci					     &val, NULL);
28638c2ecf20Sopenharmony_ci
28648c2ecf20Sopenharmony_ci		if (ret) {
28658c2ecf20Sopenharmony_ci			drm_err(&dev_priv->drm,
28668c2ecf20Sopenharmony_ci				"SKL Mailbox read error = %d\n", ret);
28678c2ecf20Sopenharmony_ci			return;
28688c2ecf20Sopenharmony_ci		}
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci		wm[0] = val & GEN9_MEM_LATENCY_LEVEL_MASK;
28718c2ecf20Sopenharmony_ci		wm[1] = (val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) &
28728c2ecf20Sopenharmony_ci				GEN9_MEM_LATENCY_LEVEL_MASK;
28738c2ecf20Sopenharmony_ci		wm[2] = (val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) &
28748c2ecf20Sopenharmony_ci				GEN9_MEM_LATENCY_LEVEL_MASK;
28758c2ecf20Sopenharmony_ci		wm[3] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
28768c2ecf20Sopenharmony_ci				GEN9_MEM_LATENCY_LEVEL_MASK;
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci		/* read the second set of memory latencies[4:7] */
28798c2ecf20Sopenharmony_ci		val = 1; /* data0 to be programmed to 1 for second set */
28808c2ecf20Sopenharmony_ci		ret = sandybridge_pcode_read(dev_priv,
28818c2ecf20Sopenharmony_ci					     GEN9_PCODE_READ_MEM_LATENCY,
28828c2ecf20Sopenharmony_ci					     &val, NULL);
28838c2ecf20Sopenharmony_ci		if (ret) {
28848c2ecf20Sopenharmony_ci			drm_err(&dev_priv->drm,
28858c2ecf20Sopenharmony_ci				"SKL Mailbox read error = %d\n", ret);
28868c2ecf20Sopenharmony_ci			return;
28878c2ecf20Sopenharmony_ci		}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci		wm[4] = val & GEN9_MEM_LATENCY_LEVEL_MASK;
28908c2ecf20Sopenharmony_ci		wm[5] = (val >> GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT) &
28918c2ecf20Sopenharmony_ci				GEN9_MEM_LATENCY_LEVEL_MASK;
28928c2ecf20Sopenharmony_ci		wm[6] = (val >> GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT) &
28938c2ecf20Sopenharmony_ci				GEN9_MEM_LATENCY_LEVEL_MASK;
28948c2ecf20Sopenharmony_ci		wm[7] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
28958c2ecf20Sopenharmony_ci				GEN9_MEM_LATENCY_LEVEL_MASK;
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci		/*
28988c2ecf20Sopenharmony_ci		 * If a level n (n > 1) has a 0us latency, all levels m (m >= n)
28998c2ecf20Sopenharmony_ci		 * need to be disabled. We make sure to sanitize the values out
29008c2ecf20Sopenharmony_ci		 * of the punit to satisfy this requirement.
29018c2ecf20Sopenharmony_ci		 */
29028c2ecf20Sopenharmony_ci		for (level = 1; level <= max_level; level++) {
29038c2ecf20Sopenharmony_ci			if (wm[level] == 0) {
29048c2ecf20Sopenharmony_ci				for (i = level + 1; i <= max_level; i++)
29058c2ecf20Sopenharmony_ci					wm[i] = 0;
29068c2ecf20Sopenharmony_ci				break;
29078c2ecf20Sopenharmony_ci			}
29088c2ecf20Sopenharmony_ci		}
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci		/*
29118c2ecf20Sopenharmony_ci		 * WaWmMemoryReadLatency:skl+,glk
29128c2ecf20Sopenharmony_ci		 *
29138c2ecf20Sopenharmony_ci		 * punit doesn't take into account the read latency so we need
29148c2ecf20Sopenharmony_ci		 * to add 2us to the various latency levels we retrieve from the
29158c2ecf20Sopenharmony_ci		 * punit when level 0 response data us 0us.
29168c2ecf20Sopenharmony_ci		 */
29178c2ecf20Sopenharmony_ci		if (wm[0] == 0) {
29188c2ecf20Sopenharmony_ci			wm[0] += 2;
29198c2ecf20Sopenharmony_ci			for (level = 1; level <= max_level; level++) {
29208c2ecf20Sopenharmony_ci				if (wm[level] == 0)
29218c2ecf20Sopenharmony_ci					break;
29228c2ecf20Sopenharmony_ci				wm[level] += 2;
29238c2ecf20Sopenharmony_ci			}
29248c2ecf20Sopenharmony_ci		}
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci		/*
29278c2ecf20Sopenharmony_ci		 * WA Level-0 adjustment for 16GB DIMMs: SKL+
29288c2ecf20Sopenharmony_ci		 * If we could not get dimm info enable this WA to prevent from
29298c2ecf20Sopenharmony_ci		 * any underrun. If not able to get Dimm info assume 16GB dimm
29308c2ecf20Sopenharmony_ci		 * to avoid any underrun.
29318c2ecf20Sopenharmony_ci		 */
29328c2ecf20Sopenharmony_ci		if (dev_priv->dram_info.is_16gb_dimm)
29338c2ecf20Sopenharmony_ci			wm[0] += 1;
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
29368c2ecf20Sopenharmony_ci		u64 sskpd = intel_uncore_read64(uncore, MCH_SSKPD);
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci		wm[0] = (sskpd >> 56) & 0xFF;
29398c2ecf20Sopenharmony_ci		if (wm[0] == 0)
29408c2ecf20Sopenharmony_ci			wm[0] = sskpd & 0xF;
29418c2ecf20Sopenharmony_ci		wm[1] = (sskpd >> 4) & 0xFF;
29428c2ecf20Sopenharmony_ci		wm[2] = (sskpd >> 12) & 0xFF;
29438c2ecf20Sopenharmony_ci		wm[3] = (sskpd >> 20) & 0x1FF;
29448c2ecf20Sopenharmony_ci		wm[4] = (sskpd >> 32) & 0x1FF;
29458c2ecf20Sopenharmony_ci	} else if (INTEL_GEN(dev_priv) >= 6) {
29468c2ecf20Sopenharmony_ci		u32 sskpd = intel_uncore_read(uncore, MCH_SSKPD);
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_ci		wm[0] = (sskpd >> SSKPD_WM0_SHIFT) & SSKPD_WM_MASK;
29498c2ecf20Sopenharmony_ci		wm[1] = (sskpd >> SSKPD_WM1_SHIFT) & SSKPD_WM_MASK;
29508c2ecf20Sopenharmony_ci		wm[2] = (sskpd >> SSKPD_WM2_SHIFT) & SSKPD_WM_MASK;
29518c2ecf20Sopenharmony_ci		wm[3] = (sskpd >> SSKPD_WM3_SHIFT) & SSKPD_WM_MASK;
29528c2ecf20Sopenharmony_ci	} else if (INTEL_GEN(dev_priv) >= 5) {
29538c2ecf20Sopenharmony_ci		u32 mltr = intel_uncore_read(uncore, MLTR_ILK);
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci		/* ILK primary LP0 latency is 700 ns */
29568c2ecf20Sopenharmony_ci		wm[0] = 7;
29578c2ecf20Sopenharmony_ci		wm[1] = (mltr >> MLTR_WM1_SHIFT) & ILK_SRLT_MASK;
29588c2ecf20Sopenharmony_ci		wm[2] = (mltr >> MLTR_WM2_SHIFT) & ILK_SRLT_MASK;
29598c2ecf20Sopenharmony_ci	} else {
29608c2ecf20Sopenharmony_ci		MISSING_CASE(INTEL_DEVID(dev_priv));
29618c2ecf20Sopenharmony_ci	}
29628c2ecf20Sopenharmony_ci}
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_cistatic void intel_fixup_spr_wm_latency(struct drm_i915_private *dev_priv,
29658c2ecf20Sopenharmony_ci				       u16 wm[5])
29668c2ecf20Sopenharmony_ci{
29678c2ecf20Sopenharmony_ci	/* ILK sprite LP0 latency is 1300 ns */
29688c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 5))
29698c2ecf20Sopenharmony_ci		wm[0] = 13;
29708c2ecf20Sopenharmony_ci}
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_cistatic void intel_fixup_cur_wm_latency(struct drm_i915_private *dev_priv,
29738c2ecf20Sopenharmony_ci				       u16 wm[5])
29748c2ecf20Sopenharmony_ci{
29758c2ecf20Sopenharmony_ci	/* ILK cursor LP0 latency is 1300 ns */
29768c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 5))
29778c2ecf20Sopenharmony_ci		wm[0] = 13;
29788c2ecf20Sopenharmony_ci}
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ciint ilk_wm_max_level(const struct drm_i915_private *dev_priv)
29818c2ecf20Sopenharmony_ci{
29828c2ecf20Sopenharmony_ci	/* how many WM levels are we expecting */
29838c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 9)
29848c2ecf20Sopenharmony_ci		return 7;
29858c2ecf20Sopenharmony_ci	else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
29868c2ecf20Sopenharmony_ci		return 4;
29878c2ecf20Sopenharmony_ci	else if (INTEL_GEN(dev_priv) >= 6)
29888c2ecf20Sopenharmony_ci		return 3;
29898c2ecf20Sopenharmony_ci	else
29908c2ecf20Sopenharmony_ci		return 2;
29918c2ecf20Sopenharmony_ci}
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_cistatic void intel_print_wm_latency(struct drm_i915_private *dev_priv,
29948c2ecf20Sopenharmony_ci				   const char *name,
29958c2ecf20Sopenharmony_ci				   const u16 wm[])
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	for (level = 0; level <= max_level; level++) {
30008c2ecf20Sopenharmony_ci		unsigned int latency = wm[level];
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci		if (latency == 0) {
30038c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
30048c2ecf20Sopenharmony_ci				    "%s WM%d latency not provided\n",
30058c2ecf20Sopenharmony_ci				    name, level);
30068c2ecf20Sopenharmony_ci			continue;
30078c2ecf20Sopenharmony_ci		}
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci		/*
30108c2ecf20Sopenharmony_ci		 * - latencies are in us on gen9.
30118c2ecf20Sopenharmony_ci		 * - before then, WM1+ latency values are in 0.5us units
30128c2ecf20Sopenharmony_ci		 */
30138c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 9)
30148c2ecf20Sopenharmony_ci			latency *= 10;
30158c2ecf20Sopenharmony_ci		else if (level > 0)
30168c2ecf20Sopenharmony_ci			latency *= 5;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
30198c2ecf20Sopenharmony_ci			    "%s WM%d latency %u (%u.%u usec)\n", name, level,
30208c2ecf20Sopenharmony_ci			    wm[level], latency / 10, latency % 10);
30218c2ecf20Sopenharmony_ci	}
30228c2ecf20Sopenharmony_ci}
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_cistatic bool ilk_increase_wm_latency(struct drm_i915_private *dev_priv,
30258c2ecf20Sopenharmony_ci				    u16 wm[5], u16 min)
30268c2ecf20Sopenharmony_ci{
30278c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci	if (wm[0] >= min)
30308c2ecf20Sopenharmony_ci		return false;
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	wm[0] = max(wm[0], min);
30338c2ecf20Sopenharmony_ci	for (level = 1; level <= max_level; level++)
30348c2ecf20Sopenharmony_ci		wm[level] = max_t(u16, wm[level], DIV_ROUND_UP(min, 5));
30358c2ecf20Sopenharmony_ci
30368c2ecf20Sopenharmony_ci	return true;
30378c2ecf20Sopenharmony_ci}
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_cistatic void snb_wm_latency_quirk(struct drm_i915_private *dev_priv)
30408c2ecf20Sopenharmony_ci{
30418c2ecf20Sopenharmony_ci	bool changed;
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	/*
30448c2ecf20Sopenharmony_ci	 * The BIOS provided WM memory latency values are often
30458c2ecf20Sopenharmony_ci	 * inadequate for high resolution displays. Adjust them.
30468c2ecf20Sopenharmony_ci	 */
30478c2ecf20Sopenharmony_ci	changed = ilk_increase_wm_latency(dev_priv, dev_priv->wm.pri_latency, 12);
30488c2ecf20Sopenharmony_ci	changed |= ilk_increase_wm_latency(dev_priv, dev_priv->wm.spr_latency, 12);
30498c2ecf20Sopenharmony_ci	changed |= ilk_increase_wm_latency(dev_priv, dev_priv->wm.cur_latency, 12);
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci	if (!changed)
30528c2ecf20Sopenharmony_ci		return;
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
30558c2ecf20Sopenharmony_ci		    "WM latency values increased to avoid potential underruns\n");
30568c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Primary", dev_priv->wm.pri_latency);
30578c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency);
30588c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
30598c2ecf20Sopenharmony_ci}
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_cistatic void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv)
30628c2ecf20Sopenharmony_ci{
30638c2ecf20Sopenharmony_ci	/*
30648c2ecf20Sopenharmony_ci	 * On some SNB machines (Thinkpad X220 Tablet at least)
30658c2ecf20Sopenharmony_ci	 * LP3 usage can cause vblank interrupts to be lost.
30668c2ecf20Sopenharmony_ci	 * The DEIIR bit will go high but it looks like the CPU
30678c2ecf20Sopenharmony_ci	 * never gets interrupted.
30688c2ecf20Sopenharmony_ci	 *
30698c2ecf20Sopenharmony_ci	 * It's not clear whether other interrupt source could
30708c2ecf20Sopenharmony_ci	 * be affected or if this is somehow limited to vblank
30718c2ecf20Sopenharmony_ci	 * interrupts only. To play it safe we disable LP3
30728c2ecf20Sopenharmony_ci	 * watermarks entirely.
30738c2ecf20Sopenharmony_ci	 */
30748c2ecf20Sopenharmony_ci	if (dev_priv->wm.pri_latency[3] == 0 &&
30758c2ecf20Sopenharmony_ci	    dev_priv->wm.spr_latency[3] == 0 &&
30768c2ecf20Sopenharmony_ci	    dev_priv->wm.cur_latency[3] == 0)
30778c2ecf20Sopenharmony_ci		return;
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci	dev_priv->wm.pri_latency[3] = 0;
30808c2ecf20Sopenharmony_ci	dev_priv->wm.spr_latency[3] = 0;
30818c2ecf20Sopenharmony_ci	dev_priv->wm.cur_latency[3] = 0;
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
30848c2ecf20Sopenharmony_ci		    "LP3 watermarks disabled due to potential for lost interrupts\n");
30858c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Primary", dev_priv->wm.pri_latency);
30868c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency);
30878c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
30888c2ecf20Sopenharmony_ci}
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_cistatic void ilk_setup_wm_latency(struct drm_i915_private *dev_priv)
30918c2ecf20Sopenharmony_ci{
30928c2ecf20Sopenharmony_ci	intel_read_wm_latency(dev_priv, dev_priv->wm.pri_latency);
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	memcpy(dev_priv->wm.spr_latency, dev_priv->wm.pri_latency,
30958c2ecf20Sopenharmony_ci	       sizeof(dev_priv->wm.pri_latency));
30968c2ecf20Sopenharmony_ci	memcpy(dev_priv->wm.cur_latency, dev_priv->wm.pri_latency,
30978c2ecf20Sopenharmony_ci	       sizeof(dev_priv->wm.pri_latency));
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci	intel_fixup_spr_wm_latency(dev_priv, dev_priv->wm.spr_latency);
31008c2ecf20Sopenharmony_ci	intel_fixup_cur_wm_latency(dev_priv, dev_priv->wm.cur_latency);
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Primary", dev_priv->wm.pri_latency);
31038c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency);
31048c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 6)) {
31078c2ecf20Sopenharmony_ci		snb_wm_latency_quirk(dev_priv);
31088c2ecf20Sopenharmony_ci		snb_wm_lp3_irq_quirk(dev_priv);
31098c2ecf20Sopenharmony_ci	}
31108c2ecf20Sopenharmony_ci}
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_cistatic void skl_setup_wm_latency(struct drm_i915_private *dev_priv)
31138c2ecf20Sopenharmony_ci{
31148c2ecf20Sopenharmony_ci	intel_read_wm_latency(dev_priv, dev_priv->wm.skl_latency);
31158c2ecf20Sopenharmony_ci	intel_print_wm_latency(dev_priv, "Gen9 Plane", dev_priv->wm.skl_latency);
31168c2ecf20Sopenharmony_ci}
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_cistatic bool ilk_validate_pipe_wm(const struct drm_i915_private *dev_priv,
31198c2ecf20Sopenharmony_ci				 struct intel_pipe_wm *pipe_wm)
31208c2ecf20Sopenharmony_ci{
31218c2ecf20Sopenharmony_ci	/* LP0 watermark maximums depend on this pipe alone */
31228c2ecf20Sopenharmony_ci	const struct intel_wm_config config = {
31238c2ecf20Sopenharmony_ci		.num_pipes_active = 1,
31248c2ecf20Sopenharmony_ci		.sprites_enabled = pipe_wm->sprites_enabled,
31258c2ecf20Sopenharmony_ci		.sprites_scaled = pipe_wm->sprites_scaled,
31268c2ecf20Sopenharmony_ci	};
31278c2ecf20Sopenharmony_ci	struct ilk_wm_maximums max;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	/* LP0 watermarks always use 1/2 DDB partitioning */
31308c2ecf20Sopenharmony_ci	ilk_compute_wm_maximums(dev_priv, 0, &config, INTEL_DDB_PART_1_2, &max);
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci	/* At least LP0 must be valid */
31338c2ecf20Sopenharmony_ci	if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) {
31348c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "LP0 watermark invalid\n");
31358c2ecf20Sopenharmony_ci		return false;
31368c2ecf20Sopenharmony_ci	}
31378c2ecf20Sopenharmony_ci
31388c2ecf20Sopenharmony_ci	return true;
31398c2ecf20Sopenharmony_ci}
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci/* Compute new watermarks for the pipe */
31428c2ecf20Sopenharmony_cistatic int ilk_compute_pipe_wm(struct intel_crtc_state *crtc_state)
31438c2ecf20Sopenharmony_ci{
31448c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
31458c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
31468c2ecf20Sopenharmony_ci	struct intel_pipe_wm *pipe_wm;
31478c2ecf20Sopenharmony_ci	struct intel_plane *plane;
31488c2ecf20Sopenharmony_ci	const struct intel_plane_state *plane_state;
31498c2ecf20Sopenharmony_ci	const struct intel_plane_state *pristate = NULL;
31508c2ecf20Sopenharmony_ci	const struct intel_plane_state *sprstate = NULL;
31518c2ecf20Sopenharmony_ci	const struct intel_plane_state *curstate = NULL;
31528c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv), usable_level;
31538c2ecf20Sopenharmony_ci	struct ilk_wm_maximums max;
31548c2ecf20Sopenharmony_ci
31558c2ecf20Sopenharmony_ci	pipe_wm = &crtc_state->wm.ilk.optimal;
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
31588c2ecf20Sopenharmony_ci		if (plane->base.type == DRM_PLANE_TYPE_PRIMARY)
31598c2ecf20Sopenharmony_ci			pristate = plane_state;
31608c2ecf20Sopenharmony_ci		else if (plane->base.type == DRM_PLANE_TYPE_OVERLAY)
31618c2ecf20Sopenharmony_ci			sprstate = plane_state;
31628c2ecf20Sopenharmony_ci		else if (plane->base.type == DRM_PLANE_TYPE_CURSOR)
31638c2ecf20Sopenharmony_ci			curstate = plane_state;
31648c2ecf20Sopenharmony_ci	}
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_ci	pipe_wm->pipe_enabled = crtc_state->hw.active;
31678c2ecf20Sopenharmony_ci	if (sprstate) {
31688c2ecf20Sopenharmony_ci		pipe_wm->sprites_enabled = sprstate->uapi.visible;
31698c2ecf20Sopenharmony_ci		pipe_wm->sprites_scaled = sprstate->uapi.visible &&
31708c2ecf20Sopenharmony_ci			(drm_rect_width(&sprstate->uapi.dst) != drm_rect_width(&sprstate->uapi.src) >> 16 ||
31718c2ecf20Sopenharmony_ci			 drm_rect_height(&sprstate->uapi.dst) != drm_rect_height(&sprstate->uapi.src) >> 16);
31728c2ecf20Sopenharmony_ci	}
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	usable_level = max_level;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	/* ILK/SNB: LP2+ watermarks only w/o sprites */
31778c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) <= 6 && pipe_wm->sprites_enabled)
31788c2ecf20Sopenharmony_ci		usable_level = 1;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	/* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
31818c2ecf20Sopenharmony_ci	if (pipe_wm->sprites_scaled)
31828c2ecf20Sopenharmony_ci		usable_level = 0;
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci	memset(&pipe_wm->wm, 0, sizeof(pipe_wm->wm));
31858c2ecf20Sopenharmony_ci	ilk_compute_wm_level(dev_priv, crtc, 0, crtc_state,
31868c2ecf20Sopenharmony_ci			     pristate, sprstate, curstate, &pipe_wm->wm[0]);
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci	if (!ilk_validate_pipe_wm(dev_priv, pipe_wm))
31898c2ecf20Sopenharmony_ci		return -EINVAL;
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci	ilk_compute_wm_reg_maximums(dev_priv, 1, &max);
31928c2ecf20Sopenharmony_ci
31938c2ecf20Sopenharmony_ci	for (level = 1; level <= usable_level; level++) {
31948c2ecf20Sopenharmony_ci		struct intel_wm_level *wm = &pipe_wm->wm[level];
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_ci		ilk_compute_wm_level(dev_priv, crtc, level, crtc_state,
31978c2ecf20Sopenharmony_ci				     pristate, sprstate, curstate, wm);
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ci		/*
32008c2ecf20Sopenharmony_ci		 * Disable any watermark level that exceeds the
32018c2ecf20Sopenharmony_ci		 * register maximums since such watermarks are
32028c2ecf20Sopenharmony_ci		 * always invalid.
32038c2ecf20Sopenharmony_ci		 */
32048c2ecf20Sopenharmony_ci		if (!ilk_validate_wm_level(level, &max, wm)) {
32058c2ecf20Sopenharmony_ci			memset(wm, 0, sizeof(*wm));
32068c2ecf20Sopenharmony_ci			break;
32078c2ecf20Sopenharmony_ci		}
32088c2ecf20Sopenharmony_ci	}
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci	return 0;
32118c2ecf20Sopenharmony_ci}
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci/*
32148c2ecf20Sopenharmony_ci * Build a set of 'intermediate' watermark values that satisfy both the old
32158c2ecf20Sopenharmony_ci * state and the new state.  These can be programmed to the hardware
32168c2ecf20Sopenharmony_ci * immediately.
32178c2ecf20Sopenharmony_ci */
32188c2ecf20Sopenharmony_cistatic int ilk_compute_intermediate_wm(struct intel_crtc_state *newstate)
32198c2ecf20Sopenharmony_ci{
32208c2ecf20Sopenharmony_ci	struct intel_crtc *intel_crtc = to_intel_crtc(newstate->uapi.crtc);
32218c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
32228c2ecf20Sopenharmony_ci	struct intel_pipe_wm *a = &newstate->wm.ilk.intermediate;
32238c2ecf20Sopenharmony_ci	struct intel_atomic_state *intel_state =
32248c2ecf20Sopenharmony_ci		to_intel_atomic_state(newstate->uapi.state);
32258c2ecf20Sopenharmony_ci	const struct intel_crtc_state *oldstate =
32268c2ecf20Sopenharmony_ci		intel_atomic_get_old_crtc_state(intel_state, intel_crtc);
32278c2ecf20Sopenharmony_ci	const struct intel_pipe_wm *b = &oldstate->wm.ilk.optimal;
32288c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
32298c2ecf20Sopenharmony_ci
32308c2ecf20Sopenharmony_ci	/*
32318c2ecf20Sopenharmony_ci	 * Start with the final, target watermarks, then combine with the
32328c2ecf20Sopenharmony_ci	 * currently active watermarks to get values that are safe both before
32338c2ecf20Sopenharmony_ci	 * and after the vblank.
32348c2ecf20Sopenharmony_ci	 */
32358c2ecf20Sopenharmony_ci	*a = newstate->wm.ilk.optimal;
32368c2ecf20Sopenharmony_ci	if (!newstate->hw.active || drm_atomic_crtc_needs_modeset(&newstate->uapi) ||
32378c2ecf20Sopenharmony_ci	    intel_state->skip_intermediate_wm)
32388c2ecf20Sopenharmony_ci		return 0;
32398c2ecf20Sopenharmony_ci
32408c2ecf20Sopenharmony_ci	a->pipe_enabled |= b->pipe_enabled;
32418c2ecf20Sopenharmony_ci	a->sprites_enabled |= b->sprites_enabled;
32428c2ecf20Sopenharmony_ci	a->sprites_scaled |= b->sprites_scaled;
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_ci	for (level = 0; level <= max_level; level++) {
32458c2ecf20Sopenharmony_ci		struct intel_wm_level *a_wm = &a->wm[level];
32468c2ecf20Sopenharmony_ci		const struct intel_wm_level *b_wm = &b->wm[level];
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci		a_wm->enable &= b_wm->enable;
32498c2ecf20Sopenharmony_ci		a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
32508c2ecf20Sopenharmony_ci		a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
32518c2ecf20Sopenharmony_ci		a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
32528c2ecf20Sopenharmony_ci		a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
32538c2ecf20Sopenharmony_ci	}
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_ci	/*
32568c2ecf20Sopenharmony_ci	 * We need to make sure that these merged watermark values are
32578c2ecf20Sopenharmony_ci	 * actually a valid configuration themselves.  If they're not,
32588c2ecf20Sopenharmony_ci	 * there's no safe way to transition from the old state to
32598c2ecf20Sopenharmony_ci	 * the new state, so we need to fail the atomic transaction.
32608c2ecf20Sopenharmony_ci	 */
32618c2ecf20Sopenharmony_ci	if (!ilk_validate_pipe_wm(dev_priv, a))
32628c2ecf20Sopenharmony_ci		return -EINVAL;
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_ci	/*
32658c2ecf20Sopenharmony_ci	 * If our intermediate WM are identical to the final WM, then we can
32668c2ecf20Sopenharmony_ci	 * omit the post-vblank programming; only update if it's different.
32678c2ecf20Sopenharmony_ci	 */
32688c2ecf20Sopenharmony_ci	if (memcmp(a, &newstate->wm.ilk.optimal, sizeof(*a)) != 0)
32698c2ecf20Sopenharmony_ci		newstate->wm.need_postvbl_update = true;
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	return 0;
32728c2ecf20Sopenharmony_ci}
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci/*
32758c2ecf20Sopenharmony_ci * Merge the watermarks from all active pipes for a specific level.
32768c2ecf20Sopenharmony_ci */
32778c2ecf20Sopenharmony_cistatic void ilk_merge_wm_level(struct drm_i915_private *dev_priv,
32788c2ecf20Sopenharmony_ci			       int level,
32798c2ecf20Sopenharmony_ci			       struct intel_wm_level *ret_wm)
32808c2ecf20Sopenharmony_ci{
32818c2ecf20Sopenharmony_ci	const struct intel_crtc *intel_crtc;
32828c2ecf20Sopenharmony_ci
32838c2ecf20Sopenharmony_ci	ret_wm->enable = true;
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, intel_crtc) {
32868c2ecf20Sopenharmony_ci		const struct intel_pipe_wm *active = &intel_crtc->wm.active.ilk;
32878c2ecf20Sopenharmony_ci		const struct intel_wm_level *wm = &active->wm[level];
32888c2ecf20Sopenharmony_ci
32898c2ecf20Sopenharmony_ci		if (!active->pipe_enabled)
32908c2ecf20Sopenharmony_ci			continue;
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci		/*
32938c2ecf20Sopenharmony_ci		 * The watermark values may have been used in the past,
32948c2ecf20Sopenharmony_ci		 * so we must maintain them in the registers for some
32958c2ecf20Sopenharmony_ci		 * time even if the level is now disabled.
32968c2ecf20Sopenharmony_ci		 */
32978c2ecf20Sopenharmony_ci		if (!wm->enable)
32988c2ecf20Sopenharmony_ci			ret_wm->enable = false;
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ci		ret_wm->pri_val = max(ret_wm->pri_val, wm->pri_val);
33018c2ecf20Sopenharmony_ci		ret_wm->spr_val = max(ret_wm->spr_val, wm->spr_val);
33028c2ecf20Sopenharmony_ci		ret_wm->cur_val = max(ret_wm->cur_val, wm->cur_val);
33038c2ecf20Sopenharmony_ci		ret_wm->fbc_val = max(ret_wm->fbc_val, wm->fbc_val);
33048c2ecf20Sopenharmony_ci	}
33058c2ecf20Sopenharmony_ci}
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ci/*
33088c2ecf20Sopenharmony_ci * Merge all low power watermarks for all active pipes.
33098c2ecf20Sopenharmony_ci */
33108c2ecf20Sopenharmony_cistatic void ilk_wm_merge(struct drm_i915_private *dev_priv,
33118c2ecf20Sopenharmony_ci			 const struct intel_wm_config *config,
33128c2ecf20Sopenharmony_ci			 const struct ilk_wm_maximums *max,
33138c2ecf20Sopenharmony_ci			 struct intel_pipe_wm *merged)
33148c2ecf20Sopenharmony_ci{
33158c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
33168c2ecf20Sopenharmony_ci	int last_enabled_level = max_level;
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci	/* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */
33198c2ecf20Sopenharmony_ci	if ((INTEL_GEN(dev_priv) <= 6 || IS_IVYBRIDGE(dev_priv)) &&
33208c2ecf20Sopenharmony_ci	    config->num_pipes_active > 1)
33218c2ecf20Sopenharmony_ci		last_enabled_level = 0;
33228c2ecf20Sopenharmony_ci
33238c2ecf20Sopenharmony_ci	/* ILK: FBC WM must be disabled always */
33248c2ecf20Sopenharmony_ci	merged->fbc_wm_enabled = INTEL_GEN(dev_priv) >= 6;
33258c2ecf20Sopenharmony_ci
33268c2ecf20Sopenharmony_ci	/* merge each WM1+ level */
33278c2ecf20Sopenharmony_ci	for (level = 1; level <= max_level; level++) {
33288c2ecf20Sopenharmony_ci		struct intel_wm_level *wm = &merged->wm[level];
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci		ilk_merge_wm_level(dev_priv, level, wm);
33318c2ecf20Sopenharmony_ci
33328c2ecf20Sopenharmony_ci		if (level > last_enabled_level)
33338c2ecf20Sopenharmony_ci			wm->enable = false;
33348c2ecf20Sopenharmony_ci		else if (!ilk_validate_wm_level(level, max, wm))
33358c2ecf20Sopenharmony_ci			/* make sure all following levels get disabled */
33368c2ecf20Sopenharmony_ci			last_enabled_level = level - 1;
33378c2ecf20Sopenharmony_ci
33388c2ecf20Sopenharmony_ci		/*
33398c2ecf20Sopenharmony_ci		 * The spec says it is preferred to disable
33408c2ecf20Sopenharmony_ci		 * FBC WMs instead of disabling a WM level.
33418c2ecf20Sopenharmony_ci		 */
33428c2ecf20Sopenharmony_ci		if (wm->fbc_val > max->fbc) {
33438c2ecf20Sopenharmony_ci			if (wm->enable)
33448c2ecf20Sopenharmony_ci				merged->fbc_wm_enabled = false;
33458c2ecf20Sopenharmony_ci			wm->fbc_val = 0;
33468c2ecf20Sopenharmony_ci		}
33478c2ecf20Sopenharmony_ci	}
33488c2ecf20Sopenharmony_ci
33498c2ecf20Sopenharmony_ci	/* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */
33508c2ecf20Sopenharmony_ci	/*
33518c2ecf20Sopenharmony_ci	 * FIXME this is racy. FBC might get enabled later.
33528c2ecf20Sopenharmony_ci	 * What we should check here is whether FBC can be
33538c2ecf20Sopenharmony_ci	 * enabled sometime later.
33548c2ecf20Sopenharmony_ci	 */
33558c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 5) && !merged->fbc_wm_enabled &&
33568c2ecf20Sopenharmony_ci	    intel_fbc_is_active(dev_priv)) {
33578c2ecf20Sopenharmony_ci		for (level = 2; level <= max_level; level++) {
33588c2ecf20Sopenharmony_ci			struct intel_wm_level *wm = &merged->wm[level];
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci			wm->enable = false;
33618c2ecf20Sopenharmony_ci		}
33628c2ecf20Sopenharmony_ci	}
33638c2ecf20Sopenharmony_ci}
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_cistatic int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm)
33668c2ecf20Sopenharmony_ci{
33678c2ecf20Sopenharmony_ci	/* LP1,LP2,LP3 levels are either 1,2,3 or 1,3,4 */
33688c2ecf20Sopenharmony_ci	return wm_lp + (wm_lp >= 2 && pipe_wm->wm[4].enable);
33698c2ecf20Sopenharmony_ci}
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci/* The value we need to program into the WM_LPx latency field */
33728c2ecf20Sopenharmony_cistatic unsigned int ilk_wm_lp_latency(struct drm_i915_private *dev_priv,
33738c2ecf20Sopenharmony_ci				      int level)
33748c2ecf20Sopenharmony_ci{
33758c2ecf20Sopenharmony_ci	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
33768c2ecf20Sopenharmony_ci		return 2 * level;
33778c2ecf20Sopenharmony_ci	else
33788c2ecf20Sopenharmony_ci		return dev_priv->wm.pri_latency[level];
33798c2ecf20Sopenharmony_ci}
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_cistatic void ilk_compute_wm_results(struct drm_i915_private *dev_priv,
33828c2ecf20Sopenharmony_ci				   const struct intel_pipe_wm *merged,
33838c2ecf20Sopenharmony_ci				   enum intel_ddb_partitioning partitioning,
33848c2ecf20Sopenharmony_ci				   struct ilk_wm_values *results)
33858c2ecf20Sopenharmony_ci{
33868c2ecf20Sopenharmony_ci	struct intel_crtc *intel_crtc;
33878c2ecf20Sopenharmony_ci	int level, wm_lp;
33888c2ecf20Sopenharmony_ci
33898c2ecf20Sopenharmony_ci	results->enable_fbc_wm = merged->fbc_wm_enabled;
33908c2ecf20Sopenharmony_ci	results->partitioning = partitioning;
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_ci	/* LP1+ register values */
33938c2ecf20Sopenharmony_ci	for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
33948c2ecf20Sopenharmony_ci		const struct intel_wm_level *r;
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci		level = ilk_wm_lp_to_level(wm_lp, merged);
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci		r = &merged->wm[level];
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci		/*
34018c2ecf20Sopenharmony_ci		 * Maintain the watermark values even if the level is
34028c2ecf20Sopenharmony_ci		 * disabled. Doing otherwise could cause underruns.
34038c2ecf20Sopenharmony_ci		 */
34048c2ecf20Sopenharmony_ci		results->wm_lp[wm_lp - 1] =
34058c2ecf20Sopenharmony_ci			(ilk_wm_lp_latency(dev_priv, level) << WM1_LP_LATENCY_SHIFT) |
34068c2ecf20Sopenharmony_ci			(r->pri_val << WM1_LP_SR_SHIFT) |
34078c2ecf20Sopenharmony_ci			r->cur_val;
34088c2ecf20Sopenharmony_ci
34098c2ecf20Sopenharmony_ci		if (r->enable)
34108c2ecf20Sopenharmony_ci			results->wm_lp[wm_lp - 1] |= WM1_LP_SR_EN;
34118c2ecf20Sopenharmony_ci
34128c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 8)
34138c2ecf20Sopenharmony_ci			results->wm_lp[wm_lp - 1] |=
34148c2ecf20Sopenharmony_ci				r->fbc_val << WM1_LP_FBC_SHIFT_BDW;
34158c2ecf20Sopenharmony_ci		else
34168c2ecf20Sopenharmony_ci			results->wm_lp[wm_lp - 1] |=
34178c2ecf20Sopenharmony_ci				r->fbc_val << WM1_LP_FBC_SHIFT;
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_ci		/*
34208c2ecf20Sopenharmony_ci		 * Always set WM1S_LP_EN when spr_val != 0, even if the
34218c2ecf20Sopenharmony_ci		 * level is disabled. Doing otherwise could cause underruns.
34228c2ecf20Sopenharmony_ci		 */
34238c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) <= 6 && r->spr_val) {
34248c2ecf20Sopenharmony_ci			drm_WARN_ON(&dev_priv->drm, wm_lp != 1);
34258c2ecf20Sopenharmony_ci			results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val;
34268c2ecf20Sopenharmony_ci		} else
34278c2ecf20Sopenharmony_ci			results->wm_lp_spr[wm_lp - 1] = r->spr_val;
34288c2ecf20Sopenharmony_ci	}
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci	/* LP0 register values */
34318c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, intel_crtc) {
34328c2ecf20Sopenharmony_ci		enum pipe pipe = intel_crtc->pipe;
34338c2ecf20Sopenharmony_ci		const struct intel_pipe_wm *pipe_wm = &intel_crtc->wm.active.ilk;
34348c2ecf20Sopenharmony_ci		const struct intel_wm_level *r = &pipe_wm->wm[0];
34358c2ecf20Sopenharmony_ci
34368c2ecf20Sopenharmony_ci		if (drm_WARN_ON(&dev_priv->drm, !r->enable))
34378c2ecf20Sopenharmony_ci			continue;
34388c2ecf20Sopenharmony_ci
34398c2ecf20Sopenharmony_ci		results->wm_pipe[pipe] =
34408c2ecf20Sopenharmony_ci			(r->pri_val << WM0_PIPE_PLANE_SHIFT) |
34418c2ecf20Sopenharmony_ci			(r->spr_val << WM0_PIPE_SPRITE_SHIFT) |
34428c2ecf20Sopenharmony_ci			r->cur_val;
34438c2ecf20Sopenharmony_ci	}
34448c2ecf20Sopenharmony_ci}
34458c2ecf20Sopenharmony_ci
34468c2ecf20Sopenharmony_ci/* Find the result with the highest level enabled. Check for enable_fbc_wm in
34478c2ecf20Sopenharmony_ci * case both are at the same level. Prefer r1 in case they're the same. */
34488c2ecf20Sopenharmony_cistatic struct intel_pipe_wm *
34498c2ecf20Sopenharmony_ciilk_find_best_result(struct drm_i915_private *dev_priv,
34508c2ecf20Sopenharmony_ci		     struct intel_pipe_wm *r1,
34518c2ecf20Sopenharmony_ci		     struct intel_pipe_wm *r2)
34528c2ecf20Sopenharmony_ci{
34538c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
34548c2ecf20Sopenharmony_ci	int level1 = 0, level2 = 0;
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_ci	for (level = 1; level <= max_level; level++) {
34578c2ecf20Sopenharmony_ci		if (r1->wm[level].enable)
34588c2ecf20Sopenharmony_ci			level1 = level;
34598c2ecf20Sopenharmony_ci		if (r2->wm[level].enable)
34608c2ecf20Sopenharmony_ci			level2 = level;
34618c2ecf20Sopenharmony_ci	}
34628c2ecf20Sopenharmony_ci
34638c2ecf20Sopenharmony_ci	if (level1 == level2) {
34648c2ecf20Sopenharmony_ci		if (r2->fbc_wm_enabled && !r1->fbc_wm_enabled)
34658c2ecf20Sopenharmony_ci			return r2;
34668c2ecf20Sopenharmony_ci		else
34678c2ecf20Sopenharmony_ci			return r1;
34688c2ecf20Sopenharmony_ci	} else if (level1 > level2) {
34698c2ecf20Sopenharmony_ci		return r1;
34708c2ecf20Sopenharmony_ci	} else {
34718c2ecf20Sopenharmony_ci		return r2;
34728c2ecf20Sopenharmony_ci	}
34738c2ecf20Sopenharmony_ci}
34748c2ecf20Sopenharmony_ci
34758c2ecf20Sopenharmony_ci/* dirty bits used to track which watermarks need changes */
34768c2ecf20Sopenharmony_ci#define WM_DIRTY_PIPE(pipe) (1 << (pipe))
34778c2ecf20Sopenharmony_ci#define WM_DIRTY_LP(wm_lp) (1 << (15 + (wm_lp)))
34788c2ecf20Sopenharmony_ci#define WM_DIRTY_LP_ALL (WM_DIRTY_LP(1) | WM_DIRTY_LP(2) | WM_DIRTY_LP(3))
34798c2ecf20Sopenharmony_ci#define WM_DIRTY_FBC (1 << 24)
34808c2ecf20Sopenharmony_ci#define WM_DIRTY_DDB (1 << 25)
34818c2ecf20Sopenharmony_ci
34828c2ecf20Sopenharmony_cistatic unsigned int ilk_compute_wm_dirty(struct drm_i915_private *dev_priv,
34838c2ecf20Sopenharmony_ci					 const struct ilk_wm_values *old,
34848c2ecf20Sopenharmony_ci					 const struct ilk_wm_values *new)
34858c2ecf20Sopenharmony_ci{
34868c2ecf20Sopenharmony_ci	unsigned int dirty = 0;
34878c2ecf20Sopenharmony_ci	enum pipe pipe;
34888c2ecf20Sopenharmony_ci	int wm_lp;
34898c2ecf20Sopenharmony_ci
34908c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
34918c2ecf20Sopenharmony_ci		if (old->wm_pipe[pipe] != new->wm_pipe[pipe]) {
34928c2ecf20Sopenharmony_ci			dirty |= WM_DIRTY_PIPE(pipe);
34938c2ecf20Sopenharmony_ci			/* Must disable LP1+ watermarks too */
34948c2ecf20Sopenharmony_ci			dirty |= WM_DIRTY_LP_ALL;
34958c2ecf20Sopenharmony_ci		}
34968c2ecf20Sopenharmony_ci	}
34978c2ecf20Sopenharmony_ci
34988c2ecf20Sopenharmony_ci	if (old->enable_fbc_wm != new->enable_fbc_wm) {
34998c2ecf20Sopenharmony_ci		dirty |= WM_DIRTY_FBC;
35008c2ecf20Sopenharmony_ci		/* Must disable LP1+ watermarks too */
35018c2ecf20Sopenharmony_ci		dirty |= WM_DIRTY_LP_ALL;
35028c2ecf20Sopenharmony_ci	}
35038c2ecf20Sopenharmony_ci
35048c2ecf20Sopenharmony_ci	if (old->partitioning != new->partitioning) {
35058c2ecf20Sopenharmony_ci		dirty |= WM_DIRTY_DDB;
35068c2ecf20Sopenharmony_ci		/* Must disable LP1+ watermarks too */
35078c2ecf20Sopenharmony_ci		dirty |= WM_DIRTY_LP_ALL;
35088c2ecf20Sopenharmony_ci	}
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci	/* LP1+ watermarks already deemed dirty, no need to continue */
35118c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP_ALL)
35128c2ecf20Sopenharmony_ci		return dirty;
35138c2ecf20Sopenharmony_ci
35148c2ecf20Sopenharmony_ci	/* Find the lowest numbered LP1+ watermark in need of an update... */
35158c2ecf20Sopenharmony_ci	for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
35168c2ecf20Sopenharmony_ci		if (old->wm_lp[wm_lp - 1] != new->wm_lp[wm_lp - 1] ||
35178c2ecf20Sopenharmony_ci		    old->wm_lp_spr[wm_lp - 1] != new->wm_lp_spr[wm_lp - 1])
35188c2ecf20Sopenharmony_ci			break;
35198c2ecf20Sopenharmony_ci	}
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_ci	/* ...and mark it and all higher numbered LP1+ watermarks as dirty */
35228c2ecf20Sopenharmony_ci	for (; wm_lp <= 3; wm_lp++)
35238c2ecf20Sopenharmony_ci		dirty |= WM_DIRTY_LP(wm_lp);
35248c2ecf20Sopenharmony_ci
35258c2ecf20Sopenharmony_ci	return dirty;
35268c2ecf20Sopenharmony_ci}
35278c2ecf20Sopenharmony_ci
35288c2ecf20Sopenharmony_cistatic bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv,
35298c2ecf20Sopenharmony_ci			       unsigned int dirty)
35308c2ecf20Sopenharmony_ci{
35318c2ecf20Sopenharmony_ci	struct ilk_wm_values *previous = &dev_priv->wm.hw;
35328c2ecf20Sopenharmony_ci	bool changed = false;
35338c2ecf20Sopenharmony_ci
35348c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) {
35358c2ecf20Sopenharmony_ci		previous->wm_lp[2] &= ~WM1_LP_SR_EN;
35368c2ecf20Sopenharmony_ci		I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]);
35378c2ecf20Sopenharmony_ci		changed = true;
35388c2ecf20Sopenharmony_ci	}
35398c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) {
35408c2ecf20Sopenharmony_ci		previous->wm_lp[1] &= ~WM1_LP_SR_EN;
35418c2ecf20Sopenharmony_ci		I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]);
35428c2ecf20Sopenharmony_ci		changed = true;
35438c2ecf20Sopenharmony_ci	}
35448c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) {
35458c2ecf20Sopenharmony_ci		previous->wm_lp[0] &= ~WM1_LP_SR_EN;
35468c2ecf20Sopenharmony_ci		I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]);
35478c2ecf20Sopenharmony_ci		changed = true;
35488c2ecf20Sopenharmony_ci	}
35498c2ecf20Sopenharmony_ci
35508c2ecf20Sopenharmony_ci	/*
35518c2ecf20Sopenharmony_ci	 * Don't touch WM1S_LP_EN here.
35528c2ecf20Sopenharmony_ci	 * Doing so could cause underruns.
35538c2ecf20Sopenharmony_ci	 */
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	return changed;
35568c2ecf20Sopenharmony_ci}
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci/*
35598c2ecf20Sopenharmony_ci * The spec says we shouldn't write when we don't need, because every write
35608c2ecf20Sopenharmony_ci * causes WMs to be re-evaluated, expending some power.
35618c2ecf20Sopenharmony_ci */
35628c2ecf20Sopenharmony_cistatic void ilk_write_wm_values(struct drm_i915_private *dev_priv,
35638c2ecf20Sopenharmony_ci				struct ilk_wm_values *results)
35648c2ecf20Sopenharmony_ci{
35658c2ecf20Sopenharmony_ci	struct ilk_wm_values *previous = &dev_priv->wm.hw;
35668c2ecf20Sopenharmony_ci	unsigned int dirty;
35678c2ecf20Sopenharmony_ci	u32 val;
35688c2ecf20Sopenharmony_ci
35698c2ecf20Sopenharmony_ci	dirty = ilk_compute_wm_dirty(dev_priv, previous, results);
35708c2ecf20Sopenharmony_ci	if (!dirty)
35718c2ecf20Sopenharmony_ci		return;
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_ci	_ilk_disable_lp_wm(dev_priv, dirty);
35748c2ecf20Sopenharmony_ci
35758c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_PIPE(PIPE_A))
35768c2ecf20Sopenharmony_ci		I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
35778c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_PIPE(PIPE_B))
35788c2ecf20Sopenharmony_ci		I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]);
35798c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_PIPE(PIPE_C))
35808c2ecf20Sopenharmony_ci		I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]);
35818c2ecf20Sopenharmony_ci
35828c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_DDB) {
35838c2ecf20Sopenharmony_ci		if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
35848c2ecf20Sopenharmony_ci			val = I915_READ(WM_MISC);
35858c2ecf20Sopenharmony_ci			if (results->partitioning == INTEL_DDB_PART_1_2)
35868c2ecf20Sopenharmony_ci				val &= ~WM_MISC_DATA_PARTITION_5_6;
35878c2ecf20Sopenharmony_ci			else
35888c2ecf20Sopenharmony_ci				val |= WM_MISC_DATA_PARTITION_5_6;
35898c2ecf20Sopenharmony_ci			I915_WRITE(WM_MISC, val);
35908c2ecf20Sopenharmony_ci		} else {
35918c2ecf20Sopenharmony_ci			val = I915_READ(DISP_ARB_CTL2);
35928c2ecf20Sopenharmony_ci			if (results->partitioning == INTEL_DDB_PART_1_2)
35938c2ecf20Sopenharmony_ci				val &= ~DISP_DATA_PARTITION_5_6;
35948c2ecf20Sopenharmony_ci			else
35958c2ecf20Sopenharmony_ci				val |= DISP_DATA_PARTITION_5_6;
35968c2ecf20Sopenharmony_ci			I915_WRITE(DISP_ARB_CTL2, val);
35978c2ecf20Sopenharmony_ci		}
35988c2ecf20Sopenharmony_ci	}
35998c2ecf20Sopenharmony_ci
36008c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_FBC) {
36018c2ecf20Sopenharmony_ci		val = I915_READ(DISP_ARB_CTL);
36028c2ecf20Sopenharmony_ci		if (results->enable_fbc_wm)
36038c2ecf20Sopenharmony_ci			val &= ~DISP_FBC_WM_DIS;
36048c2ecf20Sopenharmony_ci		else
36058c2ecf20Sopenharmony_ci			val |= DISP_FBC_WM_DIS;
36068c2ecf20Sopenharmony_ci		I915_WRITE(DISP_ARB_CTL, val);
36078c2ecf20Sopenharmony_ci	}
36088c2ecf20Sopenharmony_ci
36098c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP(1) &&
36108c2ecf20Sopenharmony_ci	    previous->wm_lp_spr[0] != results->wm_lp_spr[0])
36118c2ecf20Sopenharmony_ci		I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]);
36128c2ecf20Sopenharmony_ci
36138c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 7) {
36148c2ecf20Sopenharmony_ci		if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1])
36158c2ecf20Sopenharmony_ci			I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]);
36168c2ecf20Sopenharmony_ci		if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2])
36178c2ecf20Sopenharmony_ci			I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]);
36188c2ecf20Sopenharmony_ci	}
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != results->wm_lp[0])
36218c2ecf20Sopenharmony_ci		I915_WRITE(WM1_LP_ILK, results->wm_lp[0]);
36228c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != results->wm_lp[1])
36238c2ecf20Sopenharmony_ci		I915_WRITE(WM2_LP_ILK, results->wm_lp[1]);
36248c2ecf20Sopenharmony_ci	if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != results->wm_lp[2])
36258c2ecf20Sopenharmony_ci		I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
36268c2ecf20Sopenharmony_ci
36278c2ecf20Sopenharmony_ci	dev_priv->wm.hw = *results;
36288c2ecf20Sopenharmony_ci}
36298c2ecf20Sopenharmony_ci
36308c2ecf20Sopenharmony_cibool ilk_disable_lp_wm(struct drm_i915_private *dev_priv)
36318c2ecf20Sopenharmony_ci{
36328c2ecf20Sopenharmony_ci	return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
36338c2ecf20Sopenharmony_ci}
36348c2ecf20Sopenharmony_ci
36358c2ecf20Sopenharmony_ciu8 intel_enabled_dbuf_slices_mask(struct drm_i915_private *dev_priv)
36368c2ecf20Sopenharmony_ci{
36378c2ecf20Sopenharmony_ci	int i;
36388c2ecf20Sopenharmony_ci	int max_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
36398c2ecf20Sopenharmony_ci	u8 enabled_slices_mask = 0;
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_ci	for (i = 0; i < max_slices; i++) {
36428c2ecf20Sopenharmony_ci		if (I915_READ(DBUF_CTL_S(i)) & DBUF_POWER_STATE)
36438c2ecf20Sopenharmony_ci			enabled_slices_mask |= BIT(i);
36448c2ecf20Sopenharmony_ci	}
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	return enabled_slices_mask;
36478c2ecf20Sopenharmony_ci}
36488c2ecf20Sopenharmony_ci
36498c2ecf20Sopenharmony_ci/*
36508c2ecf20Sopenharmony_ci * FIXME: We still don't have the proper code detect if we need to apply the WA,
36518c2ecf20Sopenharmony_ci * so assume we'll always need it in order to avoid underruns.
36528c2ecf20Sopenharmony_ci */
36538c2ecf20Sopenharmony_cistatic bool skl_needs_memory_bw_wa(struct drm_i915_private *dev_priv)
36548c2ecf20Sopenharmony_ci{
36558c2ecf20Sopenharmony_ci	return IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv);
36568c2ecf20Sopenharmony_ci}
36578c2ecf20Sopenharmony_ci
36588c2ecf20Sopenharmony_cistatic bool
36598c2ecf20Sopenharmony_ciintel_has_sagv(struct drm_i915_private *dev_priv)
36608c2ecf20Sopenharmony_ci{
36618c2ecf20Sopenharmony_ci	return (IS_GEN9_BC(dev_priv) || INTEL_GEN(dev_priv) >= 10) &&
36628c2ecf20Sopenharmony_ci		dev_priv->sagv_status != I915_SAGV_NOT_CONTROLLED;
36638c2ecf20Sopenharmony_ci}
36648c2ecf20Sopenharmony_ci
36658c2ecf20Sopenharmony_cistatic void
36668c2ecf20Sopenharmony_ciskl_setup_sagv_block_time(struct drm_i915_private *dev_priv)
36678c2ecf20Sopenharmony_ci{
36688c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 12) {
36698c2ecf20Sopenharmony_ci		u32 val = 0;
36708c2ecf20Sopenharmony_ci		int ret;
36718c2ecf20Sopenharmony_ci
36728c2ecf20Sopenharmony_ci		ret = sandybridge_pcode_read(dev_priv,
36738c2ecf20Sopenharmony_ci					     GEN12_PCODE_READ_SAGV_BLOCK_TIME_US,
36748c2ecf20Sopenharmony_ci					     &val, NULL);
36758c2ecf20Sopenharmony_ci		if (!ret) {
36768c2ecf20Sopenharmony_ci			dev_priv->sagv_block_time_us = val;
36778c2ecf20Sopenharmony_ci			return;
36788c2ecf20Sopenharmony_ci		}
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "Couldn't read SAGV block time!\n");
36818c2ecf20Sopenharmony_ci	} else if (IS_GEN(dev_priv, 11)) {
36828c2ecf20Sopenharmony_ci		dev_priv->sagv_block_time_us = 10;
36838c2ecf20Sopenharmony_ci		return;
36848c2ecf20Sopenharmony_ci	} else if (IS_GEN(dev_priv, 10)) {
36858c2ecf20Sopenharmony_ci		dev_priv->sagv_block_time_us = 20;
36868c2ecf20Sopenharmony_ci		return;
36878c2ecf20Sopenharmony_ci	} else if (IS_GEN(dev_priv, 9)) {
36888c2ecf20Sopenharmony_ci		dev_priv->sagv_block_time_us = 30;
36898c2ecf20Sopenharmony_ci		return;
36908c2ecf20Sopenharmony_ci	} else {
36918c2ecf20Sopenharmony_ci		MISSING_CASE(INTEL_GEN(dev_priv));
36928c2ecf20Sopenharmony_ci	}
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_ci	/* Default to an unusable block time */
36958c2ecf20Sopenharmony_ci	dev_priv->sagv_block_time_us = -1;
36968c2ecf20Sopenharmony_ci}
36978c2ecf20Sopenharmony_ci
36988c2ecf20Sopenharmony_ci/*
36998c2ecf20Sopenharmony_ci * SAGV dynamically adjusts the system agent voltage and clock frequencies
37008c2ecf20Sopenharmony_ci * depending on power and performance requirements. The display engine access
37018c2ecf20Sopenharmony_ci * to system memory is blocked during the adjustment time. Because of the
37028c2ecf20Sopenharmony_ci * blocking time, having this enabled can cause full system hangs and/or pipe
37038c2ecf20Sopenharmony_ci * underruns if we don't meet all of the following requirements:
37048c2ecf20Sopenharmony_ci *
37058c2ecf20Sopenharmony_ci *  - <= 1 pipe enabled
37068c2ecf20Sopenharmony_ci *  - All planes can enable watermarks for latencies >= SAGV engine block time
37078c2ecf20Sopenharmony_ci *  - We're not using an interlaced display configuration
37088c2ecf20Sopenharmony_ci */
37098c2ecf20Sopenharmony_ciint
37108c2ecf20Sopenharmony_ciintel_enable_sagv(struct drm_i915_private *dev_priv)
37118c2ecf20Sopenharmony_ci{
37128c2ecf20Sopenharmony_ci	int ret;
37138c2ecf20Sopenharmony_ci
37148c2ecf20Sopenharmony_ci	if (!intel_has_sagv(dev_priv))
37158c2ecf20Sopenharmony_ci		return 0;
37168c2ecf20Sopenharmony_ci
37178c2ecf20Sopenharmony_ci	if (dev_priv->sagv_status == I915_SAGV_ENABLED)
37188c2ecf20Sopenharmony_ci		return 0;
37198c2ecf20Sopenharmony_ci
37208c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "Enabling SAGV\n");
37218c2ecf20Sopenharmony_ci	ret = sandybridge_pcode_write(dev_priv, GEN9_PCODE_SAGV_CONTROL,
37228c2ecf20Sopenharmony_ci				      GEN9_SAGV_ENABLE);
37238c2ecf20Sopenharmony_ci
37248c2ecf20Sopenharmony_ci	/* We don't need to wait for SAGV when enabling */
37258c2ecf20Sopenharmony_ci
37268c2ecf20Sopenharmony_ci	/*
37278c2ecf20Sopenharmony_ci	 * Some skl systems, pre-release machines in particular,
37288c2ecf20Sopenharmony_ci	 * don't actually have SAGV.
37298c2ecf20Sopenharmony_ci	 */
37308c2ecf20Sopenharmony_ci	if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) {
37318c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "No SAGV found on system, ignoring\n");
37328c2ecf20Sopenharmony_ci		dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED;
37338c2ecf20Sopenharmony_ci		return 0;
37348c2ecf20Sopenharmony_ci	} else if (ret < 0) {
37358c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm, "Failed to enable SAGV\n");
37368c2ecf20Sopenharmony_ci		return ret;
37378c2ecf20Sopenharmony_ci	}
37388c2ecf20Sopenharmony_ci
37398c2ecf20Sopenharmony_ci	dev_priv->sagv_status = I915_SAGV_ENABLED;
37408c2ecf20Sopenharmony_ci	return 0;
37418c2ecf20Sopenharmony_ci}
37428c2ecf20Sopenharmony_ci
37438c2ecf20Sopenharmony_ciint
37448c2ecf20Sopenharmony_ciintel_disable_sagv(struct drm_i915_private *dev_priv)
37458c2ecf20Sopenharmony_ci{
37468c2ecf20Sopenharmony_ci	int ret;
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_ci	if (!intel_has_sagv(dev_priv))
37498c2ecf20Sopenharmony_ci		return 0;
37508c2ecf20Sopenharmony_ci
37518c2ecf20Sopenharmony_ci	if (dev_priv->sagv_status == I915_SAGV_DISABLED)
37528c2ecf20Sopenharmony_ci		return 0;
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "Disabling SAGV\n");
37558c2ecf20Sopenharmony_ci	/* bspec says to keep retrying for at least 1 ms */
37568c2ecf20Sopenharmony_ci	ret = skl_pcode_request(dev_priv, GEN9_PCODE_SAGV_CONTROL,
37578c2ecf20Sopenharmony_ci				GEN9_SAGV_DISABLE,
37588c2ecf20Sopenharmony_ci				GEN9_SAGV_IS_DISABLED, GEN9_SAGV_IS_DISABLED,
37598c2ecf20Sopenharmony_ci				1);
37608c2ecf20Sopenharmony_ci	/*
37618c2ecf20Sopenharmony_ci	 * Some skl systems, pre-release machines in particular,
37628c2ecf20Sopenharmony_ci	 * don't actually have SAGV.
37638c2ecf20Sopenharmony_ci	 */
37648c2ecf20Sopenharmony_ci	if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) {
37658c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "No SAGV found on system, ignoring\n");
37668c2ecf20Sopenharmony_ci		dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED;
37678c2ecf20Sopenharmony_ci		return 0;
37688c2ecf20Sopenharmony_ci	} else if (ret < 0) {
37698c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm, "Failed to disable SAGV (%d)\n", ret);
37708c2ecf20Sopenharmony_ci		return ret;
37718c2ecf20Sopenharmony_ci	}
37728c2ecf20Sopenharmony_ci
37738c2ecf20Sopenharmony_ci	dev_priv->sagv_status = I915_SAGV_DISABLED;
37748c2ecf20Sopenharmony_ci	return 0;
37758c2ecf20Sopenharmony_ci}
37768c2ecf20Sopenharmony_ci
37778c2ecf20Sopenharmony_civoid intel_sagv_pre_plane_update(struct intel_atomic_state *state)
37788c2ecf20Sopenharmony_ci{
37798c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
37808c2ecf20Sopenharmony_ci	const struct intel_bw_state *new_bw_state;
37818c2ecf20Sopenharmony_ci	const struct intel_bw_state *old_bw_state;
37828c2ecf20Sopenharmony_ci	u32 new_mask = 0;
37838c2ecf20Sopenharmony_ci
37848c2ecf20Sopenharmony_ci	/*
37858c2ecf20Sopenharmony_ci	 * Just return if we can't control SAGV or don't have it.
37868c2ecf20Sopenharmony_ci	 * This is different from situation when we have SAGV but just can't
37878c2ecf20Sopenharmony_ci	 * afford it due to DBuf limitation - in case if SAGV is completely
37888c2ecf20Sopenharmony_ci	 * disabled in a BIOS, we are not even allowed to send a PCode request,
37898c2ecf20Sopenharmony_ci	 * as it will throw an error. So have to check it here.
37908c2ecf20Sopenharmony_ci	 */
37918c2ecf20Sopenharmony_ci	if (!intel_has_sagv(dev_priv))
37928c2ecf20Sopenharmony_ci		return;
37938c2ecf20Sopenharmony_ci
37948c2ecf20Sopenharmony_ci	new_bw_state = intel_atomic_get_new_bw_state(state);
37958c2ecf20Sopenharmony_ci	if (!new_bw_state)
37968c2ecf20Sopenharmony_ci		return;
37978c2ecf20Sopenharmony_ci
37988c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) < 11 && !intel_can_enable_sagv(dev_priv, new_bw_state)) {
37998c2ecf20Sopenharmony_ci		intel_disable_sagv(dev_priv);
38008c2ecf20Sopenharmony_ci		return;
38018c2ecf20Sopenharmony_ci	}
38028c2ecf20Sopenharmony_ci
38038c2ecf20Sopenharmony_ci	old_bw_state = intel_atomic_get_old_bw_state(state);
38048c2ecf20Sopenharmony_ci	/*
38058c2ecf20Sopenharmony_ci	 * Nothing to mask
38068c2ecf20Sopenharmony_ci	 */
38078c2ecf20Sopenharmony_ci	if (new_bw_state->qgv_points_mask == old_bw_state->qgv_points_mask)
38088c2ecf20Sopenharmony_ci		return;
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci	new_mask = old_bw_state->qgv_points_mask | new_bw_state->qgv_points_mask;
38118c2ecf20Sopenharmony_ci
38128c2ecf20Sopenharmony_ci	/*
38138c2ecf20Sopenharmony_ci	 * If new mask is zero - means there is nothing to mask,
38148c2ecf20Sopenharmony_ci	 * we can only unmask, which should be done in unmask.
38158c2ecf20Sopenharmony_ci	 */
38168c2ecf20Sopenharmony_ci	if (!new_mask)
38178c2ecf20Sopenharmony_ci		return;
38188c2ecf20Sopenharmony_ci
38198c2ecf20Sopenharmony_ci	/*
38208c2ecf20Sopenharmony_ci	 * Restrict required qgv points before updating the configuration.
38218c2ecf20Sopenharmony_ci	 * According to BSpec we can't mask and unmask qgv points at the same
38228c2ecf20Sopenharmony_ci	 * time. Also masking should be done before updating the configuration
38238c2ecf20Sopenharmony_ci	 * and unmasking afterwards.
38248c2ecf20Sopenharmony_ci	 */
38258c2ecf20Sopenharmony_ci	icl_pcode_restrict_qgv_points(dev_priv, new_mask);
38268c2ecf20Sopenharmony_ci}
38278c2ecf20Sopenharmony_ci
38288c2ecf20Sopenharmony_civoid intel_sagv_post_plane_update(struct intel_atomic_state *state)
38298c2ecf20Sopenharmony_ci{
38308c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
38318c2ecf20Sopenharmony_ci	const struct intel_bw_state *new_bw_state;
38328c2ecf20Sopenharmony_ci	const struct intel_bw_state *old_bw_state;
38338c2ecf20Sopenharmony_ci	u32 new_mask = 0;
38348c2ecf20Sopenharmony_ci
38358c2ecf20Sopenharmony_ci	/*
38368c2ecf20Sopenharmony_ci	 * Just return if we can't control SAGV or don't have it.
38378c2ecf20Sopenharmony_ci	 * This is different from situation when we have SAGV but just can't
38388c2ecf20Sopenharmony_ci	 * afford it due to DBuf limitation - in case if SAGV is completely
38398c2ecf20Sopenharmony_ci	 * disabled in a BIOS, we are not even allowed to send a PCode request,
38408c2ecf20Sopenharmony_ci	 * as it will throw an error. So have to check it here.
38418c2ecf20Sopenharmony_ci	 */
38428c2ecf20Sopenharmony_ci	if (!intel_has_sagv(dev_priv))
38438c2ecf20Sopenharmony_ci		return;
38448c2ecf20Sopenharmony_ci
38458c2ecf20Sopenharmony_ci	new_bw_state = intel_atomic_get_new_bw_state(state);
38468c2ecf20Sopenharmony_ci	if (!new_bw_state)
38478c2ecf20Sopenharmony_ci		return;
38488c2ecf20Sopenharmony_ci
38498c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) < 11 && intel_can_enable_sagv(dev_priv, new_bw_state)) {
38508c2ecf20Sopenharmony_ci		intel_enable_sagv(dev_priv);
38518c2ecf20Sopenharmony_ci		return;
38528c2ecf20Sopenharmony_ci	}
38538c2ecf20Sopenharmony_ci
38548c2ecf20Sopenharmony_ci	old_bw_state = intel_atomic_get_old_bw_state(state);
38558c2ecf20Sopenharmony_ci	/*
38568c2ecf20Sopenharmony_ci	 * Nothing to unmask
38578c2ecf20Sopenharmony_ci	 */
38588c2ecf20Sopenharmony_ci	if (new_bw_state->qgv_points_mask == old_bw_state->qgv_points_mask)
38598c2ecf20Sopenharmony_ci		return;
38608c2ecf20Sopenharmony_ci
38618c2ecf20Sopenharmony_ci	new_mask = new_bw_state->qgv_points_mask;
38628c2ecf20Sopenharmony_ci
38638c2ecf20Sopenharmony_ci	/*
38648c2ecf20Sopenharmony_ci	 * Allow required qgv points after updating the configuration.
38658c2ecf20Sopenharmony_ci	 * According to BSpec we can't mask and unmask qgv points at the same
38668c2ecf20Sopenharmony_ci	 * time. Also masking should be done before updating the configuration
38678c2ecf20Sopenharmony_ci	 * and unmasking afterwards.
38688c2ecf20Sopenharmony_ci	 */
38698c2ecf20Sopenharmony_ci	icl_pcode_restrict_qgv_points(dev_priv, new_mask);
38708c2ecf20Sopenharmony_ci}
38718c2ecf20Sopenharmony_ci
38728c2ecf20Sopenharmony_cistatic bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state)
38738c2ecf20Sopenharmony_ci{
38748c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
38758c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
38768c2ecf20Sopenharmony_ci	struct intel_plane *plane;
38778c2ecf20Sopenharmony_ci	const struct intel_plane_state *plane_state;
38788c2ecf20Sopenharmony_ci	int level, latency;
38798c2ecf20Sopenharmony_ci
38808c2ecf20Sopenharmony_ci	if (!intel_has_sagv(dev_priv))
38818c2ecf20Sopenharmony_ci		return false;
38828c2ecf20Sopenharmony_ci
38838c2ecf20Sopenharmony_ci	if (!crtc_state->hw.active)
38848c2ecf20Sopenharmony_ci		return true;
38858c2ecf20Sopenharmony_ci
38868c2ecf20Sopenharmony_ci	if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
38878c2ecf20Sopenharmony_ci		return false;
38888c2ecf20Sopenharmony_ci
38898c2ecf20Sopenharmony_ci	intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
38908c2ecf20Sopenharmony_ci		const struct skl_plane_wm *wm =
38918c2ecf20Sopenharmony_ci			&crtc_state->wm.skl.optimal.planes[plane->id];
38928c2ecf20Sopenharmony_ci
38938c2ecf20Sopenharmony_ci		/* Skip this plane if it's not enabled */
38948c2ecf20Sopenharmony_ci		if (!wm->wm[0].plane_en)
38958c2ecf20Sopenharmony_ci			continue;
38968c2ecf20Sopenharmony_ci
38978c2ecf20Sopenharmony_ci		/* Find the highest enabled wm level for this plane */
38988c2ecf20Sopenharmony_ci		for (level = ilk_wm_max_level(dev_priv);
38998c2ecf20Sopenharmony_ci		     !wm->wm[level].plane_en; --level)
39008c2ecf20Sopenharmony_ci		     { }
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_ci		latency = dev_priv->wm.skl_latency[level];
39038c2ecf20Sopenharmony_ci
39048c2ecf20Sopenharmony_ci		if (skl_needs_memory_bw_wa(dev_priv) &&
39058c2ecf20Sopenharmony_ci		    plane_state->uapi.fb->modifier ==
39068c2ecf20Sopenharmony_ci		    I915_FORMAT_MOD_X_TILED)
39078c2ecf20Sopenharmony_ci			latency += 15;
39088c2ecf20Sopenharmony_ci
39098c2ecf20Sopenharmony_ci		/*
39108c2ecf20Sopenharmony_ci		 * If any of the planes on this pipe don't enable wm levels that
39118c2ecf20Sopenharmony_ci		 * incur memory latencies higher than sagv_block_time_us we
39128c2ecf20Sopenharmony_ci		 * can't enable SAGV.
39138c2ecf20Sopenharmony_ci		 */
39148c2ecf20Sopenharmony_ci		if (latency < dev_priv->sagv_block_time_us)
39158c2ecf20Sopenharmony_ci			return false;
39168c2ecf20Sopenharmony_ci	}
39178c2ecf20Sopenharmony_ci
39188c2ecf20Sopenharmony_ci	return true;
39198c2ecf20Sopenharmony_ci}
39208c2ecf20Sopenharmony_ci
39218c2ecf20Sopenharmony_cistatic bool tgl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state)
39228c2ecf20Sopenharmony_ci{
39238c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
39248c2ecf20Sopenharmony_ci	enum plane_id plane_id;
39258c2ecf20Sopenharmony_ci
39268c2ecf20Sopenharmony_ci	if (!crtc_state->hw.active)
39278c2ecf20Sopenharmony_ci		return true;
39288c2ecf20Sopenharmony_ci
39298c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
39308c2ecf20Sopenharmony_ci		const struct skl_ddb_entry *plane_alloc =
39318c2ecf20Sopenharmony_ci			&crtc_state->wm.skl.plane_ddb_y[plane_id];
39328c2ecf20Sopenharmony_ci		const struct skl_plane_wm *wm =
39338c2ecf20Sopenharmony_ci			&crtc_state->wm.skl.optimal.planes[plane_id];
39348c2ecf20Sopenharmony_ci
39358c2ecf20Sopenharmony_ci		if (skl_ddb_entry_size(plane_alloc) < wm->sagv_wm0.min_ddb_alloc)
39368c2ecf20Sopenharmony_ci			return false;
39378c2ecf20Sopenharmony_ci	}
39388c2ecf20Sopenharmony_ci
39398c2ecf20Sopenharmony_ci	return true;
39408c2ecf20Sopenharmony_ci}
39418c2ecf20Sopenharmony_ci
39428c2ecf20Sopenharmony_cistatic bool intel_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state)
39438c2ecf20Sopenharmony_ci{
39448c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
39458c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
39468c2ecf20Sopenharmony_ci
39478c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 12)
39488c2ecf20Sopenharmony_ci		return tgl_crtc_can_enable_sagv(crtc_state);
39498c2ecf20Sopenharmony_ci	else
39508c2ecf20Sopenharmony_ci		return skl_crtc_can_enable_sagv(crtc_state);
39518c2ecf20Sopenharmony_ci}
39528c2ecf20Sopenharmony_ci
39538c2ecf20Sopenharmony_cibool intel_can_enable_sagv(struct drm_i915_private *dev_priv,
39548c2ecf20Sopenharmony_ci			   const struct intel_bw_state *bw_state)
39558c2ecf20Sopenharmony_ci{
39568c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) < 11 &&
39578c2ecf20Sopenharmony_ci	    bw_state->active_pipes && !is_power_of_2(bw_state->active_pipes))
39588c2ecf20Sopenharmony_ci		return false;
39598c2ecf20Sopenharmony_ci
39608c2ecf20Sopenharmony_ci	return bw_state->pipe_sagv_reject == 0;
39618c2ecf20Sopenharmony_ci}
39628c2ecf20Sopenharmony_ci
39638c2ecf20Sopenharmony_cistatic int intel_compute_sagv_mask(struct intel_atomic_state *state)
39648c2ecf20Sopenharmony_ci{
39658c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
39668c2ecf20Sopenharmony_ci	int ret;
39678c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
39688c2ecf20Sopenharmony_ci	struct intel_crtc_state *new_crtc_state;
39698c2ecf20Sopenharmony_ci	struct intel_bw_state *new_bw_state = NULL;
39708c2ecf20Sopenharmony_ci	const struct intel_bw_state *old_bw_state = NULL;
39718c2ecf20Sopenharmony_ci	int i;
39728c2ecf20Sopenharmony_ci
39738c2ecf20Sopenharmony_ci	for_each_new_intel_crtc_in_state(state, crtc,
39748c2ecf20Sopenharmony_ci					 new_crtc_state, i) {
39758c2ecf20Sopenharmony_ci		new_bw_state = intel_atomic_get_bw_state(state);
39768c2ecf20Sopenharmony_ci		if (IS_ERR(new_bw_state))
39778c2ecf20Sopenharmony_ci			return PTR_ERR(new_bw_state);
39788c2ecf20Sopenharmony_ci
39798c2ecf20Sopenharmony_ci		old_bw_state = intel_atomic_get_old_bw_state(state);
39808c2ecf20Sopenharmony_ci
39818c2ecf20Sopenharmony_ci		if (intel_crtc_can_enable_sagv(new_crtc_state))
39828c2ecf20Sopenharmony_ci			new_bw_state->pipe_sagv_reject &= ~BIT(crtc->pipe);
39838c2ecf20Sopenharmony_ci		else
39848c2ecf20Sopenharmony_ci			new_bw_state->pipe_sagv_reject |= BIT(crtc->pipe);
39858c2ecf20Sopenharmony_ci	}
39868c2ecf20Sopenharmony_ci
39878c2ecf20Sopenharmony_ci	if (!new_bw_state)
39888c2ecf20Sopenharmony_ci		return 0;
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_ci	new_bw_state->active_pipes =
39918c2ecf20Sopenharmony_ci		intel_calc_active_pipes(state, old_bw_state->active_pipes);
39928c2ecf20Sopenharmony_ci
39938c2ecf20Sopenharmony_ci	if (new_bw_state->active_pipes != old_bw_state->active_pipes) {
39948c2ecf20Sopenharmony_ci		ret = intel_atomic_lock_global_state(&new_bw_state->base);
39958c2ecf20Sopenharmony_ci		if (ret)
39968c2ecf20Sopenharmony_ci			return ret;
39978c2ecf20Sopenharmony_ci	}
39988c2ecf20Sopenharmony_ci
39998c2ecf20Sopenharmony_ci	if (intel_can_enable_sagv(dev_priv, new_bw_state) !=
40008c2ecf20Sopenharmony_ci	    intel_can_enable_sagv(dev_priv, old_bw_state)) {
40018c2ecf20Sopenharmony_ci		ret = intel_atomic_serialize_global_state(&new_bw_state->base);
40028c2ecf20Sopenharmony_ci		if (ret)
40038c2ecf20Sopenharmony_ci			return ret;
40048c2ecf20Sopenharmony_ci	} else if (new_bw_state->pipe_sagv_reject != old_bw_state->pipe_sagv_reject) {
40058c2ecf20Sopenharmony_ci		ret = intel_atomic_lock_global_state(&new_bw_state->base);
40068c2ecf20Sopenharmony_ci		if (ret)
40078c2ecf20Sopenharmony_ci			return ret;
40088c2ecf20Sopenharmony_ci	}
40098c2ecf20Sopenharmony_ci
40108c2ecf20Sopenharmony_ci	for_each_new_intel_crtc_in_state(state, crtc,
40118c2ecf20Sopenharmony_ci					 new_crtc_state, i) {
40128c2ecf20Sopenharmony_ci		struct skl_pipe_wm *pipe_wm = &new_crtc_state->wm.skl.optimal;
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_ci		/*
40158c2ecf20Sopenharmony_ci		 * We store use_sagv_wm in the crtc state rather than relying on
40168c2ecf20Sopenharmony_ci		 * that bw state since we have no convenient way to get at the
40178c2ecf20Sopenharmony_ci		 * latter from the plane commit hooks (especially in the legacy
40188c2ecf20Sopenharmony_ci		 * cursor case)
40198c2ecf20Sopenharmony_ci		 */
40208c2ecf20Sopenharmony_ci		pipe_wm->use_sagv_wm = INTEL_GEN(dev_priv) >= 12 &&
40218c2ecf20Sopenharmony_ci				       intel_can_enable_sagv(dev_priv, new_bw_state);
40228c2ecf20Sopenharmony_ci	}
40238c2ecf20Sopenharmony_ci
40248c2ecf20Sopenharmony_ci	return 0;
40258c2ecf20Sopenharmony_ci}
40268c2ecf20Sopenharmony_ci
40278c2ecf20Sopenharmony_ci/*
40288c2ecf20Sopenharmony_ci * Calculate initial DBuf slice offset, based on slice size
40298c2ecf20Sopenharmony_ci * and mask(i.e if slice size is 1024 and second slice is enabled
40308c2ecf20Sopenharmony_ci * offset would be 1024)
40318c2ecf20Sopenharmony_ci */
40328c2ecf20Sopenharmony_cistatic unsigned int
40338c2ecf20Sopenharmony_ciicl_get_first_dbuf_slice_offset(u32 dbuf_slice_mask,
40348c2ecf20Sopenharmony_ci				u32 slice_size,
40358c2ecf20Sopenharmony_ci				u32 ddb_size)
40368c2ecf20Sopenharmony_ci{
40378c2ecf20Sopenharmony_ci	unsigned int offset = 0;
40388c2ecf20Sopenharmony_ci
40398c2ecf20Sopenharmony_ci	if (!dbuf_slice_mask)
40408c2ecf20Sopenharmony_ci		return 0;
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_ci	offset = (ffs(dbuf_slice_mask) - 1) * slice_size;
40438c2ecf20Sopenharmony_ci
40448c2ecf20Sopenharmony_ci	WARN_ON(offset >= ddb_size);
40458c2ecf20Sopenharmony_ci	return offset;
40468c2ecf20Sopenharmony_ci}
40478c2ecf20Sopenharmony_ci
40488c2ecf20Sopenharmony_ciu16 intel_get_ddb_size(struct drm_i915_private *dev_priv)
40498c2ecf20Sopenharmony_ci{
40508c2ecf20Sopenharmony_ci	u16 ddb_size = INTEL_INFO(dev_priv)->ddb_size;
40518c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, ddb_size == 0);
40528c2ecf20Sopenharmony_ci
40538c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) < 11)
40548c2ecf20Sopenharmony_ci		return ddb_size - 4; /* 4 blocks for bypass path allocation */
40558c2ecf20Sopenharmony_ci
40568c2ecf20Sopenharmony_ci	return ddb_size;
40578c2ecf20Sopenharmony_ci}
40588c2ecf20Sopenharmony_ci
40598c2ecf20Sopenharmony_ciu32 skl_ddb_dbuf_slice_mask(struct drm_i915_private *dev_priv,
40608c2ecf20Sopenharmony_ci			    const struct skl_ddb_entry *entry)
40618c2ecf20Sopenharmony_ci{
40628c2ecf20Sopenharmony_ci	u32 slice_mask = 0;
40638c2ecf20Sopenharmony_ci	u16 ddb_size = intel_get_ddb_size(dev_priv);
40648c2ecf20Sopenharmony_ci	u16 num_supported_slices = INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
40658c2ecf20Sopenharmony_ci	u16 slice_size = ddb_size / num_supported_slices;
40668c2ecf20Sopenharmony_ci	u16 start_slice;
40678c2ecf20Sopenharmony_ci	u16 end_slice;
40688c2ecf20Sopenharmony_ci
40698c2ecf20Sopenharmony_ci	if (!skl_ddb_entry_size(entry))
40708c2ecf20Sopenharmony_ci		return 0;
40718c2ecf20Sopenharmony_ci
40728c2ecf20Sopenharmony_ci	start_slice = entry->start / slice_size;
40738c2ecf20Sopenharmony_ci	end_slice = (entry->end - 1) / slice_size;
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_ci	/*
40768c2ecf20Sopenharmony_ci	 * Per plane DDB entry can in a really worst case be on multiple slices
40778c2ecf20Sopenharmony_ci	 * but single entry is anyway contigious.
40788c2ecf20Sopenharmony_ci	 */
40798c2ecf20Sopenharmony_ci	while (start_slice <= end_slice) {
40808c2ecf20Sopenharmony_ci		slice_mask |= BIT(start_slice);
40818c2ecf20Sopenharmony_ci		start_slice++;
40828c2ecf20Sopenharmony_ci	}
40838c2ecf20Sopenharmony_ci
40848c2ecf20Sopenharmony_ci	return slice_mask;
40858c2ecf20Sopenharmony_ci}
40868c2ecf20Sopenharmony_ci
40878c2ecf20Sopenharmony_cistatic u8 skl_compute_dbuf_slices(const struct intel_crtc_state *crtc_state,
40888c2ecf20Sopenharmony_ci				  u8 active_pipes);
40898c2ecf20Sopenharmony_ci
40908c2ecf20Sopenharmony_cistatic int
40918c2ecf20Sopenharmony_ciskl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
40928c2ecf20Sopenharmony_ci				   const struct intel_crtc_state *crtc_state,
40938c2ecf20Sopenharmony_ci				   const u64 total_data_rate,
40948c2ecf20Sopenharmony_ci				   struct skl_ddb_entry *alloc, /* out */
40958c2ecf20Sopenharmony_ci				   int *num_active /* out */)
40968c2ecf20Sopenharmony_ci{
40978c2ecf20Sopenharmony_ci	struct drm_atomic_state *state = crtc_state->uapi.state;
40988c2ecf20Sopenharmony_ci	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
40998c2ecf20Sopenharmony_ci	struct drm_crtc *for_crtc = crtc_state->uapi.crtc;
41008c2ecf20Sopenharmony_ci	const struct intel_crtc *crtc;
41018c2ecf20Sopenharmony_ci	u32 pipe_width = 0, total_width_in_range = 0, width_before_pipe_in_range = 0;
41028c2ecf20Sopenharmony_ci	enum pipe for_pipe = to_intel_crtc(for_crtc)->pipe;
41038c2ecf20Sopenharmony_ci	struct intel_dbuf_state *new_dbuf_state =
41048c2ecf20Sopenharmony_ci		intel_atomic_get_new_dbuf_state(intel_state);
41058c2ecf20Sopenharmony_ci	const struct intel_dbuf_state *old_dbuf_state =
41068c2ecf20Sopenharmony_ci		intel_atomic_get_old_dbuf_state(intel_state);
41078c2ecf20Sopenharmony_ci	u8 active_pipes = new_dbuf_state->active_pipes;
41088c2ecf20Sopenharmony_ci	u16 ddb_size;
41098c2ecf20Sopenharmony_ci	u32 ddb_range_size;
41108c2ecf20Sopenharmony_ci	u32 i;
41118c2ecf20Sopenharmony_ci	u32 dbuf_slice_mask;
41128c2ecf20Sopenharmony_ci	u32 offset;
41138c2ecf20Sopenharmony_ci	u32 slice_size;
41148c2ecf20Sopenharmony_ci	u32 total_slice_mask;
41158c2ecf20Sopenharmony_ci	u32 start, end;
41168c2ecf20Sopenharmony_ci	int ret;
41178c2ecf20Sopenharmony_ci
41188c2ecf20Sopenharmony_ci	*num_active = hweight8(active_pipes);
41198c2ecf20Sopenharmony_ci
41208c2ecf20Sopenharmony_ci	if (!crtc_state->hw.active) {
41218c2ecf20Sopenharmony_ci		alloc->start = 0;
41228c2ecf20Sopenharmony_ci		alloc->end = 0;
41238c2ecf20Sopenharmony_ci		return 0;
41248c2ecf20Sopenharmony_ci	}
41258c2ecf20Sopenharmony_ci
41268c2ecf20Sopenharmony_ci	ddb_size = intel_get_ddb_size(dev_priv);
41278c2ecf20Sopenharmony_ci
41288c2ecf20Sopenharmony_ci	slice_size = ddb_size / INTEL_INFO(dev_priv)->num_supported_dbuf_slices;
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_ci	/*
41318c2ecf20Sopenharmony_ci	 * If the state doesn't change the active CRTC's or there is no
41328c2ecf20Sopenharmony_ci	 * modeset request, then there's no need to recalculate;
41338c2ecf20Sopenharmony_ci	 * the existing pipe allocation limits should remain unchanged.
41348c2ecf20Sopenharmony_ci	 * Note that we're safe from racing commits since any racing commit
41358c2ecf20Sopenharmony_ci	 * that changes the active CRTC list or do modeset would need to
41368c2ecf20Sopenharmony_ci	 * grab _all_ crtc locks, including the one we currently hold.
41378c2ecf20Sopenharmony_ci	 */
41388c2ecf20Sopenharmony_ci	if (old_dbuf_state->active_pipes == new_dbuf_state->active_pipes &&
41398c2ecf20Sopenharmony_ci	    !dev_priv->wm.distrust_bios_wm) {
41408c2ecf20Sopenharmony_ci		/*
41418c2ecf20Sopenharmony_ci		 * alloc may be cleared by clear_intel_crtc_state,
41428c2ecf20Sopenharmony_ci		 * copy from old state to be sure
41438c2ecf20Sopenharmony_ci		 *
41448c2ecf20Sopenharmony_ci		 * FIXME get rid of this mess
41458c2ecf20Sopenharmony_ci		 */
41468c2ecf20Sopenharmony_ci		*alloc = to_intel_crtc_state(for_crtc->state)->wm.skl.ddb;
41478c2ecf20Sopenharmony_ci		return 0;
41488c2ecf20Sopenharmony_ci	}
41498c2ecf20Sopenharmony_ci
41508c2ecf20Sopenharmony_ci	/*
41518c2ecf20Sopenharmony_ci	 * Get allowed DBuf slices for correspondent pipe and platform.
41528c2ecf20Sopenharmony_ci	 */
41538c2ecf20Sopenharmony_ci	dbuf_slice_mask = skl_compute_dbuf_slices(crtc_state, active_pipes);
41548c2ecf20Sopenharmony_ci
41558c2ecf20Sopenharmony_ci	/*
41568c2ecf20Sopenharmony_ci	 * Figure out at which DBuf slice we start, i.e if we start at Dbuf S2
41578c2ecf20Sopenharmony_ci	 * and slice size is 1024, the offset would be 1024
41588c2ecf20Sopenharmony_ci	 */
41598c2ecf20Sopenharmony_ci	offset = icl_get_first_dbuf_slice_offset(dbuf_slice_mask,
41608c2ecf20Sopenharmony_ci						 slice_size, ddb_size);
41618c2ecf20Sopenharmony_ci
41628c2ecf20Sopenharmony_ci	/*
41638c2ecf20Sopenharmony_ci	 * Figure out total size of allowed DBuf slices, which is basically
41648c2ecf20Sopenharmony_ci	 * a number of allowed slices for that pipe multiplied by slice size.
41658c2ecf20Sopenharmony_ci	 * Inside of this
41668c2ecf20Sopenharmony_ci	 * range ddb entries are still allocated in proportion to display width.
41678c2ecf20Sopenharmony_ci	 */
41688c2ecf20Sopenharmony_ci	ddb_range_size = hweight8(dbuf_slice_mask) * slice_size;
41698c2ecf20Sopenharmony_ci
41708c2ecf20Sopenharmony_ci	/*
41718c2ecf20Sopenharmony_ci	 * Watermark/ddb requirement highly depends upon width of the
41728c2ecf20Sopenharmony_ci	 * framebuffer, So instead of allocating DDB equally among pipes
41738c2ecf20Sopenharmony_ci	 * distribute DDB based on resolution/width of the display.
41748c2ecf20Sopenharmony_ci	 */
41758c2ecf20Sopenharmony_ci	total_slice_mask = dbuf_slice_mask;
41768c2ecf20Sopenharmony_ci	for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) {
41778c2ecf20Sopenharmony_ci		const struct drm_display_mode *adjusted_mode =
41788c2ecf20Sopenharmony_ci			&crtc_state->hw.adjusted_mode;
41798c2ecf20Sopenharmony_ci		enum pipe pipe = crtc->pipe;
41808c2ecf20Sopenharmony_ci		int hdisplay, vdisplay;
41818c2ecf20Sopenharmony_ci		u32 pipe_dbuf_slice_mask;
41828c2ecf20Sopenharmony_ci
41838c2ecf20Sopenharmony_ci		if (!crtc_state->hw.active)
41848c2ecf20Sopenharmony_ci			continue;
41858c2ecf20Sopenharmony_ci
41868c2ecf20Sopenharmony_ci		pipe_dbuf_slice_mask = skl_compute_dbuf_slices(crtc_state,
41878c2ecf20Sopenharmony_ci							       active_pipes);
41888c2ecf20Sopenharmony_ci
41898c2ecf20Sopenharmony_ci		/*
41908c2ecf20Sopenharmony_ci		 * According to BSpec pipe can share one dbuf slice with another
41918c2ecf20Sopenharmony_ci		 * pipes or pipe can use multiple dbufs, in both cases we
41928c2ecf20Sopenharmony_ci		 * account for other pipes only if they have exactly same mask.
41938c2ecf20Sopenharmony_ci		 * However we need to account how many slices we should enable
41948c2ecf20Sopenharmony_ci		 * in total.
41958c2ecf20Sopenharmony_ci		 */
41968c2ecf20Sopenharmony_ci		total_slice_mask |= pipe_dbuf_slice_mask;
41978c2ecf20Sopenharmony_ci
41988c2ecf20Sopenharmony_ci		/*
41998c2ecf20Sopenharmony_ci		 * Do not account pipes using other slice sets
42008c2ecf20Sopenharmony_ci		 * luckily as of current BSpec slice sets do not partially
42018c2ecf20Sopenharmony_ci		 * intersect(pipes share either same one slice or same slice set
42028c2ecf20Sopenharmony_ci		 * i.e no partial intersection), so it is enough to check for
42038c2ecf20Sopenharmony_ci		 * equality for now.
42048c2ecf20Sopenharmony_ci		 */
42058c2ecf20Sopenharmony_ci		if (dbuf_slice_mask != pipe_dbuf_slice_mask)
42068c2ecf20Sopenharmony_ci			continue;
42078c2ecf20Sopenharmony_ci
42088c2ecf20Sopenharmony_ci		drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay);
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci		total_width_in_range += hdisplay;
42118c2ecf20Sopenharmony_ci
42128c2ecf20Sopenharmony_ci		if (pipe < for_pipe)
42138c2ecf20Sopenharmony_ci			width_before_pipe_in_range += hdisplay;
42148c2ecf20Sopenharmony_ci		else if (pipe == for_pipe)
42158c2ecf20Sopenharmony_ci			pipe_width = hdisplay;
42168c2ecf20Sopenharmony_ci	}
42178c2ecf20Sopenharmony_ci
42188c2ecf20Sopenharmony_ci	/*
42198c2ecf20Sopenharmony_ci	 * FIXME: For now we always enable slice S1 as per
42208c2ecf20Sopenharmony_ci	 * the Bspec display initialization sequence.
42218c2ecf20Sopenharmony_ci	 */
42228c2ecf20Sopenharmony_ci	new_dbuf_state->enabled_slices = total_slice_mask | BIT(DBUF_S1);
42238c2ecf20Sopenharmony_ci
42248c2ecf20Sopenharmony_ci	if (old_dbuf_state->enabled_slices != new_dbuf_state->enabled_slices) {
42258c2ecf20Sopenharmony_ci		ret = intel_atomic_serialize_global_state(&new_dbuf_state->base);
42268c2ecf20Sopenharmony_ci		if (ret)
42278c2ecf20Sopenharmony_ci			return ret;
42288c2ecf20Sopenharmony_ci	}
42298c2ecf20Sopenharmony_ci
42308c2ecf20Sopenharmony_ci	start = ddb_range_size * width_before_pipe_in_range / total_width_in_range;
42318c2ecf20Sopenharmony_ci	end = ddb_range_size *
42328c2ecf20Sopenharmony_ci		(width_before_pipe_in_range + pipe_width) / total_width_in_range;
42338c2ecf20Sopenharmony_ci
42348c2ecf20Sopenharmony_ci	alloc->start = offset + start;
42358c2ecf20Sopenharmony_ci	alloc->end = offset + end;
42368c2ecf20Sopenharmony_ci
42378c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
42388c2ecf20Sopenharmony_ci		    "[CRTC:%d:%s] dbuf slices 0x%x, ddb (%d - %d), active pipes 0x%x\n",
42398c2ecf20Sopenharmony_ci		    for_crtc->base.id, for_crtc->name,
42408c2ecf20Sopenharmony_ci		    dbuf_slice_mask, alloc->start, alloc->end, active_pipes);
42418c2ecf20Sopenharmony_ci
42428c2ecf20Sopenharmony_ci	return 0;
42438c2ecf20Sopenharmony_ci}
42448c2ecf20Sopenharmony_ci
42458c2ecf20Sopenharmony_cistatic int skl_compute_wm_params(const struct intel_crtc_state *crtc_state,
42468c2ecf20Sopenharmony_ci				 int width, const struct drm_format_info *format,
42478c2ecf20Sopenharmony_ci				 u64 modifier, unsigned int rotation,
42488c2ecf20Sopenharmony_ci				 u32 plane_pixel_rate, struct skl_wm_params *wp,
42498c2ecf20Sopenharmony_ci				 int color_plane);
42508c2ecf20Sopenharmony_cistatic void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state,
42518c2ecf20Sopenharmony_ci				 int level,
42528c2ecf20Sopenharmony_ci				 unsigned int latency,
42538c2ecf20Sopenharmony_ci				 const struct skl_wm_params *wp,
42548c2ecf20Sopenharmony_ci				 const struct skl_wm_level *result_prev,
42558c2ecf20Sopenharmony_ci				 struct skl_wm_level *result /* out */);
42568c2ecf20Sopenharmony_ci
42578c2ecf20Sopenharmony_cistatic unsigned int
42588c2ecf20Sopenharmony_ciskl_cursor_allocation(const struct intel_crtc_state *crtc_state,
42598c2ecf20Sopenharmony_ci		      int num_active)
42608c2ecf20Sopenharmony_ci{
42618c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
42628c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
42638c2ecf20Sopenharmony_ci	struct skl_wm_level wm = {};
42648c2ecf20Sopenharmony_ci	int ret, min_ddb_alloc = 0;
42658c2ecf20Sopenharmony_ci	struct skl_wm_params wp;
42668c2ecf20Sopenharmony_ci
42678c2ecf20Sopenharmony_ci	ret = skl_compute_wm_params(crtc_state, 256,
42688c2ecf20Sopenharmony_ci				    drm_format_info(DRM_FORMAT_ARGB8888),
42698c2ecf20Sopenharmony_ci				    DRM_FORMAT_MOD_LINEAR,
42708c2ecf20Sopenharmony_ci				    DRM_MODE_ROTATE_0,
42718c2ecf20Sopenharmony_ci				    crtc_state->pixel_rate, &wp, 0);
42728c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, ret);
42738c2ecf20Sopenharmony_ci
42748c2ecf20Sopenharmony_ci	for (level = 0; level <= max_level; level++) {
42758c2ecf20Sopenharmony_ci		unsigned int latency = dev_priv->wm.skl_latency[level];
42768c2ecf20Sopenharmony_ci
42778c2ecf20Sopenharmony_ci		skl_compute_plane_wm(crtc_state, level, latency, &wp, &wm, &wm);
42788c2ecf20Sopenharmony_ci		if (wm.min_ddb_alloc == U16_MAX)
42798c2ecf20Sopenharmony_ci			break;
42808c2ecf20Sopenharmony_ci
42818c2ecf20Sopenharmony_ci		min_ddb_alloc = wm.min_ddb_alloc;
42828c2ecf20Sopenharmony_ci	}
42838c2ecf20Sopenharmony_ci
42848c2ecf20Sopenharmony_ci	return max(num_active == 1 ? 32 : 8, min_ddb_alloc);
42858c2ecf20Sopenharmony_ci}
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_cistatic void skl_ddb_entry_init_from_hw(struct drm_i915_private *dev_priv,
42888c2ecf20Sopenharmony_ci				       struct skl_ddb_entry *entry, u32 reg)
42898c2ecf20Sopenharmony_ci{
42908c2ecf20Sopenharmony_ci
42918c2ecf20Sopenharmony_ci	entry->start = reg & DDB_ENTRY_MASK;
42928c2ecf20Sopenharmony_ci	entry->end = (reg >> DDB_ENTRY_END_SHIFT) & DDB_ENTRY_MASK;
42938c2ecf20Sopenharmony_ci
42948c2ecf20Sopenharmony_ci	if (entry->end)
42958c2ecf20Sopenharmony_ci		entry->end += 1;
42968c2ecf20Sopenharmony_ci}
42978c2ecf20Sopenharmony_ci
42988c2ecf20Sopenharmony_cistatic void
42998c2ecf20Sopenharmony_ciskl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv,
43008c2ecf20Sopenharmony_ci			   const enum pipe pipe,
43018c2ecf20Sopenharmony_ci			   const enum plane_id plane_id,
43028c2ecf20Sopenharmony_ci			   struct skl_ddb_entry *ddb_y,
43038c2ecf20Sopenharmony_ci			   struct skl_ddb_entry *ddb_uv)
43048c2ecf20Sopenharmony_ci{
43058c2ecf20Sopenharmony_ci	u32 val, val2;
43068c2ecf20Sopenharmony_ci	u32 fourcc = 0;
43078c2ecf20Sopenharmony_ci
43088c2ecf20Sopenharmony_ci	/* Cursor doesn't support NV12/planar, so no extra calculation needed */
43098c2ecf20Sopenharmony_ci	if (plane_id == PLANE_CURSOR) {
43108c2ecf20Sopenharmony_ci		val = I915_READ(CUR_BUF_CFG(pipe));
43118c2ecf20Sopenharmony_ci		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
43128c2ecf20Sopenharmony_ci		return;
43138c2ecf20Sopenharmony_ci	}
43148c2ecf20Sopenharmony_ci
43158c2ecf20Sopenharmony_ci	val = I915_READ(PLANE_CTL(pipe, plane_id));
43168c2ecf20Sopenharmony_ci
43178c2ecf20Sopenharmony_ci	/* No DDB allocated for disabled planes */
43188c2ecf20Sopenharmony_ci	if (val & PLANE_CTL_ENABLE)
43198c2ecf20Sopenharmony_ci		fourcc = skl_format_to_fourcc(val & PLANE_CTL_FORMAT_MASK,
43208c2ecf20Sopenharmony_ci					      val & PLANE_CTL_ORDER_RGBX,
43218c2ecf20Sopenharmony_ci					      val & PLANE_CTL_ALPHA_MASK);
43228c2ecf20Sopenharmony_ci
43238c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11) {
43248c2ecf20Sopenharmony_ci		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
43258c2ecf20Sopenharmony_ci		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
43268c2ecf20Sopenharmony_ci	} else {
43278c2ecf20Sopenharmony_ci		val = I915_READ(PLANE_BUF_CFG(pipe, plane_id));
43288c2ecf20Sopenharmony_ci		val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id));
43298c2ecf20Sopenharmony_ci
43308c2ecf20Sopenharmony_ci		if (fourcc &&
43318c2ecf20Sopenharmony_ci		    drm_format_info_is_yuv_semiplanar(drm_format_info(fourcc)))
43328c2ecf20Sopenharmony_ci			swap(val, val2);
43338c2ecf20Sopenharmony_ci
43348c2ecf20Sopenharmony_ci		skl_ddb_entry_init_from_hw(dev_priv, ddb_y, val);
43358c2ecf20Sopenharmony_ci		skl_ddb_entry_init_from_hw(dev_priv, ddb_uv, val2);
43368c2ecf20Sopenharmony_ci	}
43378c2ecf20Sopenharmony_ci}
43388c2ecf20Sopenharmony_ci
43398c2ecf20Sopenharmony_civoid skl_pipe_ddb_get_hw_state(struct intel_crtc *crtc,
43408c2ecf20Sopenharmony_ci			       struct skl_ddb_entry *ddb_y,
43418c2ecf20Sopenharmony_ci			       struct skl_ddb_entry *ddb_uv)
43428c2ecf20Sopenharmony_ci{
43438c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
43448c2ecf20Sopenharmony_ci	enum intel_display_power_domain power_domain;
43458c2ecf20Sopenharmony_ci	enum pipe pipe = crtc->pipe;
43468c2ecf20Sopenharmony_ci	intel_wakeref_t wakeref;
43478c2ecf20Sopenharmony_ci	enum plane_id plane_id;
43488c2ecf20Sopenharmony_ci
43498c2ecf20Sopenharmony_ci	power_domain = POWER_DOMAIN_PIPE(pipe);
43508c2ecf20Sopenharmony_ci	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
43518c2ecf20Sopenharmony_ci	if (!wakeref)
43528c2ecf20Sopenharmony_ci		return;
43538c2ecf20Sopenharmony_ci
43548c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id)
43558c2ecf20Sopenharmony_ci		skl_ddb_get_hw_plane_state(dev_priv, pipe,
43568c2ecf20Sopenharmony_ci					   plane_id,
43578c2ecf20Sopenharmony_ci					   &ddb_y[plane_id],
43588c2ecf20Sopenharmony_ci					   &ddb_uv[plane_id]);
43598c2ecf20Sopenharmony_ci
43608c2ecf20Sopenharmony_ci	intel_display_power_put(dev_priv, power_domain, wakeref);
43618c2ecf20Sopenharmony_ci}
43628c2ecf20Sopenharmony_ci
43638c2ecf20Sopenharmony_ci/*
43648c2ecf20Sopenharmony_ci * Determines the downscale amount of a plane for the purposes of watermark calculations.
43658c2ecf20Sopenharmony_ci * The bspec defines downscale amount as:
43668c2ecf20Sopenharmony_ci *
43678c2ecf20Sopenharmony_ci * """
43688c2ecf20Sopenharmony_ci * Horizontal down scale amount = maximum[1, Horizontal source size /
43698c2ecf20Sopenharmony_ci *                                           Horizontal destination size]
43708c2ecf20Sopenharmony_ci * Vertical down scale amount = maximum[1, Vertical source size /
43718c2ecf20Sopenharmony_ci *                                         Vertical destination size]
43728c2ecf20Sopenharmony_ci * Total down scale amount = Horizontal down scale amount *
43738c2ecf20Sopenharmony_ci *                           Vertical down scale amount
43748c2ecf20Sopenharmony_ci * """
43758c2ecf20Sopenharmony_ci *
43768c2ecf20Sopenharmony_ci * Return value is provided in 16.16 fixed point form to retain fractional part.
43778c2ecf20Sopenharmony_ci * Caller should take care of dividing & rounding off the value.
43788c2ecf20Sopenharmony_ci */
43798c2ecf20Sopenharmony_cistatic uint_fixed_16_16_t
43808c2ecf20Sopenharmony_ciskl_plane_downscale_amount(const struct intel_crtc_state *crtc_state,
43818c2ecf20Sopenharmony_ci			   const struct intel_plane_state *plane_state)
43828c2ecf20Sopenharmony_ci{
43838c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
43848c2ecf20Sopenharmony_ci	u32 src_w, src_h, dst_w, dst_h;
43858c2ecf20Sopenharmony_ci	uint_fixed_16_16_t fp_w_ratio, fp_h_ratio;
43868c2ecf20Sopenharmony_ci	uint_fixed_16_16_t downscale_h, downscale_w;
43878c2ecf20Sopenharmony_ci
43888c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm,
43898c2ecf20Sopenharmony_ci			!intel_wm_plane_visible(crtc_state, plane_state)))
43908c2ecf20Sopenharmony_ci		return u32_to_fixed16(0);
43918c2ecf20Sopenharmony_ci
43928c2ecf20Sopenharmony_ci	/*
43938c2ecf20Sopenharmony_ci	 * Src coordinates are already rotated by 270 degrees for
43948c2ecf20Sopenharmony_ci	 * the 90/270 degree plane rotation cases (to match the
43958c2ecf20Sopenharmony_ci	 * GTT mapping), hence no need to account for rotation here.
43968c2ecf20Sopenharmony_ci	 *
43978c2ecf20Sopenharmony_ci	 * n.b., src is 16.16 fixed point, dst is whole integer.
43988c2ecf20Sopenharmony_ci	 */
43998c2ecf20Sopenharmony_ci	src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
44008c2ecf20Sopenharmony_ci	src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
44018c2ecf20Sopenharmony_ci	dst_w = drm_rect_width(&plane_state->uapi.dst);
44028c2ecf20Sopenharmony_ci	dst_h = drm_rect_height(&plane_state->uapi.dst);
44038c2ecf20Sopenharmony_ci
44048c2ecf20Sopenharmony_ci	fp_w_ratio = div_fixed16(src_w, dst_w);
44058c2ecf20Sopenharmony_ci	fp_h_ratio = div_fixed16(src_h, dst_h);
44068c2ecf20Sopenharmony_ci	downscale_w = max_fixed16(fp_w_ratio, u32_to_fixed16(1));
44078c2ecf20Sopenharmony_ci	downscale_h = max_fixed16(fp_h_ratio, u32_to_fixed16(1));
44088c2ecf20Sopenharmony_ci
44098c2ecf20Sopenharmony_ci	return mul_fixed16(downscale_w, downscale_h);
44108c2ecf20Sopenharmony_ci}
44118c2ecf20Sopenharmony_ci
44128c2ecf20Sopenharmony_cistruct dbuf_slice_conf_entry {
44138c2ecf20Sopenharmony_ci	u8 active_pipes;
44148c2ecf20Sopenharmony_ci	u8 dbuf_mask[I915_MAX_PIPES];
44158c2ecf20Sopenharmony_ci};
44168c2ecf20Sopenharmony_ci
44178c2ecf20Sopenharmony_ci/*
44188c2ecf20Sopenharmony_ci * Table taken from Bspec 12716
44198c2ecf20Sopenharmony_ci * Pipes do have some preferred DBuf slice affinity,
44208c2ecf20Sopenharmony_ci * plus there are some hardcoded requirements on how
44218c2ecf20Sopenharmony_ci * those should be distributed for multipipe scenarios.
44228c2ecf20Sopenharmony_ci * For more DBuf slices algorithm can get even more messy
44238c2ecf20Sopenharmony_ci * and less readable, so decided to use a table almost
44248c2ecf20Sopenharmony_ci * as is from BSpec itself - that way it is at least easier
44258c2ecf20Sopenharmony_ci * to compare, change and check.
44268c2ecf20Sopenharmony_ci */
44278c2ecf20Sopenharmony_cistatic const struct dbuf_slice_conf_entry icl_allowed_dbufs[] =
44288c2ecf20Sopenharmony_ci/* Autogenerated with igt/tools/intel_dbuf_map tool: */
44298c2ecf20Sopenharmony_ci{
44308c2ecf20Sopenharmony_ci	{
44318c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A),
44328c2ecf20Sopenharmony_ci		.dbuf_mask = {
44338c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
44348c2ecf20Sopenharmony_ci		},
44358c2ecf20Sopenharmony_ci	},
44368c2ecf20Sopenharmony_ci	{
44378c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_B),
44388c2ecf20Sopenharmony_ci		.dbuf_mask = {
44398c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
44408c2ecf20Sopenharmony_ci		},
44418c2ecf20Sopenharmony_ci	},
44428c2ecf20Sopenharmony_ci	{
44438c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_B),
44448c2ecf20Sopenharmony_ci		.dbuf_mask = {
44458c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
44468c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S2),
44478c2ecf20Sopenharmony_ci		},
44488c2ecf20Sopenharmony_ci	},
44498c2ecf20Sopenharmony_ci	{
44508c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_C),
44518c2ecf20Sopenharmony_ci		.dbuf_mask = {
44528c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
44538c2ecf20Sopenharmony_ci		},
44548c2ecf20Sopenharmony_ci	},
44558c2ecf20Sopenharmony_ci	{
44568c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_C),
44578c2ecf20Sopenharmony_ci		.dbuf_mask = {
44588c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
44598c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
44608c2ecf20Sopenharmony_ci		},
44618c2ecf20Sopenharmony_ci	},
44628c2ecf20Sopenharmony_ci	{
44638c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_B) | BIT(PIPE_C),
44648c2ecf20Sopenharmony_ci		.dbuf_mask = {
44658c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
44668c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
44678c2ecf20Sopenharmony_ci		},
44688c2ecf20Sopenharmony_ci	},
44698c2ecf20Sopenharmony_ci	{
44708c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C),
44718c2ecf20Sopenharmony_ci		.dbuf_mask = {
44728c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
44738c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
44748c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
44758c2ecf20Sopenharmony_ci		},
44768c2ecf20Sopenharmony_ci	},
44778c2ecf20Sopenharmony_ci	{}
44788c2ecf20Sopenharmony_ci};
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci/*
44818c2ecf20Sopenharmony_ci * Table taken from Bspec 49255
44828c2ecf20Sopenharmony_ci * Pipes do have some preferred DBuf slice affinity,
44838c2ecf20Sopenharmony_ci * plus there are some hardcoded requirements on how
44848c2ecf20Sopenharmony_ci * those should be distributed for multipipe scenarios.
44858c2ecf20Sopenharmony_ci * For more DBuf slices algorithm can get even more messy
44868c2ecf20Sopenharmony_ci * and less readable, so decided to use a table almost
44878c2ecf20Sopenharmony_ci * as is from BSpec itself - that way it is at least easier
44888c2ecf20Sopenharmony_ci * to compare, change and check.
44898c2ecf20Sopenharmony_ci */
44908c2ecf20Sopenharmony_cistatic const struct dbuf_slice_conf_entry tgl_allowed_dbufs[] =
44918c2ecf20Sopenharmony_ci/* Autogenerated with igt/tools/intel_dbuf_map tool: */
44928c2ecf20Sopenharmony_ci{
44938c2ecf20Sopenharmony_ci	{
44948c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A),
44958c2ecf20Sopenharmony_ci		.dbuf_mask = {
44968c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1) | BIT(DBUF_S2),
44978c2ecf20Sopenharmony_ci		},
44988c2ecf20Sopenharmony_ci	},
44998c2ecf20Sopenharmony_ci	{
45008c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_B),
45018c2ecf20Sopenharmony_ci		.dbuf_mask = {
45028c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1) | BIT(DBUF_S2),
45038c2ecf20Sopenharmony_ci		},
45048c2ecf20Sopenharmony_ci	},
45058c2ecf20Sopenharmony_ci	{
45068c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_B),
45078c2ecf20Sopenharmony_ci		.dbuf_mask = {
45088c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S2),
45098c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
45108c2ecf20Sopenharmony_ci		},
45118c2ecf20Sopenharmony_ci	},
45128c2ecf20Sopenharmony_ci	{
45138c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_C),
45148c2ecf20Sopenharmony_ci		.dbuf_mask = {
45158c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2) | BIT(DBUF_S1),
45168c2ecf20Sopenharmony_ci		},
45178c2ecf20Sopenharmony_ci	},
45188c2ecf20Sopenharmony_ci	{
45198c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_C),
45208c2ecf20Sopenharmony_ci		.dbuf_mask = {
45218c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
45228c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
45238c2ecf20Sopenharmony_ci		},
45248c2ecf20Sopenharmony_ci	},
45258c2ecf20Sopenharmony_ci	{
45268c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_B) | BIT(PIPE_C),
45278c2ecf20Sopenharmony_ci		.dbuf_mask = {
45288c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
45298c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
45308c2ecf20Sopenharmony_ci		},
45318c2ecf20Sopenharmony_ci	},
45328c2ecf20Sopenharmony_ci	{
45338c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C),
45348c2ecf20Sopenharmony_ci		.dbuf_mask = {
45358c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
45368c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
45378c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
45388c2ecf20Sopenharmony_ci		},
45398c2ecf20Sopenharmony_ci	},
45408c2ecf20Sopenharmony_ci	{
45418c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_D),
45428c2ecf20Sopenharmony_ci		.dbuf_mask = {
45438c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2) | BIT(DBUF_S1),
45448c2ecf20Sopenharmony_ci		},
45458c2ecf20Sopenharmony_ci	},
45468c2ecf20Sopenharmony_ci	{
45478c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_D),
45488c2ecf20Sopenharmony_ci		.dbuf_mask = {
45498c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
45508c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2),
45518c2ecf20Sopenharmony_ci		},
45528c2ecf20Sopenharmony_ci	},
45538c2ecf20Sopenharmony_ci	{
45548c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_B) | BIT(PIPE_D),
45558c2ecf20Sopenharmony_ci		.dbuf_mask = {
45568c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
45578c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2),
45588c2ecf20Sopenharmony_ci		},
45598c2ecf20Sopenharmony_ci	},
45608c2ecf20Sopenharmony_ci	{
45618c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_D),
45628c2ecf20Sopenharmony_ci		.dbuf_mask = {
45638c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
45648c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
45658c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2),
45668c2ecf20Sopenharmony_ci		},
45678c2ecf20Sopenharmony_ci	},
45688c2ecf20Sopenharmony_ci	{
45698c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_C) | BIT(PIPE_D),
45708c2ecf20Sopenharmony_ci		.dbuf_mask = {
45718c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S1),
45728c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2),
45738c2ecf20Sopenharmony_ci		},
45748c2ecf20Sopenharmony_ci	},
45758c2ecf20Sopenharmony_ci	{
45768c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_C) | BIT(PIPE_D),
45778c2ecf20Sopenharmony_ci		.dbuf_mask = {
45788c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
45798c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
45808c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2),
45818c2ecf20Sopenharmony_ci		},
45828c2ecf20Sopenharmony_ci	},
45838c2ecf20Sopenharmony_ci	{
45848c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D),
45858c2ecf20Sopenharmony_ci		.dbuf_mask = {
45868c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
45878c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
45888c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2),
45898c2ecf20Sopenharmony_ci		},
45908c2ecf20Sopenharmony_ci	},
45918c2ecf20Sopenharmony_ci	{
45928c2ecf20Sopenharmony_ci		.active_pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D),
45938c2ecf20Sopenharmony_ci		.dbuf_mask = {
45948c2ecf20Sopenharmony_ci			[PIPE_A] = BIT(DBUF_S1),
45958c2ecf20Sopenharmony_ci			[PIPE_B] = BIT(DBUF_S1),
45968c2ecf20Sopenharmony_ci			[PIPE_C] = BIT(DBUF_S2),
45978c2ecf20Sopenharmony_ci			[PIPE_D] = BIT(DBUF_S2),
45988c2ecf20Sopenharmony_ci		},
45998c2ecf20Sopenharmony_ci	},
46008c2ecf20Sopenharmony_ci	{}
46018c2ecf20Sopenharmony_ci};
46028c2ecf20Sopenharmony_ci
46038c2ecf20Sopenharmony_cistatic u8 compute_dbuf_slices(enum pipe pipe, u8 active_pipes,
46048c2ecf20Sopenharmony_ci			      const struct dbuf_slice_conf_entry *dbuf_slices)
46058c2ecf20Sopenharmony_ci{
46068c2ecf20Sopenharmony_ci	int i;
46078c2ecf20Sopenharmony_ci
46088c2ecf20Sopenharmony_ci	for (i = 0; i < dbuf_slices[i].active_pipes; i++) {
46098c2ecf20Sopenharmony_ci		if (dbuf_slices[i].active_pipes == active_pipes)
46108c2ecf20Sopenharmony_ci			return dbuf_slices[i].dbuf_mask[pipe];
46118c2ecf20Sopenharmony_ci	}
46128c2ecf20Sopenharmony_ci	return 0;
46138c2ecf20Sopenharmony_ci}
46148c2ecf20Sopenharmony_ci
46158c2ecf20Sopenharmony_ci/*
46168c2ecf20Sopenharmony_ci * This function finds an entry with same enabled pipe configuration and
46178c2ecf20Sopenharmony_ci * returns correspondent DBuf slice mask as stated in BSpec for particular
46188c2ecf20Sopenharmony_ci * platform.
46198c2ecf20Sopenharmony_ci */
46208c2ecf20Sopenharmony_cistatic u8 icl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
46218c2ecf20Sopenharmony_ci{
46228c2ecf20Sopenharmony_ci	/*
46238c2ecf20Sopenharmony_ci	 * FIXME: For ICL this is still a bit unclear as prev BSpec revision
46248c2ecf20Sopenharmony_ci	 * required calculating "pipe ratio" in order to determine
46258c2ecf20Sopenharmony_ci	 * if one or two slices can be used for single pipe configurations
46268c2ecf20Sopenharmony_ci	 * as additional constraint to the existing table.
46278c2ecf20Sopenharmony_ci	 * However based on recent info, it should be not "pipe ratio"
46288c2ecf20Sopenharmony_ci	 * but rather ratio between pixel_rate and cdclk with additional
46298c2ecf20Sopenharmony_ci	 * constants, so for now we are using only table until this is
46308c2ecf20Sopenharmony_ci	 * clarified. Also this is the reason why crtc_state param is
46318c2ecf20Sopenharmony_ci	 * still here - we will need it once those additional constraints
46328c2ecf20Sopenharmony_ci	 * pop up.
46338c2ecf20Sopenharmony_ci	 */
46348c2ecf20Sopenharmony_ci	return compute_dbuf_slices(pipe, active_pipes, icl_allowed_dbufs);
46358c2ecf20Sopenharmony_ci}
46368c2ecf20Sopenharmony_ci
46378c2ecf20Sopenharmony_cistatic u8 tgl_compute_dbuf_slices(enum pipe pipe, u8 active_pipes)
46388c2ecf20Sopenharmony_ci{
46398c2ecf20Sopenharmony_ci	return compute_dbuf_slices(pipe, active_pipes, tgl_allowed_dbufs);
46408c2ecf20Sopenharmony_ci}
46418c2ecf20Sopenharmony_ci
46428c2ecf20Sopenharmony_cistatic u8 skl_compute_dbuf_slices(const struct intel_crtc_state *crtc_state,
46438c2ecf20Sopenharmony_ci				  u8 active_pipes)
46448c2ecf20Sopenharmony_ci{
46458c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
46468c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
46478c2ecf20Sopenharmony_ci	enum pipe pipe = crtc->pipe;
46488c2ecf20Sopenharmony_ci
46498c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 12))
46508c2ecf20Sopenharmony_ci		return tgl_compute_dbuf_slices(pipe, active_pipes);
46518c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 11))
46528c2ecf20Sopenharmony_ci		return icl_compute_dbuf_slices(pipe, active_pipes);
46538c2ecf20Sopenharmony_ci	/*
46548c2ecf20Sopenharmony_ci	 * For anything else just return one slice yet.
46558c2ecf20Sopenharmony_ci	 * Should be extended for other platforms.
46568c2ecf20Sopenharmony_ci	 */
46578c2ecf20Sopenharmony_ci	return active_pipes & BIT(pipe) ? BIT(DBUF_S1) : 0;
46588c2ecf20Sopenharmony_ci}
46598c2ecf20Sopenharmony_ci
46608c2ecf20Sopenharmony_cistatic u64
46618c2ecf20Sopenharmony_ciskl_plane_relative_data_rate(const struct intel_crtc_state *crtc_state,
46628c2ecf20Sopenharmony_ci			     const struct intel_plane_state *plane_state,
46638c2ecf20Sopenharmony_ci			     int color_plane)
46648c2ecf20Sopenharmony_ci{
46658c2ecf20Sopenharmony_ci	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
46668c2ecf20Sopenharmony_ci	const struct drm_framebuffer *fb = plane_state->hw.fb;
46678c2ecf20Sopenharmony_ci	u32 data_rate;
46688c2ecf20Sopenharmony_ci	u32 width = 0, height = 0;
46698c2ecf20Sopenharmony_ci	uint_fixed_16_16_t down_scale_amount;
46708c2ecf20Sopenharmony_ci	u64 rate;
46718c2ecf20Sopenharmony_ci
46728c2ecf20Sopenharmony_ci	if (!plane_state->uapi.visible)
46738c2ecf20Sopenharmony_ci		return 0;
46748c2ecf20Sopenharmony_ci
46758c2ecf20Sopenharmony_ci	if (plane->id == PLANE_CURSOR)
46768c2ecf20Sopenharmony_ci		return 0;
46778c2ecf20Sopenharmony_ci
46788c2ecf20Sopenharmony_ci	if (color_plane == 1 &&
46798c2ecf20Sopenharmony_ci	    !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
46808c2ecf20Sopenharmony_ci		return 0;
46818c2ecf20Sopenharmony_ci
46828c2ecf20Sopenharmony_ci	/*
46838c2ecf20Sopenharmony_ci	 * Src coordinates are already rotated by 270 degrees for
46848c2ecf20Sopenharmony_ci	 * the 90/270 degree plane rotation cases (to match the
46858c2ecf20Sopenharmony_ci	 * GTT mapping), hence no need to account for rotation here.
46868c2ecf20Sopenharmony_ci	 */
46878c2ecf20Sopenharmony_ci	width = drm_rect_width(&plane_state->uapi.src) >> 16;
46888c2ecf20Sopenharmony_ci	height = drm_rect_height(&plane_state->uapi.src) >> 16;
46898c2ecf20Sopenharmony_ci
46908c2ecf20Sopenharmony_ci	/* UV plane does 1/2 pixel sub-sampling */
46918c2ecf20Sopenharmony_ci	if (color_plane == 1) {
46928c2ecf20Sopenharmony_ci		width /= 2;
46938c2ecf20Sopenharmony_ci		height /= 2;
46948c2ecf20Sopenharmony_ci	}
46958c2ecf20Sopenharmony_ci
46968c2ecf20Sopenharmony_ci	data_rate = width * height;
46978c2ecf20Sopenharmony_ci
46988c2ecf20Sopenharmony_ci	down_scale_amount = skl_plane_downscale_amount(crtc_state, plane_state);
46998c2ecf20Sopenharmony_ci
47008c2ecf20Sopenharmony_ci	rate = mul_round_up_u32_fixed16(data_rate, down_scale_amount);
47018c2ecf20Sopenharmony_ci
47028c2ecf20Sopenharmony_ci	rate *= fb->format->cpp[color_plane];
47038c2ecf20Sopenharmony_ci	return rate;
47048c2ecf20Sopenharmony_ci}
47058c2ecf20Sopenharmony_ci
47068c2ecf20Sopenharmony_cistatic u64
47078c2ecf20Sopenharmony_ciskl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
47088c2ecf20Sopenharmony_ci				 u64 *plane_data_rate,
47098c2ecf20Sopenharmony_ci				 u64 *uv_plane_data_rate)
47108c2ecf20Sopenharmony_ci{
47118c2ecf20Sopenharmony_ci	struct intel_plane *plane;
47128c2ecf20Sopenharmony_ci	const struct intel_plane_state *plane_state;
47138c2ecf20Sopenharmony_ci	u64 total_data_rate = 0;
47148c2ecf20Sopenharmony_ci
47158c2ecf20Sopenharmony_ci	/* Calculate and cache data rate for each plane */
47168c2ecf20Sopenharmony_ci	intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
47178c2ecf20Sopenharmony_ci		enum plane_id plane_id = plane->id;
47188c2ecf20Sopenharmony_ci		u64 rate;
47198c2ecf20Sopenharmony_ci
47208c2ecf20Sopenharmony_ci		/* packed/y */
47218c2ecf20Sopenharmony_ci		rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0);
47228c2ecf20Sopenharmony_ci		plane_data_rate[plane_id] = rate;
47238c2ecf20Sopenharmony_ci		total_data_rate += rate;
47248c2ecf20Sopenharmony_ci
47258c2ecf20Sopenharmony_ci		/* uv-plane */
47268c2ecf20Sopenharmony_ci		rate = skl_plane_relative_data_rate(crtc_state, plane_state, 1);
47278c2ecf20Sopenharmony_ci		uv_plane_data_rate[plane_id] = rate;
47288c2ecf20Sopenharmony_ci		total_data_rate += rate;
47298c2ecf20Sopenharmony_ci	}
47308c2ecf20Sopenharmony_ci
47318c2ecf20Sopenharmony_ci	return total_data_rate;
47328c2ecf20Sopenharmony_ci}
47338c2ecf20Sopenharmony_ci
47348c2ecf20Sopenharmony_cistatic u64
47358c2ecf20Sopenharmony_ciicl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
47368c2ecf20Sopenharmony_ci				 u64 *plane_data_rate)
47378c2ecf20Sopenharmony_ci{
47388c2ecf20Sopenharmony_ci	struct intel_plane *plane;
47398c2ecf20Sopenharmony_ci	const struct intel_plane_state *plane_state;
47408c2ecf20Sopenharmony_ci	u64 total_data_rate = 0;
47418c2ecf20Sopenharmony_ci
47428c2ecf20Sopenharmony_ci	/* Calculate and cache data rate for each plane */
47438c2ecf20Sopenharmony_ci	intel_atomic_crtc_state_for_each_plane_state(plane, plane_state, crtc_state) {
47448c2ecf20Sopenharmony_ci		enum plane_id plane_id = plane->id;
47458c2ecf20Sopenharmony_ci		u64 rate;
47468c2ecf20Sopenharmony_ci
47478c2ecf20Sopenharmony_ci		if (!plane_state->planar_linked_plane) {
47488c2ecf20Sopenharmony_ci			rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0);
47498c2ecf20Sopenharmony_ci			plane_data_rate[plane_id] = rate;
47508c2ecf20Sopenharmony_ci			total_data_rate += rate;
47518c2ecf20Sopenharmony_ci		} else {
47528c2ecf20Sopenharmony_ci			enum plane_id y_plane_id;
47538c2ecf20Sopenharmony_ci
47548c2ecf20Sopenharmony_ci			/*
47558c2ecf20Sopenharmony_ci			 * The slave plane might not iterate in
47568c2ecf20Sopenharmony_ci			 * intel_atomic_crtc_state_for_each_plane_state(),
47578c2ecf20Sopenharmony_ci			 * and needs the master plane state which may be
47588c2ecf20Sopenharmony_ci			 * NULL if we try get_new_plane_state(), so we
47598c2ecf20Sopenharmony_ci			 * always calculate from the master.
47608c2ecf20Sopenharmony_ci			 */
47618c2ecf20Sopenharmony_ci			if (plane_state->planar_slave)
47628c2ecf20Sopenharmony_ci				continue;
47638c2ecf20Sopenharmony_ci
47648c2ecf20Sopenharmony_ci			/* Y plane rate is calculated on the slave */
47658c2ecf20Sopenharmony_ci			rate = skl_plane_relative_data_rate(crtc_state, plane_state, 0);
47668c2ecf20Sopenharmony_ci			y_plane_id = plane_state->planar_linked_plane->id;
47678c2ecf20Sopenharmony_ci			plane_data_rate[y_plane_id] = rate;
47688c2ecf20Sopenharmony_ci			total_data_rate += rate;
47698c2ecf20Sopenharmony_ci
47708c2ecf20Sopenharmony_ci			rate = skl_plane_relative_data_rate(crtc_state, plane_state, 1);
47718c2ecf20Sopenharmony_ci			plane_data_rate[plane_id] = rate;
47728c2ecf20Sopenharmony_ci			total_data_rate += rate;
47738c2ecf20Sopenharmony_ci		}
47748c2ecf20Sopenharmony_ci	}
47758c2ecf20Sopenharmony_ci
47768c2ecf20Sopenharmony_ci	return total_data_rate;
47778c2ecf20Sopenharmony_ci}
47788c2ecf20Sopenharmony_ci
47798c2ecf20Sopenharmony_cistatic const struct skl_wm_level *
47808c2ecf20Sopenharmony_ciskl_plane_wm_level(const struct intel_crtc_state *crtc_state,
47818c2ecf20Sopenharmony_ci		   enum plane_id plane_id,
47828c2ecf20Sopenharmony_ci		   int level)
47838c2ecf20Sopenharmony_ci{
47848c2ecf20Sopenharmony_ci	const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
47858c2ecf20Sopenharmony_ci	const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id];
47868c2ecf20Sopenharmony_ci
47878c2ecf20Sopenharmony_ci	if (level == 0 && pipe_wm->use_sagv_wm)
47888c2ecf20Sopenharmony_ci		return &wm->sagv_wm0;
47898c2ecf20Sopenharmony_ci
47908c2ecf20Sopenharmony_ci	return &wm->wm[level];
47918c2ecf20Sopenharmony_ci}
47928c2ecf20Sopenharmony_ci
47938c2ecf20Sopenharmony_cistatic int
47948c2ecf20Sopenharmony_ciskl_allocate_pipe_ddb(struct intel_crtc_state *crtc_state)
47958c2ecf20Sopenharmony_ci{
47968c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
47978c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
47988c2ecf20Sopenharmony_ci	struct skl_ddb_entry *alloc = &crtc_state->wm.skl.ddb;
47998c2ecf20Sopenharmony_ci	u16 alloc_size, start = 0;
48008c2ecf20Sopenharmony_ci	u16 total[I915_MAX_PLANES] = {};
48018c2ecf20Sopenharmony_ci	u16 uv_total[I915_MAX_PLANES] = {};
48028c2ecf20Sopenharmony_ci	u64 total_data_rate;
48038c2ecf20Sopenharmony_ci	enum plane_id plane_id;
48048c2ecf20Sopenharmony_ci	int num_active;
48058c2ecf20Sopenharmony_ci	u64 plane_data_rate[I915_MAX_PLANES] = {};
48068c2ecf20Sopenharmony_ci	u64 uv_plane_data_rate[I915_MAX_PLANES] = {};
48078c2ecf20Sopenharmony_ci	u32 blocks;
48088c2ecf20Sopenharmony_ci	int level;
48098c2ecf20Sopenharmony_ci	int ret;
48108c2ecf20Sopenharmony_ci
48118c2ecf20Sopenharmony_ci	/* Clear the partitioning for disabled planes. */
48128c2ecf20Sopenharmony_ci	memset(crtc_state->wm.skl.plane_ddb_y, 0, sizeof(crtc_state->wm.skl.plane_ddb_y));
48138c2ecf20Sopenharmony_ci	memset(crtc_state->wm.skl.plane_ddb_uv, 0, sizeof(crtc_state->wm.skl.plane_ddb_uv));
48148c2ecf20Sopenharmony_ci
48158c2ecf20Sopenharmony_ci	if (!crtc_state->hw.active) {
48168c2ecf20Sopenharmony_ci		struct intel_atomic_state *state =
48178c2ecf20Sopenharmony_ci			to_intel_atomic_state(crtc_state->uapi.state);
48188c2ecf20Sopenharmony_ci		struct intel_dbuf_state *new_dbuf_state =
48198c2ecf20Sopenharmony_ci			intel_atomic_get_new_dbuf_state(state);
48208c2ecf20Sopenharmony_ci		const struct intel_dbuf_state *old_dbuf_state =
48218c2ecf20Sopenharmony_ci			intel_atomic_get_old_dbuf_state(state);
48228c2ecf20Sopenharmony_ci
48238c2ecf20Sopenharmony_ci		/*
48248c2ecf20Sopenharmony_ci		 * FIXME hack to make sure we compute this sensibly when
48258c2ecf20Sopenharmony_ci		 * turning off all the pipes. Otherwise we leave it at
48268c2ecf20Sopenharmony_ci		 * whatever we had previously, and then runtime PM will
48278c2ecf20Sopenharmony_ci		 * mess it up by turning off all but S1. Remove this
48288c2ecf20Sopenharmony_ci		 * once the dbuf state computation flow becomes sane.
48298c2ecf20Sopenharmony_ci		 */
48308c2ecf20Sopenharmony_ci		if (new_dbuf_state->active_pipes == 0) {
48318c2ecf20Sopenharmony_ci			new_dbuf_state->enabled_slices = BIT(DBUF_S1);
48328c2ecf20Sopenharmony_ci
48338c2ecf20Sopenharmony_ci			if (old_dbuf_state->enabled_slices != new_dbuf_state->enabled_slices) {
48348c2ecf20Sopenharmony_ci				ret = intel_atomic_serialize_global_state(&new_dbuf_state->base);
48358c2ecf20Sopenharmony_ci				if (ret)
48368c2ecf20Sopenharmony_ci					return ret;
48378c2ecf20Sopenharmony_ci			}
48388c2ecf20Sopenharmony_ci		}
48398c2ecf20Sopenharmony_ci
48408c2ecf20Sopenharmony_ci		alloc->start = alloc->end = 0;
48418c2ecf20Sopenharmony_ci		return 0;
48428c2ecf20Sopenharmony_ci	}
48438c2ecf20Sopenharmony_ci
48448c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11)
48458c2ecf20Sopenharmony_ci		total_data_rate =
48468c2ecf20Sopenharmony_ci			icl_get_total_relative_data_rate(crtc_state,
48478c2ecf20Sopenharmony_ci							 plane_data_rate);
48488c2ecf20Sopenharmony_ci	else
48498c2ecf20Sopenharmony_ci		total_data_rate =
48508c2ecf20Sopenharmony_ci			skl_get_total_relative_data_rate(crtc_state,
48518c2ecf20Sopenharmony_ci							 plane_data_rate,
48528c2ecf20Sopenharmony_ci							 uv_plane_data_rate);
48538c2ecf20Sopenharmony_ci
48548c2ecf20Sopenharmony_ci	ret = skl_ddb_get_pipe_allocation_limits(dev_priv, crtc_state,
48558c2ecf20Sopenharmony_ci						 total_data_rate,
48568c2ecf20Sopenharmony_ci						 alloc, &num_active);
48578c2ecf20Sopenharmony_ci	if (ret)
48588c2ecf20Sopenharmony_ci		return ret;
48598c2ecf20Sopenharmony_ci
48608c2ecf20Sopenharmony_ci	alloc_size = skl_ddb_entry_size(alloc);
48618c2ecf20Sopenharmony_ci	if (alloc_size == 0)
48628c2ecf20Sopenharmony_ci		return 0;
48638c2ecf20Sopenharmony_ci
48648c2ecf20Sopenharmony_ci	/* Allocate fixed number of blocks for cursor. */
48658c2ecf20Sopenharmony_ci	total[PLANE_CURSOR] = skl_cursor_allocation(crtc_state, num_active);
48668c2ecf20Sopenharmony_ci	alloc_size -= total[PLANE_CURSOR];
48678c2ecf20Sopenharmony_ci	crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR].start =
48688c2ecf20Sopenharmony_ci		alloc->end - total[PLANE_CURSOR];
48698c2ecf20Sopenharmony_ci	crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR].end = alloc->end;
48708c2ecf20Sopenharmony_ci
48718c2ecf20Sopenharmony_ci	if (total_data_rate == 0)
48728c2ecf20Sopenharmony_ci		return 0;
48738c2ecf20Sopenharmony_ci
48748c2ecf20Sopenharmony_ci	/*
48758c2ecf20Sopenharmony_ci	 * Find the highest watermark level for which we can satisfy the block
48768c2ecf20Sopenharmony_ci	 * requirement of active planes.
48778c2ecf20Sopenharmony_ci	 */
48788c2ecf20Sopenharmony_ci	for (level = ilk_wm_max_level(dev_priv); level >= 0; level--) {
48798c2ecf20Sopenharmony_ci		blocks = 0;
48808c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id) {
48818c2ecf20Sopenharmony_ci			const struct skl_plane_wm *wm =
48828c2ecf20Sopenharmony_ci				&crtc_state->wm.skl.optimal.planes[plane_id];
48838c2ecf20Sopenharmony_ci
48848c2ecf20Sopenharmony_ci			if (plane_id == PLANE_CURSOR) {
48858c2ecf20Sopenharmony_ci				if (wm->wm[level].min_ddb_alloc > total[PLANE_CURSOR]) {
48868c2ecf20Sopenharmony_ci					drm_WARN_ON(&dev_priv->drm,
48878c2ecf20Sopenharmony_ci						    wm->wm[level].min_ddb_alloc != U16_MAX);
48888c2ecf20Sopenharmony_ci					blocks = U32_MAX;
48898c2ecf20Sopenharmony_ci					break;
48908c2ecf20Sopenharmony_ci				}
48918c2ecf20Sopenharmony_ci				continue;
48928c2ecf20Sopenharmony_ci			}
48938c2ecf20Sopenharmony_ci
48948c2ecf20Sopenharmony_ci			blocks += wm->wm[level].min_ddb_alloc;
48958c2ecf20Sopenharmony_ci			blocks += wm->uv_wm[level].min_ddb_alloc;
48968c2ecf20Sopenharmony_ci		}
48978c2ecf20Sopenharmony_ci
48988c2ecf20Sopenharmony_ci		if (blocks <= alloc_size) {
48998c2ecf20Sopenharmony_ci			alloc_size -= blocks;
49008c2ecf20Sopenharmony_ci			break;
49018c2ecf20Sopenharmony_ci		}
49028c2ecf20Sopenharmony_ci	}
49038c2ecf20Sopenharmony_ci
49048c2ecf20Sopenharmony_ci	if (level < 0) {
49058c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
49068c2ecf20Sopenharmony_ci			    "Requested display configuration exceeds system DDB limitations");
49078c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "minimum required %d/%d\n",
49088c2ecf20Sopenharmony_ci			    blocks, alloc_size);
49098c2ecf20Sopenharmony_ci		return -EINVAL;
49108c2ecf20Sopenharmony_ci	}
49118c2ecf20Sopenharmony_ci
49128c2ecf20Sopenharmony_ci	/*
49138c2ecf20Sopenharmony_ci	 * Grant each plane the blocks it requires at the highest achievable
49148c2ecf20Sopenharmony_ci	 * watermark level, plus an extra share of the leftover blocks
49158c2ecf20Sopenharmony_ci	 * proportional to its relative data rate.
49168c2ecf20Sopenharmony_ci	 */
49178c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
49188c2ecf20Sopenharmony_ci		const struct skl_plane_wm *wm =
49198c2ecf20Sopenharmony_ci			&crtc_state->wm.skl.optimal.planes[plane_id];
49208c2ecf20Sopenharmony_ci		u64 rate;
49218c2ecf20Sopenharmony_ci		u16 extra;
49228c2ecf20Sopenharmony_ci
49238c2ecf20Sopenharmony_ci		if (plane_id == PLANE_CURSOR)
49248c2ecf20Sopenharmony_ci			continue;
49258c2ecf20Sopenharmony_ci
49268c2ecf20Sopenharmony_ci		/*
49278c2ecf20Sopenharmony_ci		 * We've accounted for all active planes; remaining planes are
49288c2ecf20Sopenharmony_ci		 * all disabled.
49298c2ecf20Sopenharmony_ci		 */
49308c2ecf20Sopenharmony_ci		if (total_data_rate == 0)
49318c2ecf20Sopenharmony_ci			break;
49328c2ecf20Sopenharmony_ci
49338c2ecf20Sopenharmony_ci		rate = plane_data_rate[plane_id];
49348c2ecf20Sopenharmony_ci		extra = min_t(u16, alloc_size,
49358c2ecf20Sopenharmony_ci			      DIV64_U64_ROUND_UP(alloc_size * rate,
49368c2ecf20Sopenharmony_ci						 total_data_rate));
49378c2ecf20Sopenharmony_ci		total[plane_id] = wm->wm[level].min_ddb_alloc + extra;
49388c2ecf20Sopenharmony_ci		alloc_size -= extra;
49398c2ecf20Sopenharmony_ci		total_data_rate -= rate;
49408c2ecf20Sopenharmony_ci
49418c2ecf20Sopenharmony_ci		if (total_data_rate == 0)
49428c2ecf20Sopenharmony_ci			break;
49438c2ecf20Sopenharmony_ci
49448c2ecf20Sopenharmony_ci		rate = uv_plane_data_rate[plane_id];
49458c2ecf20Sopenharmony_ci		extra = min_t(u16, alloc_size,
49468c2ecf20Sopenharmony_ci			      DIV64_U64_ROUND_UP(alloc_size * rate,
49478c2ecf20Sopenharmony_ci						 total_data_rate));
49488c2ecf20Sopenharmony_ci		uv_total[plane_id] = wm->uv_wm[level].min_ddb_alloc + extra;
49498c2ecf20Sopenharmony_ci		alloc_size -= extra;
49508c2ecf20Sopenharmony_ci		total_data_rate -= rate;
49518c2ecf20Sopenharmony_ci	}
49528c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, alloc_size != 0 || total_data_rate != 0);
49538c2ecf20Sopenharmony_ci
49548c2ecf20Sopenharmony_ci	/* Set the actual DDB start/end points for each plane */
49558c2ecf20Sopenharmony_ci	start = alloc->start;
49568c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
49578c2ecf20Sopenharmony_ci		struct skl_ddb_entry *plane_alloc =
49588c2ecf20Sopenharmony_ci			&crtc_state->wm.skl.plane_ddb_y[plane_id];
49598c2ecf20Sopenharmony_ci		struct skl_ddb_entry *uv_plane_alloc =
49608c2ecf20Sopenharmony_ci			&crtc_state->wm.skl.plane_ddb_uv[plane_id];
49618c2ecf20Sopenharmony_ci
49628c2ecf20Sopenharmony_ci		if (plane_id == PLANE_CURSOR)
49638c2ecf20Sopenharmony_ci			continue;
49648c2ecf20Sopenharmony_ci
49658c2ecf20Sopenharmony_ci		/* Gen11+ uses a separate plane for UV watermarks */
49668c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
49678c2ecf20Sopenharmony_ci			    INTEL_GEN(dev_priv) >= 11 && uv_total[plane_id]);
49688c2ecf20Sopenharmony_ci
49698c2ecf20Sopenharmony_ci		/* Leave disabled planes at (0,0) */
49708c2ecf20Sopenharmony_ci		if (total[plane_id]) {
49718c2ecf20Sopenharmony_ci			plane_alloc->start = start;
49728c2ecf20Sopenharmony_ci			start += total[plane_id];
49738c2ecf20Sopenharmony_ci			plane_alloc->end = start;
49748c2ecf20Sopenharmony_ci		}
49758c2ecf20Sopenharmony_ci
49768c2ecf20Sopenharmony_ci		if (uv_total[plane_id]) {
49778c2ecf20Sopenharmony_ci			uv_plane_alloc->start = start;
49788c2ecf20Sopenharmony_ci			start += uv_total[plane_id];
49798c2ecf20Sopenharmony_ci			uv_plane_alloc->end = start;
49808c2ecf20Sopenharmony_ci		}
49818c2ecf20Sopenharmony_ci	}
49828c2ecf20Sopenharmony_ci
49838c2ecf20Sopenharmony_ci	/*
49848c2ecf20Sopenharmony_ci	 * When we calculated watermark values we didn't know how high
49858c2ecf20Sopenharmony_ci	 * of a level we'd actually be able to hit, so we just marked
49868c2ecf20Sopenharmony_ci	 * all levels as "enabled."  Go back now and disable the ones
49878c2ecf20Sopenharmony_ci	 * that aren't actually possible.
49888c2ecf20Sopenharmony_ci	 */
49898c2ecf20Sopenharmony_ci	for (level++; level <= ilk_wm_max_level(dev_priv); level++) {
49908c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id) {
49918c2ecf20Sopenharmony_ci			struct skl_plane_wm *wm =
49928c2ecf20Sopenharmony_ci				&crtc_state->wm.skl.optimal.planes[plane_id];
49938c2ecf20Sopenharmony_ci
49948c2ecf20Sopenharmony_ci			/*
49958c2ecf20Sopenharmony_ci			 * We only disable the watermarks for each plane if
49968c2ecf20Sopenharmony_ci			 * they exceed the ddb allocation of said plane. This
49978c2ecf20Sopenharmony_ci			 * is done so that we don't end up touching cursor
49988c2ecf20Sopenharmony_ci			 * watermarks needlessly when some other plane reduces
49998c2ecf20Sopenharmony_ci			 * our max possible watermark level.
50008c2ecf20Sopenharmony_ci			 *
50018c2ecf20Sopenharmony_ci			 * Bspec has this to say about the PLANE_WM enable bit:
50028c2ecf20Sopenharmony_ci			 * "All the watermarks at this level for all enabled
50038c2ecf20Sopenharmony_ci			 *  planes must be enabled before the level will be used."
50048c2ecf20Sopenharmony_ci			 * So this is actually safe to do.
50058c2ecf20Sopenharmony_ci			 */
50068c2ecf20Sopenharmony_ci			if (wm->wm[level].min_ddb_alloc > total[plane_id] ||
50078c2ecf20Sopenharmony_ci			    wm->uv_wm[level].min_ddb_alloc > uv_total[plane_id])
50088c2ecf20Sopenharmony_ci				memset(&wm->wm[level], 0, sizeof(wm->wm[level]));
50098c2ecf20Sopenharmony_ci
50108c2ecf20Sopenharmony_ci			/*
50118c2ecf20Sopenharmony_ci			 * Wa_1408961008:icl, ehl
50128c2ecf20Sopenharmony_ci			 * Underruns with WM1+ disabled
50138c2ecf20Sopenharmony_ci			 */
50148c2ecf20Sopenharmony_ci			if (IS_GEN(dev_priv, 11) &&
50158c2ecf20Sopenharmony_ci			    level == 1 && wm->wm[0].plane_en) {
50168c2ecf20Sopenharmony_ci				wm->wm[level].plane_res_b = wm->wm[0].plane_res_b;
50178c2ecf20Sopenharmony_ci				wm->wm[level].plane_res_l = wm->wm[0].plane_res_l;
50188c2ecf20Sopenharmony_ci				wm->wm[level].ignore_lines = wm->wm[0].ignore_lines;
50198c2ecf20Sopenharmony_ci			}
50208c2ecf20Sopenharmony_ci		}
50218c2ecf20Sopenharmony_ci	}
50228c2ecf20Sopenharmony_ci
50238c2ecf20Sopenharmony_ci	/*
50248c2ecf20Sopenharmony_ci	 * Go back and disable the transition watermark if it turns out we
50258c2ecf20Sopenharmony_ci	 * don't have enough DDB blocks for it.
50268c2ecf20Sopenharmony_ci	 */
50278c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
50288c2ecf20Sopenharmony_ci		struct skl_plane_wm *wm =
50298c2ecf20Sopenharmony_ci			&crtc_state->wm.skl.optimal.planes[plane_id];
50308c2ecf20Sopenharmony_ci
50318c2ecf20Sopenharmony_ci		if (wm->trans_wm.plane_res_b >= total[plane_id])
50328c2ecf20Sopenharmony_ci			memset(&wm->trans_wm, 0, sizeof(wm->trans_wm));
50338c2ecf20Sopenharmony_ci	}
50348c2ecf20Sopenharmony_ci
50358c2ecf20Sopenharmony_ci	return 0;
50368c2ecf20Sopenharmony_ci}
50378c2ecf20Sopenharmony_ci
50388c2ecf20Sopenharmony_ci/*
50398c2ecf20Sopenharmony_ci * The max latency should be 257 (max the punit can code is 255 and we add 2us
50408c2ecf20Sopenharmony_ci * for the read latency) and cpp should always be <= 8, so that
50418c2ecf20Sopenharmony_ci * should allow pixel_rate up to ~2 GHz which seems sufficient since max
50428c2ecf20Sopenharmony_ci * 2xcdclk is 1350 MHz and the pixel rate should never exceed that.
50438c2ecf20Sopenharmony_ci*/
50448c2ecf20Sopenharmony_cistatic uint_fixed_16_16_t
50458c2ecf20Sopenharmony_ciskl_wm_method1(const struct drm_i915_private *dev_priv, u32 pixel_rate,
50468c2ecf20Sopenharmony_ci	       u8 cpp, u32 latency, u32 dbuf_block_size)
50478c2ecf20Sopenharmony_ci{
50488c2ecf20Sopenharmony_ci	u32 wm_intermediate_val;
50498c2ecf20Sopenharmony_ci	uint_fixed_16_16_t ret;
50508c2ecf20Sopenharmony_ci
50518c2ecf20Sopenharmony_ci	if (latency == 0)
50528c2ecf20Sopenharmony_ci		return FP_16_16_MAX;
50538c2ecf20Sopenharmony_ci
50548c2ecf20Sopenharmony_ci	wm_intermediate_val = latency * pixel_rate * cpp;
50558c2ecf20Sopenharmony_ci	ret = div_fixed16(wm_intermediate_val, 1000 * dbuf_block_size);
50568c2ecf20Sopenharmony_ci
50578c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
50588c2ecf20Sopenharmony_ci		ret = add_fixed16_u32(ret, 1);
50598c2ecf20Sopenharmony_ci
50608c2ecf20Sopenharmony_ci	return ret;
50618c2ecf20Sopenharmony_ci}
50628c2ecf20Sopenharmony_ci
50638c2ecf20Sopenharmony_cistatic uint_fixed_16_16_t
50648c2ecf20Sopenharmony_ciskl_wm_method2(u32 pixel_rate, u32 pipe_htotal, u32 latency,
50658c2ecf20Sopenharmony_ci	       uint_fixed_16_16_t plane_blocks_per_line)
50668c2ecf20Sopenharmony_ci{
50678c2ecf20Sopenharmony_ci	u32 wm_intermediate_val;
50688c2ecf20Sopenharmony_ci	uint_fixed_16_16_t ret;
50698c2ecf20Sopenharmony_ci
50708c2ecf20Sopenharmony_ci	if (latency == 0)
50718c2ecf20Sopenharmony_ci		return FP_16_16_MAX;
50728c2ecf20Sopenharmony_ci
50738c2ecf20Sopenharmony_ci	wm_intermediate_val = latency * pixel_rate;
50748c2ecf20Sopenharmony_ci	wm_intermediate_val = DIV_ROUND_UP(wm_intermediate_val,
50758c2ecf20Sopenharmony_ci					   pipe_htotal * 1000);
50768c2ecf20Sopenharmony_ci	ret = mul_u32_fixed16(wm_intermediate_val, plane_blocks_per_line);
50778c2ecf20Sopenharmony_ci	return ret;
50788c2ecf20Sopenharmony_ci}
50798c2ecf20Sopenharmony_ci
50808c2ecf20Sopenharmony_cistatic uint_fixed_16_16_t
50818c2ecf20Sopenharmony_ciintel_get_linetime_us(const struct intel_crtc_state *crtc_state)
50828c2ecf20Sopenharmony_ci{
50838c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
50848c2ecf20Sopenharmony_ci	u32 pixel_rate;
50858c2ecf20Sopenharmony_ci	u32 crtc_htotal;
50868c2ecf20Sopenharmony_ci	uint_fixed_16_16_t linetime_us;
50878c2ecf20Sopenharmony_ci
50888c2ecf20Sopenharmony_ci	if (!crtc_state->hw.active)
50898c2ecf20Sopenharmony_ci		return u32_to_fixed16(0);
50908c2ecf20Sopenharmony_ci
50918c2ecf20Sopenharmony_ci	pixel_rate = crtc_state->pixel_rate;
50928c2ecf20Sopenharmony_ci
50938c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm, pixel_rate == 0))
50948c2ecf20Sopenharmony_ci		return u32_to_fixed16(0);
50958c2ecf20Sopenharmony_ci
50968c2ecf20Sopenharmony_ci	crtc_htotal = crtc_state->hw.adjusted_mode.crtc_htotal;
50978c2ecf20Sopenharmony_ci	linetime_us = div_fixed16(crtc_htotal * 1000, pixel_rate);
50988c2ecf20Sopenharmony_ci
50998c2ecf20Sopenharmony_ci	return linetime_us;
51008c2ecf20Sopenharmony_ci}
51018c2ecf20Sopenharmony_ci
51028c2ecf20Sopenharmony_cistatic u32
51038c2ecf20Sopenharmony_ciskl_adjusted_plane_pixel_rate(const struct intel_crtc_state *crtc_state,
51048c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state)
51058c2ecf20Sopenharmony_ci{
51068c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
51078c2ecf20Sopenharmony_ci	u64 adjusted_pixel_rate;
51088c2ecf20Sopenharmony_ci	uint_fixed_16_16_t downscale_amount;
51098c2ecf20Sopenharmony_ci
51108c2ecf20Sopenharmony_ci	/* Shouldn't reach here on disabled planes... */
51118c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm,
51128c2ecf20Sopenharmony_ci			!intel_wm_plane_visible(crtc_state, plane_state)))
51138c2ecf20Sopenharmony_ci		return 0;
51148c2ecf20Sopenharmony_ci
51158c2ecf20Sopenharmony_ci	/*
51168c2ecf20Sopenharmony_ci	 * Adjusted plane pixel rate is just the pipe's adjusted pixel rate
51178c2ecf20Sopenharmony_ci	 * with additional adjustments for plane-specific scaling.
51188c2ecf20Sopenharmony_ci	 */
51198c2ecf20Sopenharmony_ci	adjusted_pixel_rate = crtc_state->pixel_rate;
51208c2ecf20Sopenharmony_ci	downscale_amount = skl_plane_downscale_amount(crtc_state, plane_state);
51218c2ecf20Sopenharmony_ci
51228c2ecf20Sopenharmony_ci	return mul_round_up_u32_fixed16(adjusted_pixel_rate,
51238c2ecf20Sopenharmony_ci					    downscale_amount);
51248c2ecf20Sopenharmony_ci}
51258c2ecf20Sopenharmony_ci
51268c2ecf20Sopenharmony_cistatic int
51278c2ecf20Sopenharmony_ciskl_compute_wm_params(const struct intel_crtc_state *crtc_state,
51288c2ecf20Sopenharmony_ci		      int width, const struct drm_format_info *format,
51298c2ecf20Sopenharmony_ci		      u64 modifier, unsigned int rotation,
51308c2ecf20Sopenharmony_ci		      u32 plane_pixel_rate, struct skl_wm_params *wp,
51318c2ecf20Sopenharmony_ci		      int color_plane)
51328c2ecf20Sopenharmony_ci{
51338c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
51348c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
51358c2ecf20Sopenharmony_ci	u32 interm_pbpl;
51368c2ecf20Sopenharmony_ci
51378c2ecf20Sopenharmony_ci	/* only planar format has two planes */
51388c2ecf20Sopenharmony_ci	if (color_plane == 1 &&
51398c2ecf20Sopenharmony_ci	    !intel_format_info_is_yuv_semiplanar(format, modifier)) {
51408c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
51418c2ecf20Sopenharmony_ci			    "Non planar format have single plane\n");
51428c2ecf20Sopenharmony_ci		return -EINVAL;
51438c2ecf20Sopenharmony_ci	}
51448c2ecf20Sopenharmony_ci
51458c2ecf20Sopenharmony_ci	wp->y_tiled = modifier == I915_FORMAT_MOD_Y_TILED ||
51468c2ecf20Sopenharmony_ci		      modifier == I915_FORMAT_MOD_Yf_TILED ||
51478c2ecf20Sopenharmony_ci		      modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
51488c2ecf20Sopenharmony_ci		      modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
51498c2ecf20Sopenharmony_ci		      modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
51508c2ecf20Sopenharmony_ci		      modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
51518c2ecf20Sopenharmony_ci	wp->x_tiled = modifier == I915_FORMAT_MOD_X_TILED;
51528c2ecf20Sopenharmony_ci	wp->rc_surface = modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
51538c2ecf20Sopenharmony_ci			 modifier == I915_FORMAT_MOD_Yf_TILED_CCS ||
51548c2ecf20Sopenharmony_ci			 modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS ||
51558c2ecf20Sopenharmony_ci			 modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
51568c2ecf20Sopenharmony_ci	wp->is_planar = intel_format_info_is_yuv_semiplanar(format, modifier);
51578c2ecf20Sopenharmony_ci
51588c2ecf20Sopenharmony_ci	wp->width = width;
51598c2ecf20Sopenharmony_ci	if (color_plane == 1 && wp->is_planar)
51608c2ecf20Sopenharmony_ci		wp->width /= 2;
51618c2ecf20Sopenharmony_ci
51628c2ecf20Sopenharmony_ci	wp->cpp = format->cpp[color_plane];
51638c2ecf20Sopenharmony_ci	wp->plane_pixel_rate = plane_pixel_rate;
51648c2ecf20Sopenharmony_ci
51658c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11 &&
51668c2ecf20Sopenharmony_ci	    modifier == I915_FORMAT_MOD_Yf_TILED  && wp->cpp == 1)
51678c2ecf20Sopenharmony_ci		wp->dbuf_block_size = 256;
51688c2ecf20Sopenharmony_ci	else
51698c2ecf20Sopenharmony_ci		wp->dbuf_block_size = 512;
51708c2ecf20Sopenharmony_ci
51718c2ecf20Sopenharmony_ci	if (drm_rotation_90_or_270(rotation)) {
51728c2ecf20Sopenharmony_ci		switch (wp->cpp) {
51738c2ecf20Sopenharmony_ci		case 1:
51748c2ecf20Sopenharmony_ci			wp->y_min_scanlines = 16;
51758c2ecf20Sopenharmony_ci			break;
51768c2ecf20Sopenharmony_ci		case 2:
51778c2ecf20Sopenharmony_ci			wp->y_min_scanlines = 8;
51788c2ecf20Sopenharmony_ci			break;
51798c2ecf20Sopenharmony_ci		case 4:
51808c2ecf20Sopenharmony_ci			wp->y_min_scanlines = 4;
51818c2ecf20Sopenharmony_ci			break;
51828c2ecf20Sopenharmony_ci		default:
51838c2ecf20Sopenharmony_ci			MISSING_CASE(wp->cpp);
51848c2ecf20Sopenharmony_ci			return -EINVAL;
51858c2ecf20Sopenharmony_ci		}
51868c2ecf20Sopenharmony_ci	} else {
51878c2ecf20Sopenharmony_ci		wp->y_min_scanlines = 4;
51888c2ecf20Sopenharmony_ci	}
51898c2ecf20Sopenharmony_ci
51908c2ecf20Sopenharmony_ci	if (skl_needs_memory_bw_wa(dev_priv))
51918c2ecf20Sopenharmony_ci		wp->y_min_scanlines *= 2;
51928c2ecf20Sopenharmony_ci
51938c2ecf20Sopenharmony_ci	wp->plane_bytes_per_line = wp->width * wp->cpp;
51948c2ecf20Sopenharmony_ci	if (wp->y_tiled) {
51958c2ecf20Sopenharmony_ci		interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line *
51968c2ecf20Sopenharmony_ci					   wp->y_min_scanlines,
51978c2ecf20Sopenharmony_ci					   wp->dbuf_block_size);
51988c2ecf20Sopenharmony_ci
51998c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
52008c2ecf20Sopenharmony_ci			interm_pbpl++;
52018c2ecf20Sopenharmony_ci
52028c2ecf20Sopenharmony_ci		wp->plane_blocks_per_line = div_fixed16(interm_pbpl,
52038c2ecf20Sopenharmony_ci							wp->y_min_scanlines);
52048c2ecf20Sopenharmony_ci	} else {
52058c2ecf20Sopenharmony_ci		interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line,
52068c2ecf20Sopenharmony_ci					   wp->dbuf_block_size);
52078c2ecf20Sopenharmony_ci
52088c2ecf20Sopenharmony_ci		if (!wp->x_tiled ||
52098c2ecf20Sopenharmony_ci		    INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
52108c2ecf20Sopenharmony_ci			interm_pbpl++;
52118c2ecf20Sopenharmony_ci
52128c2ecf20Sopenharmony_ci		wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
52138c2ecf20Sopenharmony_ci	}
52148c2ecf20Sopenharmony_ci
52158c2ecf20Sopenharmony_ci	wp->y_tile_minimum = mul_u32_fixed16(wp->y_min_scanlines,
52168c2ecf20Sopenharmony_ci					     wp->plane_blocks_per_line);
52178c2ecf20Sopenharmony_ci
52188c2ecf20Sopenharmony_ci	wp->linetime_us = fixed16_to_u32_round_up(
52198c2ecf20Sopenharmony_ci					intel_get_linetime_us(crtc_state));
52208c2ecf20Sopenharmony_ci
52218c2ecf20Sopenharmony_ci	return 0;
52228c2ecf20Sopenharmony_ci}
52238c2ecf20Sopenharmony_ci
52248c2ecf20Sopenharmony_cistatic int
52258c2ecf20Sopenharmony_ciskl_compute_plane_wm_params(const struct intel_crtc_state *crtc_state,
52268c2ecf20Sopenharmony_ci			    const struct intel_plane_state *plane_state,
52278c2ecf20Sopenharmony_ci			    struct skl_wm_params *wp, int color_plane)
52288c2ecf20Sopenharmony_ci{
52298c2ecf20Sopenharmony_ci	const struct drm_framebuffer *fb = plane_state->hw.fb;
52308c2ecf20Sopenharmony_ci	int width;
52318c2ecf20Sopenharmony_ci
52328c2ecf20Sopenharmony_ci	/*
52338c2ecf20Sopenharmony_ci	 * Src coordinates are already rotated by 270 degrees for
52348c2ecf20Sopenharmony_ci	 * the 90/270 degree plane rotation cases (to match the
52358c2ecf20Sopenharmony_ci	 * GTT mapping), hence no need to account for rotation here.
52368c2ecf20Sopenharmony_ci	 */
52378c2ecf20Sopenharmony_ci	width = drm_rect_width(&plane_state->uapi.src) >> 16;
52388c2ecf20Sopenharmony_ci
52398c2ecf20Sopenharmony_ci	return skl_compute_wm_params(crtc_state, width,
52408c2ecf20Sopenharmony_ci				     fb->format, fb->modifier,
52418c2ecf20Sopenharmony_ci				     plane_state->hw.rotation,
52428c2ecf20Sopenharmony_ci				     skl_adjusted_plane_pixel_rate(crtc_state, plane_state),
52438c2ecf20Sopenharmony_ci				     wp, color_plane);
52448c2ecf20Sopenharmony_ci}
52458c2ecf20Sopenharmony_ci
52468c2ecf20Sopenharmony_cistatic bool skl_wm_has_lines(struct drm_i915_private *dev_priv, int level)
52478c2ecf20Sopenharmony_ci{
52488c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
52498c2ecf20Sopenharmony_ci		return true;
52508c2ecf20Sopenharmony_ci
52518c2ecf20Sopenharmony_ci	/* The number of lines are ignored for the level 0 watermark. */
52528c2ecf20Sopenharmony_ci	return level > 0;
52538c2ecf20Sopenharmony_ci}
52548c2ecf20Sopenharmony_ci
52558c2ecf20Sopenharmony_cistatic void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state,
52568c2ecf20Sopenharmony_ci				 int level,
52578c2ecf20Sopenharmony_ci				 unsigned int latency,
52588c2ecf20Sopenharmony_ci				 const struct skl_wm_params *wp,
52598c2ecf20Sopenharmony_ci				 const struct skl_wm_level *result_prev,
52608c2ecf20Sopenharmony_ci				 struct skl_wm_level *result /* out */)
52618c2ecf20Sopenharmony_ci{
52628c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
52638c2ecf20Sopenharmony_ci	uint_fixed_16_16_t method1, method2;
52648c2ecf20Sopenharmony_ci	uint_fixed_16_16_t selected_result;
52658c2ecf20Sopenharmony_ci	u32 res_blocks, res_lines, min_ddb_alloc = 0;
52668c2ecf20Sopenharmony_ci
52678c2ecf20Sopenharmony_ci	if (latency == 0) {
52688c2ecf20Sopenharmony_ci		/* reject it */
52698c2ecf20Sopenharmony_ci		result->min_ddb_alloc = U16_MAX;
52708c2ecf20Sopenharmony_ci		return;
52718c2ecf20Sopenharmony_ci	}
52728c2ecf20Sopenharmony_ci
52738c2ecf20Sopenharmony_ci	/*
52748c2ecf20Sopenharmony_ci	 * WaIncreaseLatencyIPCEnabled: kbl,cfl
52758c2ecf20Sopenharmony_ci	 * Display WA #1141: kbl,cfl
52768c2ecf20Sopenharmony_ci	 */
52778c2ecf20Sopenharmony_ci	if ((IS_KABYLAKE(dev_priv) ||
52788c2ecf20Sopenharmony_ci	     IS_COFFEELAKE(dev_priv) ||
52798c2ecf20Sopenharmony_ci	     IS_COMETLAKE(dev_priv)) &&
52808c2ecf20Sopenharmony_ci	    dev_priv->ipc_enabled)
52818c2ecf20Sopenharmony_ci		latency += 4;
52828c2ecf20Sopenharmony_ci
52838c2ecf20Sopenharmony_ci	if (skl_needs_memory_bw_wa(dev_priv) && wp->x_tiled)
52848c2ecf20Sopenharmony_ci		latency += 15;
52858c2ecf20Sopenharmony_ci
52868c2ecf20Sopenharmony_ci	method1 = skl_wm_method1(dev_priv, wp->plane_pixel_rate,
52878c2ecf20Sopenharmony_ci				 wp->cpp, latency, wp->dbuf_block_size);
52888c2ecf20Sopenharmony_ci	method2 = skl_wm_method2(wp->plane_pixel_rate,
52898c2ecf20Sopenharmony_ci				 crtc_state->hw.adjusted_mode.crtc_htotal,
52908c2ecf20Sopenharmony_ci				 latency,
52918c2ecf20Sopenharmony_ci				 wp->plane_blocks_per_line);
52928c2ecf20Sopenharmony_ci
52938c2ecf20Sopenharmony_ci	if (wp->y_tiled) {
52948c2ecf20Sopenharmony_ci		selected_result = max_fixed16(method2, wp->y_tile_minimum);
52958c2ecf20Sopenharmony_ci	} else {
52968c2ecf20Sopenharmony_ci		if ((wp->cpp * crtc_state->hw.adjusted_mode.crtc_htotal /
52978c2ecf20Sopenharmony_ci		     wp->dbuf_block_size < 1) &&
52988c2ecf20Sopenharmony_ci		     (wp->plane_bytes_per_line / wp->dbuf_block_size < 1)) {
52998c2ecf20Sopenharmony_ci			selected_result = method2;
53008c2ecf20Sopenharmony_ci		} else if (latency >= wp->linetime_us) {
53018c2ecf20Sopenharmony_ci			if (IS_GEN(dev_priv, 9) &&
53028c2ecf20Sopenharmony_ci			    !IS_GEMINILAKE(dev_priv))
53038c2ecf20Sopenharmony_ci				selected_result = min_fixed16(method1, method2);
53048c2ecf20Sopenharmony_ci			else
53058c2ecf20Sopenharmony_ci				selected_result = method2;
53068c2ecf20Sopenharmony_ci		} else {
53078c2ecf20Sopenharmony_ci			selected_result = method1;
53088c2ecf20Sopenharmony_ci		}
53098c2ecf20Sopenharmony_ci	}
53108c2ecf20Sopenharmony_ci
53118c2ecf20Sopenharmony_ci	res_blocks = fixed16_to_u32_round_up(selected_result) + 1;
53128c2ecf20Sopenharmony_ci	res_lines = div_round_up_fixed16(selected_result,
53138c2ecf20Sopenharmony_ci					 wp->plane_blocks_per_line);
53148c2ecf20Sopenharmony_ci
53158c2ecf20Sopenharmony_ci	if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) {
53168c2ecf20Sopenharmony_ci		/* Display WA #1125: skl,bxt,kbl */
53178c2ecf20Sopenharmony_ci		if (level == 0 && wp->rc_surface)
53188c2ecf20Sopenharmony_ci			res_blocks +=
53198c2ecf20Sopenharmony_ci				fixed16_to_u32_round_up(wp->y_tile_minimum);
53208c2ecf20Sopenharmony_ci
53218c2ecf20Sopenharmony_ci		/* Display WA #1126: skl,bxt,kbl */
53228c2ecf20Sopenharmony_ci		if (level >= 1 && level <= 7) {
53238c2ecf20Sopenharmony_ci			if (wp->y_tiled) {
53248c2ecf20Sopenharmony_ci				res_blocks +=
53258c2ecf20Sopenharmony_ci				    fixed16_to_u32_round_up(wp->y_tile_minimum);
53268c2ecf20Sopenharmony_ci				res_lines += wp->y_min_scanlines;
53278c2ecf20Sopenharmony_ci			} else {
53288c2ecf20Sopenharmony_ci				res_blocks++;
53298c2ecf20Sopenharmony_ci			}
53308c2ecf20Sopenharmony_ci
53318c2ecf20Sopenharmony_ci			/*
53328c2ecf20Sopenharmony_ci			 * Make sure result blocks for higher latency levels are
53338c2ecf20Sopenharmony_ci			 * atleast as high as level below the current level.
53348c2ecf20Sopenharmony_ci			 * Assumption in DDB algorithm optimization for special
53358c2ecf20Sopenharmony_ci			 * cases. Also covers Display WA #1125 for RC.
53368c2ecf20Sopenharmony_ci			 */
53378c2ecf20Sopenharmony_ci			if (result_prev->plane_res_b > res_blocks)
53388c2ecf20Sopenharmony_ci				res_blocks = result_prev->plane_res_b;
53398c2ecf20Sopenharmony_ci		}
53408c2ecf20Sopenharmony_ci	}
53418c2ecf20Sopenharmony_ci
53428c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11) {
53438c2ecf20Sopenharmony_ci		if (wp->y_tiled) {
53448c2ecf20Sopenharmony_ci			int extra_lines;
53458c2ecf20Sopenharmony_ci
53468c2ecf20Sopenharmony_ci			if (res_lines % wp->y_min_scanlines == 0)
53478c2ecf20Sopenharmony_ci				extra_lines = wp->y_min_scanlines;
53488c2ecf20Sopenharmony_ci			else
53498c2ecf20Sopenharmony_ci				extra_lines = wp->y_min_scanlines * 2 -
53508c2ecf20Sopenharmony_ci					res_lines % wp->y_min_scanlines;
53518c2ecf20Sopenharmony_ci
53528c2ecf20Sopenharmony_ci			min_ddb_alloc = mul_round_up_u32_fixed16(res_lines + extra_lines,
53538c2ecf20Sopenharmony_ci								 wp->plane_blocks_per_line);
53548c2ecf20Sopenharmony_ci		} else {
53558c2ecf20Sopenharmony_ci			min_ddb_alloc = res_blocks +
53568c2ecf20Sopenharmony_ci				DIV_ROUND_UP(res_blocks, 10);
53578c2ecf20Sopenharmony_ci		}
53588c2ecf20Sopenharmony_ci	}
53598c2ecf20Sopenharmony_ci
53608c2ecf20Sopenharmony_ci	if (!skl_wm_has_lines(dev_priv, level))
53618c2ecf20Sopenharmony_ci		res_lines = 0;
53628c2ecf20Sopenharmony_ci
53638c2ecf20Sopenharmony_ci	if (res_lines > 31) {
53648c2ecf20Sopenharmony_ci		/* reject it */
53658c2ecf20Sopenharmony_ci		result->min_ddb_alloc = U16_MAX;
53668c2ecf20Sopenharmony_ci		return;
53678c2ecf20Sopenharmony_ci	}
53688c2ecf20Sopenharmony_ci
53698c2ecf20Sopenharmony_ci	/*
53708c2ecf20Sopenharmony_ci	 * If res_lines is valid, assume we can use this watermark level
53718c2ecf20Sopenharmony_ci	 * for now.  We'll come back and disable it after we calculate the
53728c2ecf20Sopenharmony_ci	 * DDB allocation if it turns out we don't actually have enough
53738c2ecf20Sopenharmony_ci	 * blocks to satisfy it.
53748c2ecf20Sopenharmony_ci	 */
53758c2ecf20Sopenharmony_ci	result->plane_res_b = res_blocks;
53768c2ecf20Sopenharmony_ci	result->plane_res_l = res_lines;
53778c2ecf20Sopenharmony_ci	/* Bspec says: value >= plane ddb allocation -> invalid, hence the +1 here */
53788c2ecf20Sopenharmony_ci	result->min_ddb_alloc = max(min_ddb_alloc, res_blocks) + 1;
53798c2ecf20Sopenharmony_ci	result->plane_en = true;
53808c2ecf20Sopenharmony_ci}
53818c2ecf20Sopenharmony_ci
53828c2ecf20Sopenharmony_cistatic void
53838c2ecf20Sopenharmony_ciskl_compute_wm_levels(const struct intel_crtc_state *crtc_state,
53848c2ecf20Sopenharmony_ci		      const struct skl_wm_params *wm_params,
53858c2ecf20Sopenharmony_ci		      struct skl_wm_level *levels)
53868c2ecf20Sopenharmony_ci{
53878c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
53888c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
53898c2ecf20Sopenharmony_ci	struct skl_wm_level *result_prev = &levels[0];
53908c2ecf20Sopenharmony_ci
53918c2ecf20Sopenharmony_ci	for (level = 0; level <= max_level; level++) {
53928c2ecf20Sopenharmony_ci		struct skl_wm_level *result = &levels[level];
53938c2ecf20Sopenharmony_ci		unsigned int latency = dev_priv->wm.skl_latency[level];
53948c2ecf20Sopenharmony_ci
53958c2ecf20Sopenharmony_ci		skl_compute_plane_wm(crtc_state, level, latency,
53968c2ecf20Sopenharmony_ci				     wm_params, result_prev, result);
53978c2ecf20Sopenharmony_ci
53988c2ecf20Sopenharmony_ci		result_prev = result;
53998c2ecf20Sopenharmony_ci	}
54008c2ecf20Sopenharmony_ci}
54018c2ecf20Sopenharmony_ci
54028c2ecf20Sopenharmony_cistatic void tgl_compute_sagv_wm(const struct intel_crtc_state *crtc_state,
54038c2ecf20Sopenharmony_ci				const struct skl_wm_params *wm_params,
54048c2ecf20Sopenharmony_ci				struct skl_plane_wm *plane_wm)
54058c2ecf20Sopenharmony_ci{
54068c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
54078c2ecf20Sopenharmony_ci	struct skl_wm_level *sagv_wm = &plane_wm->sagv_wm0;
54088c2ecf20Sopenharmony_ci	struct skl_wm_level *levels = plane_wm->wm;
54098c2ecf20Sopenharmony_ci	unsigned int latency = dev_priv->wm.skl_latency[0] + dev_priv->sagv_block_time_us;
54108c2ecf20Sopenharmony_ci
54118c2ecf20Sopenharmony_ci	skl_compute_plane_wm(crtc_state, 0, latency,
54128c2ecf20Sopenharmony_ci			     wm_params, &levels[0],
54138c2ecf20Sopenharmony_ci			     sagv_wm);
54148c2ecf20Sopenharmony_ci}
54158c2ecf20Sopenharmony_ci
54168c2ecf20Sopenharmony_cistatic void skl_compute_transition_wm(const struct intel_crtc_state *crtc_state,
54178c2ecf20Sopenharmony_ci				      const struct skl_wm_params *wp,
54188c2ecf20Sopenharmony_ci				      struct skl_plane_wm *wm)
54198c2ecf20Sopenharmony_ci{
54208c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc_state->uapi.crtc->dev;
54218c2ecf20Sopenharmony_ci	const struct drm_i915_private *dev_priv = to_i915(dev);
54228c2ecf20Sopenharmony_ci	u16 trans_min, trans_amount, trans_y_tile_min;
54238c2ecf20Sopenharmony_ci	u16 wm0_sel_res_b, trans_offset_b, res_blocks;
54248c2ecf20Sopenharmony_ci
54258c2ecf20Sopenharmony_ci	/* Transition WM don't make any sense if ipc is disabled */
54268c2ecf20Sopenharmony_ci	if (!dev_priv->ipc_enabled)
54278c2ecf20Sopenharmony_ci		return;
54288c2ecf20Sopenharmony_ci
54298c2ecf20Sopenharmony_ci	/*
54308c2ecf20Sopenharmony_ci	 * WaDisableTWM:skl,kbl,cfl,bxt
54318c2ecf20Sopenharmony_ci	 * Transition WM are not recommended by HW team for GEN9
54328c2ecf20Sopenharmony_ci	 */
54338c2ecf20Sopenharmony_ci	if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv))
54348c2ecf20Sopenharmony_ci		return;
54358c2ecf20Sopenharmony_ci
54368c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11)
54378c2ecf20Sopenharmony_ci		trans_min = 4;
54388c2ecf20Sopenharmony_ci	else
54398c2ecf20Sopenharmony_ci		trans_min = 14;
54408c2ecf20Sopenharmony_ci
54418c2ecf20Sopenharmony_ci	/* Display WA #1140: glk,cnl */
54428c2ecf20Sopenharmony_ci	if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
54438c2ecf20Sopenharmony_ci		trans_amount = 0;
54448c2ecf20Sopenharmony_ci	else
54458c2ecf20Sopenharmony_ci		trans_amount = 10; /* This is configurable amount */
54468c2ecf20Sopenharmony_ci
54478c2ecf20Sopenharmony_ci	trans_offset_b = trans_min + trans_amount;
54488c2ecf20Sopenharmony_ci
54498c2ecf20Sopenharmony_ci	/*
54508c2ecf20Sopenharmony_ci	 * The spec asks for Selected Result Blocks for wm0 (the real value),
54518c2ecf20Sopenharmony_ci	 * not Result Blocks (the integer value). Pay attention to the capital
54528c2ecf20Sopenharmony_ci	 * letters. The value wm_l0->plane_res_b is actually Result Blocks, but
54538c2ecf20Sopenharmony_ci	 * since Result Blocks is the ceiling of Selected Result Blocks plus 1,
54548c2ecf20Sopenharmony_ci	 * and since we later will have to get the ceiling of the sum in the
54558c2ecf20Sopenharmony_ci	 * transition watermarks calculation, we can just pretend Selected
54568c2ecf20Sopenharmony_ci	 * Result Blocks is Result Blocks minus 1 and it should work for the
54578c2ecf20Sopenharmony_ci	 * current platforms.
54588c2ecf20Sopenharmony_ci	 */
54598c2ecf20Sopenharmony_ci	wm0_sel_res_b = wm->wm[0].plane_res_b - 1;
54608c2ecf20Sopenharmony_ci
54618c2ecf20Sopenharmony_ci	if (wp->y_tiled) {
54628c2ecf20Sopenharmony_ci		trans_y_tile_min =
54638c2ecf20Sopenharmony_ci			(u16)mul_round_up_u32_fixed16(2, wp->y_tile_minimum);
54648c2ecf20Sopenharmony_ci		res_blocks = max(wm0_sel_res_b, trans_y_tile_min) +
54658c2ecf20Sopenharmony_ci				trans_offset_b;
54668c2ecf20Sopenharmony_ci	} else {
54678c2ecf20Sopenharmony_ci		res_blocks = wm0_sel_res_b + trans_offset_b;
54688c2ecf20Sopenharmony_ci	}
54698c2ecf20Sopenharmony_ci
54708c2ecf20Sopenharmony_ci	/*
54718c2ecf20Sopenharmony_ci	 * Just assume we can enable the transition watermark.  After
54728c2ecf20Sopenharmony_ci	 * computing the DDB we'll come back and disable it if that
54738c2ecf20Sopenharmony_ci	 * assumption turns out to be false.
54748c2ecf20Sopenharmony_ci	 */
54758c2ecf20Sopenharmony_ci	wm->trans_wm.plane_res_b = res_blocks + 1;
54768c2ecf20Sopenharmony_ci	wm->trans_wm.plane_en = true;
54778c2ecf20Sopenharmony_ci}
54788c2ecf20Sopenharmony_ci
54798c2ecf20Sopenharmony_cistatic int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state,
54808c2ecf20Sopenharmony_ci				     const struct intel_plane_state *plane_state,
54818c2ecf20Sopenharmony_ci				     enum plane_id plane_id, int color_plane)
54828c2ecf20Sopenharmony_ci{
54838c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
54848c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
54858c2ecf20Sopenharmony_ci	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
54868c2ecf20Sopenharmony_ci	struct skl_wm_params wm_params;
54878c2ecf20Sopenharmony_ci	int ret;
54888c2ecf20Sopenharmony_ci
54898c2ecf20Sopenharmony_ci	ret = skl_compute_plane_wm_params(crtc_state, plane_state,
54908c2ecf20Sopenharmony_ci					  &wm_params, color_plane);
54918c2ecf20Sopenharmony_ci	if (ret)
54928c2ecf20Sopenharmony_ci		return ret;
54938c2ecf20Sopenharmony_ci
54948c2ecf20Sopenharmony_ci	skl_compute_wm_levels(crtc_state, &wm_params, wm->wm);
54958c2ecf20Sopenharmony_ci
54968c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 12)
54978c2ecf20Sopenharmony_ci		tgl_compute_sagv_wm(crtc_state, &wm_params, wm);
54988c2ecf20Sopenharmony_ci
54998c2ecf20Sopenharmony_ci	skl_compute_transition_wm(crtc_state, &wm_params, wm);
55008c2ecf20Sopenharmony_ci
55018c2ecf20Sopenharmony_ci	return 0;
55028c2ecf20Sopenharmony_ci}
55038c2ecf20Sopenharmony_ci
55048c2ecf20Sopenharmony_cistatic int skl_build_plane_wm_uv(struct intel_crtc_state *crtc_state,
55058c2ecf20Sopenharmony_ci				 const struct intel_plane_state *plane_state,
55068c2ecf20Sopenharmony_ci				 enum plane_id plane_id)
55078c2ecf20Sopenharmony_ci{
55088c2ecf20Sopenharmony_ci	struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id];
55098c2ecf20Sopenharmony_ci	struct skl_wm_params wm_params;
55108c2ecf20Sopenharmony_ci	int ret;
55118c2ecf20Sopenharmony_ci
55128c2ecf20Sopenharmony_ci	wm->is_planar = true;
55138c2ecf20Sopenharmony_ci
55148c2ecf20Sopenharmony_ci	/* uv plane watermarks must also be validated for NV12/Planar */
55158c2ecf20Sopenharmony_ci	ret = skl_compute_plane_wm_params(crtc_state, plane_state,
55168c2ecf20Sopenharmony_ci					  &wm_params, 1);
55178c2ecf20Sopenharmony_ci	if (ret)
55188c2ecf20Sopenharmony_ci		return ret;
55198c2ecf20Sopenharmony_ci
55208c2ecf20Sopenharmony_ci	skl_compute_wm_levels(crtc_state, &wm_params, wm->uv_wm);
55218c2ecf20Sopenharmony_ci
55228c2ecf20Sopenharmony_ci	return 0;
55238c2ecf20Sopenharmony_ci}
55248c2ecf20Sopenharmony_ci
55258c2ecf20Sopenharmony_cistatic int skl_build_plane_wm(struct intel_crtc_state *crtc_state,
55268c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state)
55278c2ecf20Sopenharmony_ci{
55288c2ecf20Sopenharmony_ci	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
55298c2ecf20Sopenharmony_ci	const struct drm_framebuffer *fb = plane_state->hw.fb;
55308c2ecf20Sopenharmony_ci	enum plane_id plane_id = plane->id;
55318c2ecf20Sopenharmony_ci	int ret;
55328c2ecf20Sopenharmony_ci
55338c2ecf20Sopenharmony_ci	if (!intel_wm_plane_visible(crtc_state, plane_state))
55348c2ecf20Sopenharmony_ci		return 0;
55358c2ecf20Sopenharmony_ci
55368c2ecf20Sopenharmony_ci	ret = skl_build_plane_wm_single(crtc_state, plane_state,
55378c2ecf20Sopenharmony_ci					plane_id, 0);
55388c2ecf20Sopenharmony_ci	if (ret)
55398c2ecf20Sopenharmony_ci		return ret;
55408c2ecf20Sopenharmony_ci
55418c2ecf20Sopenharmony_ci	if (fb->format->is_yuv && fb->format->num_planes > 1) {
55428c2ecf20Sopenharmony_ci		ret = skl_build_plane_wm_uv(crtc_state, plane_state,
55438c2ecf20Sopenharmony_ci					    plane_id);
55448c2ecf20Sopenharmony_ci		if (ret)
55458c2ecf20Sopenharmony_ci			return ret;
55468c2ecf20Sopenharmony_ci	}
55478c2ecf20Sopenharmony_ci
55488c2ecf20Sopenharmony_ci	return 0;
55498c2ecf20Sopenharmony_ci}
55508c2ecf20Sopenharmony_ci
55518c2ecf20Sopenharmony_cistatic int icl_build_plane_wm(struct intel_crtc_state *crtc_state,
55528c2ecf20Sopenharmony_ci			      const struct intel_plane_state *plane_state)
55538c2ecf20Sopenharmony_ci{
55548c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
55558c2ecf20Sopenharmony_ci	enum plane_id plane_id = to_intel_plane(plane_state->uapi.plane)->id;
55568c2ecf20Sopenharmony_ci	int ret;
55578c2ecf20Sopenharmony_ci
55588c2ecf20Sopenharmony_ci	/* Watermarks calculated in master */
55598c2ecf20Sopenharmony_ci	if (plane_state->planar_slave)
55608c2ecf20Sopenharmony_ci		return 0;
55618c2ecf20Sopenharmony_ci
55628c2ecf20Sopenharmony_ci	if (plane_state->planar_linked_plane) {
55638c2ecf20Sopenharmony_ci		const struct drm_framebuffer *fb = plane_state->hw.fb;
55648c2ecf20Sopenharmony_ci		enum plane_id y_plane_id = plane_state->planar_linked_plane->id;
55658c2ecf20Sopenharmony_ci
55668c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
55678c2ecf20Sopenharmony_ci			    !intel_wm_plane_visible(crtc_state, plane_state));
55688c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, !fb->format->is_yuv ||
55698c2ecf20Sopenharmony_ci			    fb->format->num_planes == 1);
55708c2ecf20Sopenharmony_ci
55718c2ecf20Sopenharmony_ci		ret = skl_build_plane_wm_single(crtc_state, plane_state,
55728c2ecf20Sopenharmony_ci						y_plane_id, 0);
55738c2ecf20Sopenharmony_ci		if (ret)
55748c2ecf20Sopenharmony_ci			return ret;
55758c2ecf20Sopenharmony_ci
55768c2ecf20Sopenharmony_ci		ret = skl_build_plane_wm_single(crtc_state, plane_state,
55778c2ecf20Sopenharmony_ci						plane_id, 1);
55788c2ecf20Sopenharmony_ci		if (ret)
55798c2ecf20Sopenharmony_ci			return ret;
55808c2ecf20Sopenharmony_ci	} else if (intel_wm_plane_visible(crtc_state, plane_state)) {
55818c2ecf20Sopenharmony_ci		ret = skl_build_plane_wm_single(crtc_state, plane_state,
55828c2ecf20Sopenharmony_ci						plane_id, 0);
55838c2ecf20Sopenharmony_ci		if (ret)
55848c2ecf20Sopenharmony_ci			return ret;
55858c2ecf20Sopenharmony_ci	}
55868c2ecf20Sopenharmony_ci
55878c2ecf20Sopenharmony_ci	return 0;
55888c2ecf20Sopenharmony_ci}
55898c2ecf20Sopenharmony_ci
55908c2ecf20Sopenharmony_cistatic int skl_build_pipe_wm(struct intel_crtc_state *crtc_state)
55918c2ecf20Sopenharmony_ci{
55928c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
55938c2ecf20Sopenharmony_ci	struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal;
55948c2ecf20Sopenharmony_ci	struct intel_plane *plane;
55958c2ecf20Sopenharmony_ci	const struct intel_plane_state *plane_state;
55968c2ecf20Sopenharmony_ci	int ret;
55978c2ecf20Sopenharmony_ci
55988c2ecf20Sopenharmony_ci	/*
55998c2ecf20Sopenharmony_ci	 * We'll only calculate watermarks for planes that are actually
56008c2ecf20Sopenharmony_ci	 * enabled, so make sure all other planes are set as disabled.
56018c2ecf20Sopenharmony_ci	 */
56028c2ecf20Sopenharmony_ci	memset(pipe_wm->planes, 0, sizeof(pipe_wm->planes));
56038c2ecf20Sopenharmony_ci
56048c2ecf20Sopenharmony_ci	intel_atomic_crtc_state_for_each_plane_state(plane, plane_state,
56058c2ecf20Sopenharmony_ci						     crtc_state) {
56068c2ecf20Sopenharmony_ci
56078c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 11)
56088c2ecf20Sopenharmony_ci			ret = icl_build_plane_wm(crtc_state, plane_state);
56098c2ecf20Sopenharmony_ci		else
56108c2ecf20Sopenharmony_ci			ret = skl_build_plane_wm(crtc_state, plane_state);
56118c2ecf20Sopenharmony_ci		if (ret)
56128c2ecf20Sopenharmony_ci			return ret;
56138c2ecf20Sopenharmony_ci	}
56148c2ecf20Sopenharmony_ci
56158c2ecf20Sopenharmony_ci	return 0;
56168c2ecf20Sopenharmony_ci}
56178c2ecf20Sopenharmony_ci
56188c2ecf20Sopenharmony_cistatic void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
56198c2ecf20Sopenharmony_ci				i915_reg_t reg,
56208c2ecf20Sopenharmony_ci				const struct skl_ddb_entry *entry)
56218c2ecf20Sopenharmony_ci{
56228c2ecf20Sopenharmony_ci	if (entry->end)
56238c2ecf20Sopenharmony_ci		intel_de_write_fw(dev_priv, reg,
56248c2ecf20Sopenharmony_ci				  (entry->end - 1) << 16 | entry->start);
56258c2ecf20Sopenharmony_ci	else
56268c2ecf20Sopenharmony_ci		intel_de_write_fw(dev_priv, reg, 0);
56278c2ecf20Sopenharmony_ci}
56288c2ecf20Sopenharmony_ci
56298c2ecf20Sopenharmony_cistatic void skl_write_wm_level(struct drm_i915_private *dev_priv,
56308c2ecf20Sopenharmony_ci			       i915_reg_t reg,
56318c2ecf20Sopenharmony_ci			       const struct skl_wm_level *level)
56328c2ecf20Sopenharmony_ci{
56338c2ecf20Sopenharmony_ci	u32 val = 0;
56348c2ecf20Sopenharmony_ci
56358c2ecf20Sopenharmony_ci	if (level->plane_en)
56368c2ecf20Sopenharmony_ci		val |= PLANE_WM_EN;
56378c2ecf20Sopenharmony_ci	if (level->ignore_lines)
56388c2ecf20Sopenharmony_ci		val |= PLANE_WM_IGNORE_LINES;
56398c2ecf20Sopenharmony_ci	val |= level->plane_res_b;
56408c2ecf20Sopenharmony_ci	val |= level->plane_res_l << PLANE_WM_LINES_SHIFT;
56418c2ecf20Sopenharmony_ci
56428c2ecf20Sopenharmony_ci	intel_de_write_fw(dev_priv, reg, val);
56438c2ecf20Sopenharmony_ci}
56448c2ecf20Sopenharmony_ci
56458c2ecf20Sopenharmony_civoid skl_write_plane_wm(struct intel_plane *plane,
56468c2ecf20Sopenharmony_ci			const struct intel_crtc_state *crtc_state)
56478c2ecf20Sopenharmony_ci{
56488c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
56498c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
56508c2ecf20Sopenharmony_ci	enum plane_id plane_id = plane->id;
56518c2ecf20Sopenharmony_ci	enum pipe pipe = plane->pipe;
56528c2ecf20Sopenharmony_ci	const struct skl_plane_wm *wm =
56538c2ecf20Sopenharmony_ci		&crtc_state->wm.skl.optimal.planes[plane_id];
56548c2ecf20Sopenharmony_ci	const struct skl_ddb_entry *ddb_y =
56558c2ecf20Sopenharmony_ci		&crtc_state->wm.skl.plane_ddb_y[plane_id];
56568c2ecf20Sopenharmony_ci	const struct skl_ddb_entry *ddb_uv =
56578c2ecf20Sopenharmony_ci		&crtc_state->wm.skl.plane_ddb_uv[plane_id];
56588c2ecf20Sopenharmony_ci
56598c2ecf20Sopenharmony_ci	for (level = 0; level <= max_level; level++) {
56608c2ecf20Sopenharmony_ci		const struct skl_wm_level *wm_level;
56618c2ecf20Sopenharmony_ci
56628c2ecf20Sopenharmony_ci		wm_level = skl_plane_wm_level(crtc_state, plane_id, level);
56638c2ecf20Sopenharmony_ci
56648c2ecf20Sopenharmony_ci		skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level),
56658c2ecf20Sopenharmony_ci				   wm_level);
56668c2ecf20Sopenharmony_ci	}
56678c2ecf20Sopenharmony_ci	skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id),
56688c2ecf20Sopenharmony_ci			   &wm->trans_wm);
56698c2ecf20Sopenharmony_ci
56708c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11) {
56718c2ecf20Sopenharmony_ci		skl_ddb_entry_write(dev_priv,
56728c2ecf20Sopenharmony_ci				    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
56738c2ecf20Sopenharmony_ci		return;
56748c2ecf20Sopenharmony_ci	}
56758c2ecf20Sopenharmony_ci
56768c2ecf20Sopenharmony_ci	if (wm->is_planar)
56778c2ecf20Sopenharmony_ci		swap(ddb_y, ddb_uv);
56788c2ecf20Sopenharmony_ci
56798c2ecf20Sopenharmony_ci	skl_ddb_entry_write(dev_priv,
56808c2ecf20Sopenharmony_ci			    PLANE_BUF_CFG(pipe, plane_id), ddb_y);
56818c2ecf20Sopenharmony_ci	skl_ddb_entry_write(dev_priv,
56828c2ecf20Sopenharmony_ci			    PLANE_NV12_BUF_CFG(pipe, plane_id), ddb_uv);
56838c2ecf20Sopenharmony_ci}
56848c2ecf20Sopenharmony_ci
56858c2ecf20Sopenharmony_civoid skl_write_cursor_wm(struct intel_plane *plane,
56868c2ecf20Sopenharmony_ci			 const struct intel_crtc_state *crtc_state)
56878c2ecf20Sopenharmony_ci{
56888c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
56898c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
56908c2ecf20Sopenharmony_ci	enum plane_id plane_id = plane->id;
56918c2ecf20Sopenharmony_ci	enum pipe pipe = plane->pipe;
56928c2ecf20Sopenharmony_ci	const struct skl_plane_wm *wm =
56938c2ecf20Sopenharmony_ci		&crtc_state->wm.skl.optimal.planes[plane_id];
56948c2ecf20Sopenharmony_ci	const struct skl_ddb_entry *ddb =
56958c2ecf20Sopenharmony_ci		&crtc_state->wm.skl.plane_ddb_y[plane_id];
56968c2ecf20Sopenharmony_ci
56978c2ecf20Sopenharmony_ci	for (level = 0; level <= max_level; level++) {
56988c2ecf20Sopenharmony_ci		const struct skl_wm_level *wm_level;
56998c2ecf20Sopenharmony_ci
57008c2ecf20Sopenharmony_ci		wm_level = skl_plane_wm_level(crtc_state, plane_id, level);
57018c2ecf20Sopenharmony_ci
57028c2ecf20Sopenharmony_ci		skl_write_wm_level(dev_priv, CUR_WM(pipe, level),
57038c2ecf20Sopenharmony_ci				   wm_level);
57048c2ecf20Sopenharmony_ci	}
57058c2ecf20Sopenharmony_ci	skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm);
57068c2ecf20Sopenharmony_ci
57078c2ecf20Sopenharmony_ci	skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb);
57088c2ecf20Sopenharmony_ci}
57098c2ecf20Sopenharmony_ci
57108c2ecf20Sopenharmony_cibool skl_wm_level_equals(const struct skl_wm_level *l1,
57118c2ecf20Sopenharmony_ci			 const struct skl_wm_level *l2)
57128c2ecf20Sopenharmony_ci{
57138c2ecf20Sopenharmony_ci	return l1->plane_en == l2->plane_en &&
57148c2ecf20Sopenharmony_ci		l1->ignore_lines == l2->ignore_lines &&
57158c2ecf20Sopenharmony_ci		l1->plane_res_l == l2->plane_res_l &&
57168c2ecf20Sopenharmony_ci		l1->plane_res_b == l2->plane_res_b;
57178c2ecf20Sopenharmony_ci}
57188c2ecf20Sopenharmony_ci
57198c2ecf20Sopenharmony_cistatic bool skl_plane_wm_equals(struct drm_i915_private *dev_priv,
57208c2ecf20Sopenharmony_ci				const struct skl_plane_wm *wm1,
57218c2ecf20Sopenharmony_ci				const struct skl_plane_wm *wm2)
57228c2ecf20Sopenharmony_ci{
57238c2ecf20Sopenharmony_ci	int level, max_level = ilk_wm_max_level(dev_priv);
57248c2ecf20Sopenharmony_ci
57258c2ecf20Sopenharmony_ci	for (level = 0; level <= max_level; level++) {
57268c2ecf20Sopenharmony_ci		/*
57278c2ecf20Sopenharmony_ci		 * We don't check uv_wm as the hardware doesn't actually
57288c2ecf20Sopenharmony_ci		 * use it. It only gets used for calculating the required
57298c2ecf20Sopenharmony_ci		 * ddb allocation.
57308c2ecf20Sopenharmony_ci		 */
57318c2ecf20Sopenharmony_ci		if (!skl_wm_level_equals(&wm1->wm[level], &wm2->wm[level]))
57328c2ecf20Sopenharmony_ci			return false;
57338c2ecf20Sopenharmony_ci	}
57348c2ecf20Sopenharmony_ci
57358c2ecf20Sopenharmony_ci	return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm);
57368c2ecf20Sopenharmony_ci}
57378c2ecf20Sopenharmony_ci
57388c2ecf20Sopenharmony_cistatic bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
57398c2ecf20Sopenharmony_ci				    const struct skl_ddb_entry *b)
57408c2ecf20Sopenharmony_ci{
57418c2ecf20Sopenharmony_ci	return a->start < b->end && b->start < a->end;
57428c2ecf20Sopenharmony_ci}
57438c2ecf20Sopenharmony_ci
57448c2ecf20Sopenharmony_cibool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb,
57458c2ecf20Sopenharmony_ci				 const struct skl_ddb_entry *entries,
57468c2ecf20Sopenharmony_ci				 int num_entries, int ignore_idx)
57478c2ecf20Sopenharmony_ci{
57488c2ecf20Sopenharmony_ci	int i;
57498c2ecf20Sopenharmony_ci
57508c2ecf20Sopenharmony_ci	for (i = 0; i < num_entries; i++) {
57518c2ecf20Sopenharmony_ci		if (i != ignore_idx &&
57528c2ecf20Sopenharmony_ci		    skl_ddb_entries_overlap(ddb, &entries[i]))
57538c2ecf20Sopenharmony_ci			return true;
57548c2ecf20Sopenharmony_ci	}
57558c2ecf20Sopenharmony_ci
57568c2ecf20Sopenharmony_ci	return false;
57578c2ecf20Sopenharmony_ci}
57588c2ecf20Sopenharmony_ci
57598c2ecf20Sopenharmony_cistatic int
57608c2ecf20Sopenharmony_ciskl_ddb_add_affected_planes(const struct intel_crtc_state *old_crtc_state,
57618c2ecf20Sopenharmony_ci			    struct intel_crtc_state *new_crtc_state)
57628c2ecf20Sopenharmony_ci{
57638c2ecf20Sopenharmony_ci	struct intel_atomic_state *state = to_intel_atomic_state(new_crtc_state->uapi.state);
57648c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
57658c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
57668c2ecf20Sopenharmony_ci	struct intel_plane *plane;
57678c2ecf20Sopenharmony_ci
57688c2ecf20Sopenharmony_ci	for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
57698c2ecf20Sopenharmony_ci		struct intel_plane_state *plane_state;
57708c2ecf20Sopenharmony_ci		enum plane_id plane_id = plane->id;
57718c2ecf20Sopenharmony_ci
57728c2ecf20Sopenharmony_ci		if (skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_y[plane_id],
57738c2ecf20Sopenharmony_ci					&new_crtc_state->wm.skl.plane_ddb_y[plane_id]) &&
57748c2ecf20Sopenharmony_ci		    skl_ddb_entry_equal(&old_crtc_state->wm.skl.plane_ddb_uv[plane_id],
57758c2ecf20Sopenharmony_ci					&new_crtc_state->wm.skl.plane_ddb_uv[plane_id]))
57768c2ecf20Sopenharmony_ci			continue;
57778c2ecf20Sopenharmony_ci
57788c2ecf20Sopenharmony_ci		plane_state = intel_atomic_get_plane_state(state, plane);
57798c2ecf20Sopenharmony_ci		if (IS_ERR(plane_state))
57808c2ecf20Sopenharmony_ci			return PTR_ERR(plane_state);
57818c2ecf20Sopenharmony_ci
57828c2ecf20Sopenharmony_ci		new_crtc_state->update_planes |= BIT(plane_id);
57838c2ecf20Sopenharmony_ci	}
57848c2ecf20Sopenharmony_ci
57858c2ecf20Sopenharmony_ci	return 0;
57868c2ecf20Sopenharmony_ci}
57878c2ecf20Sopenharmony_ci
57888c2ecf20Sopenharmony_cistatic int
57898c2ecf20Sopenharmony_ciskl_compute_ddb(struct intel_atomic_state *state)
57908c2ecf20Sopenharmony_ci{
57918c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
57928c2ecf20Sopenharmony_ci	const struct intel_dbuf_state *old_dbuf_state;
57938c2ecf20Sopenharmony_ci	const struct intel_dbuf_state *new_dbuf_state;
57948c2ecf20Sopenharmony_ci	const struct intel_crtc_state *old_crtc_state;
57958c2ecf20Sopenharmony_ci	struct intel_crtc_state *new_crtc_state;
57968c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
57978c2ecf20Sopenharmony_ci	int ret, i;
57988c2ecf20Sopenharmony_ci
57998c2ecf20Sopenharmony_ci	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
58008c2ecf20Sopenharmony_ci					    new_crtc_state, i) {
58018c2ecf20Sopenharmony_ci		ret = skl_allocate_pipe_ddb(new_crtc_state);
58028c2ecf20Sopenharmony_ci		if (ret)
58038c2ecf20Sopenharmony_ci			return ret;
58048c2ecf20Sopenharmony_ci
58058c2ecf20Sopenharmony_ci		ret = skl_ddb_add_affected_planes(old_crtc_state,
58068c2ecf20Sopenharmony_ci						  new_crtc_state);
58078c2ecf20Sopenharmony_ci		if (ret)
58088c2ecf20Sopenharmony_ci			return ret;
58098c2ecf20Sopenharmony_ci	}
58108c2ecf20Sopenharmony_ci
58118c2ecf20Sopenharmony_ci	old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
58128c2ecf20Sopenharmony_ci	new_dbuf_state = intel_atomic_get_new_dbuf_state(state);
58138c2ecf20Sopenharmony_ci
58148c2ecf20Sopenharmony_ci	if (new_dbuf_state &&
58158c2ecf20Sopenharmony_ci	    new_dbuf_state->enabled_slices != old_dbuf_state->enabled_slices)
58168c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
58178c2ecf20Sopenharmony_ci			    "Enabled dbuf slices 0x%x -> 0x%x (out of %d dbuf slices)\n",
58188c2ecf20Sopenharmony_ci			    old_dbuf_state->enabled_slices,
58198c2ecf20Sopenharmony_ci			    new_dbuf_state->enabled_slices,
58208c2ecf20Sopenharmony_ci			    INTEL_INFO(dev_priv)->num_supported_dbuf_slices);
58218c2ecf20Sopenharmony_ci
58228c2ecf20Sopenharmony_ci	return 0;
58238c2ecf20Sopenharmony_ci}
58248c2ecf20Sopenharmony_ci
58258c2ecf20Sopenharmony_cistatic char enast(bool enable)
58268c2ecf20Sopenharmony_ci{
58278c2ecf20Sopenharmony_ci	return enable ? '*' : ' ';
58288c2ecf20Sopenharmony_ci}
58298c2ecf20Sopenharmony_ci
58308c2ecf20Sopenharmony_cistatic void
58318c2ecf20Sopenharmony_ciskl_print_wm_changes(struct intel_atomic_state *state)
58328c2ecf20Sopenharmony_ci{
58338c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
58348c2ecf20Sopenharmony_ci	const struct intel_crtc_state *old_crtc_state;
58358c2ecf20Sopenharmony_ci	const struct intel_crtc_state *new_crtc_state;
58368c2ecf20Sopenharmony_ci	struct intel_plane *plane;
58378c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
58388c2ecf20Sopenharmony_ci	int i;
58398c2ecf20Sopenharmony_ci
58408c2ecf20Sopenharmony_ci	if (!drm_debug_enabled(DRM_UT_KMS))
58418c2ecf20Sopenharmony_ci		return;
58428c2ecf20Sopenharmony_ci
58438c2ecf20Sopenharmony_ci	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
58448c2ecf20Sopenharmony_ci					    new_crtc_state, i) {
58458c2ecf20Sopenharmony_ci		const struct skl_pipe_wm *old_pipe_wm, *new_pipe_wm;
58468c2ecf20Sopenharmony_ci
58478c2ecf20Sopenharmony_ci		old_pipe_wm = &old_crtc_state->wm.skl.optimal;
58488c2ecf20Sopenharmony_ci		new_pipe_wm = &new_crtc_state->wm.skl.optimal;
58498c2ecf20Sopenharmony_ci
58508c2ecf20Sopenharmony_ci		for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
58518c2ecf20Sopenharmony_ci			enum plane_id plane_id = plane->id;
58528c2ecf20Sopenharmony_ci			const struct skl_ddb_entry *old, *new;
58538c2ecf20Sopenharmony_ci
58548c2ecf20Sopenharmony_ci			old = &old_crtc_state->wm.skl.plane_ddb_y[plane_id];
58558c2ecf20Sopenharmony_ci			new = &new_crtc_state->wm.skl.plane_ddb_y[plane_id];
58568c2ecf20Sopenharmony_ci
58578c2ecf20Sopenharmony_ci			if (skl_ddb_entry_equal(old, new))
58588c2ecf20Sopenharmony_ci				continue;
58598c2ecf20Sopenharmony_ci
58608c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
58618c2ecf20Sopenharmony_ci				    "[PLANE:%d:%s] ddb (%4d - %4d) -> (%4d - %4d), size %4d -> %4d\n",
58628c2ecf20Sopenharmony_ci				    plane->base.base.id, plane->base.name,
58638c2ecf20Sopenharmony_ci				    old->start, old->end, new->start, new->end,
58648c2ecf20Sopenharmony_ci				    skl_ddb_entry_size(old), skl_ddb_entry_size(new));
58658c2ecf20Sopenharmony_ci		}
58668c2ecf20Sopenharmony_ci
58678c2ecf20Sopenharmony_ci		for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
58688c2ecf20Sopenharmony_ci			enum plane_id plane_id = plane->id;
58698c2ecf20Sopenharmony_ci			const struct skl_plane_wm *old_wm, *new_wm;
58708c2ecf20Sopenharmony_ci
58718c2ecf20Sopenharmony_ci			old_wm = &old_pipe_wm->planes[plane_id];
58728c2ecf20Sopenharmony_ci			new_wm = &new_pipe_wm->planes[plane_id];
58738c2ecf20Sopenharmony_ci
58748c2ecf20Sopenharmony_ci			if (skl_plane_wm_equals(dev_priv, old_wm, new_wm))
58758c2ecf20Sopenharmony_ci				continue;
58768c2ecf20Sopenharmony_ci
58778c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
58788c2ecf20Sopenharmony_ci				    "[PLANE:%d:%s]   level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm"
58798c2ecf20Sopenharmony_ci				    " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm\n",
58808c2ecf20Sopenharmony_ci				    plane->base.base.id, plane->base.name,
58818c2ecf20Sopenharmony_ci				    enast(old_wm->wm[0].plane_en), enast(old_wm->wm[1].plane_en),
58828c2ecf20Sopenharmony_ci				    enast(old_wm->wm[2].plane_en), enast(old_wm->wm[3].plane_en),
58838c2ecf20Sopenharmony_ci				    enast(old_wm->wm[4].plane_en), enast(old_wm->wm[5].plane_en),
58848c2ecf20Sopenharmony_ci				    enast(old_wm->wm[6].plane_en), enast(old_wm->wm[7].plane_en),
58858c2ecf20Sopenharmony_ci				    enast(old_wm->trans_wm.plane_en),
58868c2ecf20Sopenharmony_ci				    enast(old_wm->sagv_wm0.plane_en),
58878c2ecf20Sopenharmony_ci				    enast(new_wm->wm[0].plane_en), enast(new_wm->wm[1].plane_en),
58888c2ecf20Sopenharmony_ci				    enast(new_wm->wm[2].plane_en), enast(new_wm->wm[3].plane_en),
58898c2ecf20Sopenharmony_ci				    enast(new_wm->wm[4].plane_en), enast(new_wm->wm[5].plane_en),
58908c2ecf20Sopenharmony_ci				    enast(new_wm->wm[6].plane_en), enast(new_wm->wm[7].plane_en),
58918c2ecf20Sopenharmony_ci				    enast(new_wm->trans_wm.plane_en),
58928c2ecf20Sopenharmony_ci				    enast(new_wm->sagv_wm0.plane_en));
58938c2ecf20Sopenharmony_ci
58948c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
58958c2ecf20Sopenharmony_ci				    "[PLANE:%d:%s]   lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d"
58968c2ecf20Sopenharmony_ci				      " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d\n",
58978c2ecf20Sopenharmony_ci				    plane->base.base.id, plane->base.name,
58988c2ecf20Sopenharmony_ci				    enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].plane_res_l,
58998c2ecf20Sopenharmony_ci				    enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].plane_res_l,
59008c2ecf20Sopenharmony_ci				    enast(old_wm->wm[2].ignore_lines), old_wm->wm[2].plane_res_l,
59018c2ecf20Sopenharmony_ci				    enast(old_wm->wm[3].ignore_lines), old_wm->wm[3].plane_res_l,
59028c2ecf20Sopenharmony_ci				    enast(old_wm->wm[4].ignore_lines), old_wm->wm[4].plane_res_l,
59038c2ecf20Sopenharmony_ci				    enast(old_wm->wm[5].ignore_lines), old_wm->wm[5].plane_res_l,
59048c2ecf20Sopenharmony_ci				    enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].plane_res_l,
59058c2ecf20Sopenharmony_ci				    enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].plane_res_l,
59068c2ecf20Sopenharmony_ci				    enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.plane_res_l,
59078c2ecf20Sopenharmony_ci				    enast(old_wm->sagv_wm0.ignore_lines), old_wm->sagv_wm0.plane_res_l,
59088c2ecf20Sopenharmony_ci
59098c2ecf20Sopenharmony_ci				    enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].plane_res_l,
59108c2ecf20Sopenharmony_ci				    enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].plane_res_l,
59118c2ecf20Sopenharmony_ci				    enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].plane_res_l,
59128c2ecf20Sopenharmony_ci				    enast(new_wm->wm[3].ignore_lines), new_wm->wm[3].plane_res_l,
59138c2ecf20Sopenharmony_ci				    enast(new_wm->wm[4].ignore_lines), new_wm->wm[4].plane_res_l,
59148c2ecf20Sopenharmony_ci				    enast(new_wm->wm[5].ignore_lines), new_wm->wm[5].plane_res_l,
59158c2ecf20Sopenharmony_ci				    enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].plane_res_l,
59168c2ecf20Sopenharmony_ci				    enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].plane_res_l,
59178c2ecf20Sopenharmony_ci				    enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.plane_res_l,
59188c2ecf20Sopenharmony_ci				    enast(new_wm->sagv_wm0.ignore_lines), new_wm->sagv_wm0.plane_res_l);
59198c2ecf20Sopenharmony_ci
59208c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
59218c2ecf20Sopenharmony_ci				    "[PLANE:%d:%s]  blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d"
59228c2ecf20Sopenharmony_ci				    " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\n",
59238c2ecf20Sopenharmony_ci				    plane->base.base.id, plane->base.name,
59248c2ecf20Sopenharmony_ci				    old_wm->wm[0].plane_res_b, old_wm->wm[1].plane_res_b,
59258c2ecf20Sopenharmony_ci				    old_wm->wm[2].plane_res_b, old_wm->wm[3].plane_res_b,
59268c2ecf20Sopenharmony_ci				    old_wm->wm[4].plane_res_b, old_wm->wm[5].plane_res_b,
59278c2ecf20Sopenharmony_ci				    old_wm->wm[6].plane_res_b, old_wm->wm[7].plane_res_b,
59288c2ecf20Sopenharmony_ci				    old_wm->trans_wm.plane_res_b,
59298c2ecf20Sopenharmony_ci				    old_wm->sagv_wm0.plane_res_b,
59308c2ecf20Sopenharmony_ci				    new_wm->wm[0].plane_res_b, new_wm->wm[1].plane_res_b,
59318c2ecf20Sopenharmony_ci				    new_wm->wm[2].plane_res_b, new_wm->wm[3].plane_res_b,
59328c2ecf20Sopenharmony_ci				    new_wm->wm[4].plane_res_b, new_wm->wm[5].plane_res_b,
59338c2ecf20Sopenharmony_ci				    new_wm->wm[6].plane_res_b, new_wm->wm[7].plane_res_b,
59348c2ecf20Sopenharmony_ci				    new_wm->trans_wm.plane_res_b,
59358c2ecf20Sopenharmony_ci				    new_wm->sagv_wm0.plane_res_b);
59368c2ecf20Sopenharmony_ci
59378c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
59388c2ecf20Sopenharmony_ci				    "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d"
59398c2ecf20Sopenharmony_ci				    " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\n",
59408c2ecf20Sopenharmony_ci				    plane->base.base.id, plane->base.name,
59418c2ecf20Sopenharmony_ci				    old_wm->wm[0].min_ddb_alloc, old_wm->wm[1].min_ddb_alloc,
59428c2ecf20Sopenharmony_ci				    old_wm->wm[2].min_ddb_alloc, old_wm->wm[3].min_ddb_alloc,
59438c2ecf20Sopenharmony_ci				    old_wm->wm[4].min_ddb_alloc, old_wm->wm[5].min_ddb_alloc,
59448c2ecf20Sopenharmony_ci				    old_wm->wm[6].min_ddb_alloc, old_wm->wm[7].min_ddb_alloc,
59458c2ecf20Sopenharmony_ci				    old_wm->trans_wm.min_ddb_alloc,
59468c2ecf20Sopenharmony_ci				    old_wm->sagv_wm0.min_ddb_alloc,
59478c2ecf20Sopenharmony_ci				    new_wm->wm[0].min_ddb_alloc, new_wm->wm[1].min_ddb_alloc,
59488c2ecf20Sopenharmony_ci				    new_wm->wm[2].min_ddb_alloc, new_wm->wm[3].min_ddb_alloc,
59498c2ecf20Sopenharmony_ci				    new_wm->wm[4].min_ddb_alloc, new_wm->wm[5].min_ddb_alloc,
59508c2ecf20Sopenharmony_ci				    new_wm->wm[6].min_ddb_alloc, new_wm->wm[7].min_ddb_alloc,
59518c2ecf20Sopenharmony_ci				    new_wm->trans_wm.min_ddb_alloc,
59528c2ecf20Sopenharmony_ci				    new_wm->sagv_wm0.min_ddb_alloc);
59538c2ecf20Sopenharmony_ci		}
59548c2ecf20Sopenharmony_ci	}
59558c2ecf20Sopenharmony_ci}
59568c2ecf20Sopenharmony_ci
59578c2ecf20Sopenharmony_cistatic int intel_add_affected_pipes(struct intel_atomic_state *state,
59588c2ecf20Sopenharmony_ci				    u8 pipe_mask)
59598c2ecf20Sopenharmony_ci{
59608c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
59618c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
59628c2ecf20Sopenharmony_ci
59638c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
59648c2ecf20Sopenharmony_ci		struct intel_crtc_state *crtc_state;
59658c2ecf20Sopenharmony_ci
59668c2ecf20Sopenharmony_ci		if ((pipe_mask & BIT(crtc->pipe)) == 0)
59678c2ecf20Sopenharmony_ci			continue;
59688c2ecf20Sopenharmony_ci
59698c2ecf20Sopenharmony_ci		crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
59708c2ecf20Sopenharmony_ci		if (IS_ERR(crtc_state))
59718c2ecf20Sopenharmony_ci			return PTR_ERR(crtc_state);
59728c2ecf20Sopenharmony_ci	}
59738c2ecf20Sopenharmony_ci
59748c2ecf20Sopenharmony_ci	return 0;
59758c2ecf20Sopenharmony_ci}
59768c2ecf20Sopenharmony_ci
59778c2ecf20Sopenharmony_cistatic int
59788c2ecf20Sopenharmony_ciskl_ddb_add_affected_pipes(struct intel_atomic_state *state)
59798c2ecf20Sopenharmony_ci{
59808c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
59818c2ecf20Sopenharmony_ci	struct intel_crtc_state *crtc_state;
59828c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
59838c2ecf20Sopenharmony_ci	int i, ret;
59848c2ecf20Sopenharmony_ci
59858c2ecf20Sopenharmony_ci	if (dev_priv->wm.distrust_bios_wm) {
59868c2ecf20Sopenharmony_ci		/*
59878c2ecf20Sopenharmony_ci		 * skl_ddb_get_pipe_allocation_limits() currently requires
59888c2ecf20Sopenharmony_ci		 * all active pipes to be included in the state so that
59898c2ecf20Sopenharmony_ci		 * it can redistribute the dbuf among them, and it really
59908c2ecf20Sopenharmony_ci		 * wants to recompute things when distrust_bios_wm is set
59918c2ecf20Sopenharmony_ci		 * so we add all the pipes to the state.
59928c2ecf20Sopenharmony_ci		 */
59938c2ecf20Sopenharmony_ci		ret = intel_add_affected_pipes(state, ~0);
59948c2ecf20Sopenharmony_ci		if (ret)
59958c2ecf20Sopenharmony_ci			return ret;
59968c2ecf20Sopenharmony_ci	}
59978c2ecf20Sopenharmony_ci
59988c2ecf20Sopenharmony_ci	for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
59998c2ecf20Sopenharmony_ci		struct intel_dbuf_state *new_dbuf_state;
60008c2ecf20Sopenharmony_ci		const struct intel_dbuf_state *old_dbuf_state;
60018c2ecf20Sopenharmony_ci
60028c2ecf20Sopenharmony_ci		new_dbuf_state = intel_atomic_get_dbuf_state(state);
60038c2ecf20Sopenharmony_ci		if (IS_ERR(new_dbuf_state))
60048c2ecf20Sopenharmony_ci			return PTR_ERR(new_dbuf_state);
60058c2ecf20Sopenharmony_ci
60068c2ecf20Sopenharmony_ci		old_dbuf_state = intel_atomic_get_old_dbuf_state(state);
60078c2ecf20Sopenharmony_ci
60088c2ecf20Sopenharmony_ci		new_dbuf_state->active_pipes =
60098c2ecf20Sopenharmony_ci			intel_calc_active_pipes(state, old_dbuf_state->active_pipes);
60108c2ecf20Sopenharmony_ci
60118c2ecf20Sopenharmony_ci		if (old_dbuf_state->active_pipes == new_dbuf_state->active_pipes)
60128c2ecf20Sopenharmony_ci			break;
60138c2ecf20Sopenharmony_ci
60148c2ecf20Sopenharmony_ci		ret = intel_atomic_lock_global_state(&new_dbuf_state->base);
60158c2ecf20Sopenharmony_ci		if (ret)
60168c2ecf20Sopenharmony_ci			return ret;
60178c2ecf20Sopenharmony_ci
60188c2ecf20Sopenharmony_ci		/*
60198c2ecf20Sopenharmony_ci		 * skl_ddb_get_pipe_allocation_limits() currently requires
60208c2ecf20Sopenharmony_ci		 * all active pipes to be included in the state so that
60218c2ecf20Sopenharmony_ci		 * it can redistribute the dbuf among them.
60228c2ecf20Sopenharmony_ci		 */
60238c2ecf20Sopenharmony_ci		ret = intel_add_affected_pipes(state,
60248c2ecf20Sopenharmony_ci					       new_dbuf_state->active_pipes);
60258c2ecf20Sopenharmony_ci		if (ret)
60268c2ecf20Sopenharmony_ci			return ret;
60278c2ecf20Sopenharmony_ci
60288c2ecf20Sopenharmony_ci		break;
60298c2ecf20Sopenharmony_ci	}
60308c2ecf20Sopenharmony_ci
60318c2ecf20Sopenharmony_ci	return 0;
60328c2ecf20Sopenharmony_ci}
60338c2ecf20Sopenharmony_ci
60348c2ecf20Sopenharmony_ci/*
60358c2ecf20Sopenharmony_ci * To make sure the cursor watermark registers are always consistent
60368c2ecf20Sopenharmony_ci * with our computed state the following scenario needs special
60378c2ecf20Sopenharmony_ci * treatment:
60388c2ecf20Sopenharmony_ci *
60398c2ecf20Sopenharmony_ci * 1. enable cursor
60408c2ecf20Sopenharmony_ci * 2. move cursor entirely offscreen
60418c2ecf20Sopenharmony_ci * 3. disable cursor
60428c2ecf20Sopenharmony_ci *
60438c2ecf20Sopenharmony_ci * Step 2. does call .disable_plane() but does not zero the watermarks
60448c2ecf20Sopenharmony_ci * (since we consider an offscreen cursor still active for the purposes
60458c2ecf20Sopenharmony_ci * of watermarks). Step 3. would not normally call .disable_plane()
60468c2ecf20Sopenharmony_ci * because the actual plane visibility isn't changing, and we don't
60478c2ecf20Sopenharmony_ci * deallocate the cursor ddb until the pipe gets disabled. So we must
60488c2ecf20Sopenharmony_ci * force step 3. to call .disable_plane() to update the watermark
60498c2ecf20Sopenharmony_ci * registers properly.
60508c2ecf20Sopenharmony_ci *
60518c2ecf20Sopenharmony_ci * Other planes do not suffer from this issues as their watermarks are
60528c2ecf20Sopenharmony_ci * calculated based on the actual plane visibility. The only time this
60538c2ecf20Sopenharmony_ci * can trigger for the other planes is during the initial readout as the
60548c2ecf20Sopenharmony_ci * default value of the watermarks registers is not zero.
60558c2ecf20Sopenharmony_ci */
60568c2ecf20Sopenharmony_cistatic int skl_wm_add_affected_planes(struct intel_atomic_state *state,
60578c2ecf20Sopenharmony_ci				      struct intel_crtc *crtc)
60588c2ecf20Sopenharmony_ci{
60598c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
60608c2ecf20Sopenharmony_ci	const struct intel_crtc_state *old_crtc_state =
60618c2ecf20Sopenharmony_ci		intel_atomic_get_old_crtc_state(state, crtc);
60628c2ecf20Sopenharmony_ci	struct intel_crtc_state *new_crtc_state =
60638c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
60648c2ecf20Sopenharmony_ci	struct intel_plane *plane;
60658c2ecf20Sopenharmony_ci
60668c2ecf20Sopenharmony_ci	for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
60678c2ecf20Sopenharmony_ci		struct intel_plane_state *plane_state;
60688c2ecf20Sopenharmony_ci		enum plane_id plane_id = plane->id;
60698c2ecf20Sopenharmony_ci
60708c2ecf20Sopenharmony_ci		/*
60718c2ecf20Sopenharmony_ci		 * Force a full wm update for every plane on modeset.
60728c2ecf20Sopenharmony_ci		 * Required because the reset value of the wm registers
60738c2ecf20Sopenharmony_ci		 * is non-zero, whereas we want all disabled planes to
60748c2ecf20Sopenharmony_ci		 * have zero watermarks. So if we turn off the relevant
60758c2ecf20Sopenharmony_ci		 * power well the hardware state will go out of sync
60768c2ecf20Sopenharmony_ci		 * with the software state.
60778c2ecf20Sopenharmony_ci		 */
60788c2ecf20Sopenharmony_ci		if (!drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi) &&
60798c2ecf20Sopenharmony_ci		    skl_plane_wm_equals(dev_priv,
60808c2ecf20Sopenharmony_ci					&old_crtc_state->wm.skl.optimal.planes[plane_id],
60818c2ecf20Sopenharmony_ci					&new_crtc_state->wm.skl.optimal.planes[plane_id]))
60828c2ecf20Sopenharmony_ci			continue;
60838c2ecf20Sopenharmony_ci
60848c2ecf20Sopenharmony_ci		plane_state = intel_atomic_get_plane_state(state, plane);
60858c2ecf20Sopenharmony_ci		if (IS_ERR(plane_state))
60868c2ecf20Sopenharmony_ci			return PTR_ERR(plane_state);
60878c2ecf20Sopenharmony_ci
60888c2ecf20Sopenharmony_ci		new_crtc_state->update_planes |= BIT(plane_id);
60898c2ecf20Sopenharmony_ci	}
60908c2ecf20Sopenharmony_ci
60918c2ecf20Sopenharmony_ci	return 0;
60928c2ecf20Sopenharmony_ci}
60938c2ecf20Sopenharmony_ci
60948c2ecf20Sopenharmony_cistatic int
60958c2ecf20Sopenharmony_ciskl_compute_wm(struct intel_atomic_state *state)
60968c2ecf20Sopenharmony_ci{
60978c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
60988c2ecf20Sopenharmony_ci	struct intel_crtc_state *new_crtc_state;
60998c2ecf20Sopenharmony_ci	struct intel_crtc_state *old_crtc_state;
61008c2ecf20Sopenharmony_ci	int ret, i;
61018c2ecf20Sopenharmony_ci
61028c2ecf20Sopenharmony_ci	ret = skl_ddb_add_affected_pipes(state);
61038c2ecf20Sopenharmony_ci	if (ret)
61048c2ecf20Sopenharmony_ci		return ret;
61058c2ecf20Sopenharmony_ci
61068c2ecf20Sopenharmony_ci	/*
61078c2ecf20Sopenharmony_ci	 * Calculate WM's for all pipes that are part of this transaction.
61088c2ecf20Sopenharmony_ci	 * Note that skl_ddb_add_affected_pipes may have added more CRTC's that
61098c2ecf20Sopenharmony_ci	 * weren't otherwise being modified if pipe allocations had to change.
61108c2ecf20Sopenharmony_ci	 */
61118c2ecf20Sopenharmony_ci	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
61128c2ecf20Sopenharmony_ci					    new_crtc_state, i) {
61138c2ecf20Sopenharmony_ci		ret = skl_build_pipe_wm(new_crtc_state);
61148c2ecf20Sopenharmony_ci		if (ret)
61158c2ecf20Sopenharmony_ci			return ret;
61168c2ecf20Sopenharmony_ci	}
61178c2ecf20Sopenharmony_ci
61188c2ecf20Sopenharmony_ci	ret = skl_compute_ddb(state);
61198c2ecf20Sopenharmony_ci	if (ret)
61208c2ecf20Sopenharmony_ci		return ret;
61218c2ecf20Sopenharmony_ci
61228c2ecf20Sopenharmony_ci	ret = intel_compute_sagv_mask(state);
61238c2ecf20Sopenharmony_ci	if (ret)
61248c2ecf20Sopenharmony_ci		return ret;
61258c2ecf20Sopenharmony_ci
61268c2ecf20Sopenharmony_ci	/*
61278c2ecf20Sopenharmony_ci	 * skl_compute_ddb() will have adjusted the final watermarks
61288c2ecf20Sopenharmony_ci	 * based on how much ddb is available. Now we can actually
61298c2ecf20Sopenharmony_ci	 * check if the final watermarks changed.
61308c2ecf20Sopenharmony_ci	 */
61318c2ecf20Sopenharmony_ci	for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state,
61328c2ecf20Sopenharmony_ci					    new_crtc_state, i) {
61338c2ecf20Sopenharmony_ci		ret = skl_wm_add_affected_planes(state, crtc);
61348c2ecf20Sopenharmony_ci		if (ret)
61358c2ecf20Sopenharmony_ci			return ret;
61368c2ecf20Sopenharmony_ci	}
61378c2ecf20Sopenharmony_ci
61388c2ecf20Sopenharmony_ci	skl_print_wm_changes(state);
61398c2ecf20Sopenharmony_ci
61408c2ecf20Sopenharmony_ci	return 0;
61418c2ecf20Sopenharmony_ci}
61428c2ecf20Sopenharmony_ci
61438c2ecf20Sopenharmony_cistatic void ilk_compute_wm_config(struct drm_i915_private *dev_priv,
61448c2ecf20Sopenharmony_ci				  struct intel_wm_config *config)
61458c2ecf20Sopenharmony_ci{
61468c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
61478c2ecf20Sopenharmony_ci
61488c2ecf20Sopenharmony_ci	/* Compute the currently _active_ config */
61498c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
61508c2ecf20Sopenharmony_ci		const struct intel_pipe_wm *wm = &crtc->wm.active.ilk;
61518c2ecf20Sopenharmony_ci
61528c2ecf20Sopenharmony_ci		if (!wm->pipe_enabled)
61538c2ecf20Sopenharmony_ci			continue;
61548c2ecf20Sopenharmony_ci
61558c2ecf20Sopenharmony_ci		config->sprites_enabled |= wm->sprites_enabled;
61568c2ecf20Sopenharmony_ci		config->sprites_scaled |= wm->sprites_scaled;
61578c2ecf20Sopenharmony_ci		config->num_pipes_active++;
61588c2ecf20Sopenharmony_ci	}
61598c2ecf20Sopenharmony_ci}
61608c2ecf20Sopenharmony_ci
61618c2ecf20Sopenharmony_cistatic void ilk_program_watermarks(struct drm_i915_private *dev_priv)
61628c2ecf20Sopenharmony_ci{
61638c2ecf20Sopenharmony_ci	struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
61648c2ecf20Sopenharmony_ci	struct ilk_wm_maximums max;
61658c2ecf20Sopenharmony_ci	struct intel_wm_config config = {};
61668c2ecf20Sopenharmony_ci	struct ilk_wm_values results = {};
61678c2ecf20Sopenharmony_ci	enum intel_ddb_partitioning partitioning;
61688c2ecf20Sopenharmony_ci
61698c2ecf20Sopenharmony_ci	ilk_compute_wm_config(dev_priv, &config);
61708c2ecf20Sopenharmony_ci
61718c2ecf20Sopenharmony_ci	ilk_compute_wm_maximums(dev_priv, 1, &config, INTEL_DDB_PART_1_2, &max);
61728c2ecf20Sopenharmony_ci	ilk_wm_merge(dev_priv, &config, &max, &lp_wm_1_2);
61738c2ecf20Sopenharmony_ci
61748c2ecf20Sopenharmony_ci	/* 5/6 split only in single pipe config on IVB+ */
61758c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 7 &&
61768c2ecf20Sopenharmony_ci	    config.num_pipes_active == 1 && config.sprites_enabled) {
61778c2ecf20Sopenharmony_ci		ilk_compute_wm_maximums(dev_priv, 1, &config, INTEL_DDB_PART_5_6, &max);
61788c2ecf20Sopenharmony_ci		ilk_wm_merge(dev_priv, &config, &max, &lp_wm_5_6);
61798c2ecf20Sopenharmony_ci
61808c2ecf20Sopenharmony_ci		best_lp_wm = ilk_find_best_result(dev_priv, &lp_wm_1_2, &lp_wm_5_6);
61818c2ecf20Sopenharmony_ci	} else {
61828c2ecf20Sopenharmony_ci		best_lp_wm = &lp_wm_1_2;
61838c2ecf20Sopenharmony_ci	}
61848c2ecf20Sopenharmony_ci
61858c2ecf20Sopenharmony_ci	partitioning = (best_lp_wm == &lp_wm_1_2) ?
61868c2ecf20Sopenharmony_ci		       INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6;
61878c2ecf20Sopenharmony_ci
61888c2ecf20Sopenharmony_ci	ilk_compute_wm_results(dev_priv, best_lp_wm, partitioning, &results);
61898c2ecf20Sopenharmony_ci
61908c2ecf20Sopenharmony_ci	ilk_write_wm_values(dev_priv, &results);
61918c2ecf20Sopenharmony_ci}
61928c2ecf20Sopenharmony_ci
61938c2ecf20Sopenharmony_cistatic void ilk_initial_watermarks(struct intel_atomic_state *state,
61948c2ecf20Sopenharmony_ci				   struct intel_crtc *crtc)
61958c2ecf20Sopenharmony_ci{
61968c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
61978c2ecf20Sopenharmony_ci	const struct intel_crtc_state *crtc_state =
61988c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
61998c2ecf20Sopenharmony_ci
62008c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
62018c2ecf20Sopenharmony_ci	crtc->wm.active.ilk = crtc_state->wm.ilk.intermediate;
62028c2ecf20Sopenharmony_ci	ilk_program_watermarks(dev_priv);
62038c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
62048c2ecf20Sopenharmony_ci}
62058c2ecf20Sopenharmony_ci
62068c2ecf20Sopenharmony_cistatic void ilk_optimize_watermarks(struct intel_atomic_state *state,
62078c2ecf20Sopenharmony_ci				    struct intel_crtc *crtc)
62088c2ecf20Sopenharmony_ci{
62098c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
62108c2ecf20Sopenharmony_ci	const struct intel_crtc_state *crtc_state =
62118c2ecf20Sopenharmony_ci		intel_atomic_get_new_crtc_state(state, crtc);
62128c2ecf20Sopenharmony_ci
62138c2ecf20Sopenharmony_ci	if (!crtc_state->wm.need_postvbl_update)
62148c2ecf20Sopenharmony_ci		return;
62158c2ecf20Sopenharmony_ci
62168c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
62178c2ecf20Sopenharmony_ci	crtc->wm.active.ilk = crtc_state->wm.ilk.optimal;
62188c2ecf20Sopenharmony_ci	ilk_program_watermarks(dev_priv);
62198c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
62208c2ecf20Sopenharmony_ci}
62218c2ecf20Sopenharmony_ci
62228c2ecf20Sopenharmony_cistatic void skl_wm_level_from_reg_val(u32 val, struct skl_wm_level *level)
62238c2ecf20Sopenharmony_ci{
62248c2ecf20Sopenharmony_ci	level->plane_en = val & PLANE_WM_EN;
62258c2ecf20Sopenharmony_ci	level->ignore_lines = val & PLANE_WM_IGNORE_LINES;
62268c2ecf20Sopenharmony_ci	level->plane_res_b = val & PLANE_WM_BLOCKS_MASK;
62278c2ecf20Sopenharmony_ci	level->plane_res_l = (val >> PLANE_WM_LINES_SHIFT) &
62288c2ecf20Sopenharmony_ci		PLANE_WM_LINES_MASK;
62298c2ecf20Sopenharmony_ci}
62308c2ecf20Sopenharmony_ci
62318c2ecf20Sopenharmony_civoid skl_pipe_wm_get_hw_state(struct intel_crtc *crtc,
62328c2ecf20Sopenharmony_ci			      struct skl_pipe_wm *out)
62338c2ecf20Sopenharmony_ci{
62348c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
62358c2ecf20Sopenharmony_ci	enum pipe pipe = crtc->pipe;
62368c2ecf20Sopenharmony_ci	int level, max_level;
62378c2ecf20Sopenharmony_ci	enum plane_id plane_id;
62388c2ecf20Sopenharmony_ci	u32 val;
62398c2ecf20Sopenharmony_ci
62408c2ecf20Sopenharmony_ci	max_level = ilk_wm_max_level(dev_priv);
62418c2ecf20Sopenharmony_ci
62428c2ecf20Sopenharmony_ci	for_each_plane_id_on_crtc(crtc, plane_id) {
62438c2ecf20Sopenharmony_ci		struct skl_plane_wm *wm = &out->planes[plane_id];
62448c2ecf20Sopenharmony_ci
62458c2ecf20Sopenharmony_ci		for (level = 0; level <= max_level; level++) {
62468c2ecf20Sopenharmony_ci			if (plane_id != PLANE_CURSOR)
62478c2ecf20Sopenharmony_ci				val = I915_READ(PLANE_WM(pipe, plane_id, level));
62488c2ecf20Sopenharmony_ci			else
62498c2ecf20Sopenharmony_ci				val = I915_READ(CUR_WM(pipe, level));
62508c2ecf20Sopenharmony_ci
62518c2ecf20Sopenharmony_ci			skl_wm_level_from_reg_val(val, &wm->wm[level]);
62528c2ecf20Sopenharmony_ci		}
62538c2ecf20Sopenharmony_ci
62548c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 12)
62558c2ecf20Sopenharmony_ci			wm->sagv_wm0 = wm->wm[0];
62568c2ecf20Sopenharmony_ci
62578c2ecf20Sopenharmony_ci		if (plane_id != PLANE_CURSOR)
62588c2ecf20Sopenharmony_ci			val = I915_READ(PLANE_WM_TRANS(pipe, plane_id));
62598c2ecf20Sopenharmony_ci		else
62608c2ecf20Sopenharmony_ci			val = I915_READ(CUR_WM_TRANS(pipe));
62618c2ecf20Sopenharmony_ci
62628c2ecf20Sopenharmony_ci		skl_wm_level_from_reg_val(val, &wm->trans_wm);
62638c2ecf20Sopenharmony_ci	}
62648c2ecf20Sopenharmony_ci
62658c2ecf20Sopenharmony_ci	if (!crtc->active)
62668c2ecf20Sopenharmony_ci		return;
62678c2ecf20Sopenharmony_ci}
62688c2ecf20Sopenharmony_ci
62698c2ecf20Sopenharmony_civoid skl_wm_get_hw_state(struct drm_i915_private *dev_priv)
62708c2ecf20Sopenharmony_ci{
62718c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
62728c2ecf20Sopenharmony_ci	struct intel_crtc_state *crtc_state;
62738c2ecf20Sopenharmony_ci
62748c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
62758c2ecf20Sopenharmony_ci		crtc_state = to_intel_crtc_state(crtc->base.state);
62768c2ecf20Sopenharmony_ci
62778c2ecf20Sopenharmony_ci		skl_pipe_wm_get_hw_state(crtc, &crtc_state->wm.skl.optimal);
62788c2ecf20Sopenharmony_ci	}
62798c2ecf20Sopenharmony_ci
62808c2ecf20Sopenharmony_ci	if (dev_priv->active_pipes) {
62818c2ecf20Sopenharmony_ci		/* Fully recompute DDB on first atomic commit */
62828c2ecf20Sopenharmony_ci		dev_priv->wm.distrust_bios_wm = true;
62838c2ecf20Sopenharmony_ci	}
62848c2ecf20Sopenharmony_ci}
62858c2ecf20Sopenharmony_ci
62868c2ecf20Sopenharmony_cistatic void ilk_pipe_wm_get_hw_state(struct intel_crtc *crtc)
62878c2ecf20Sopenharmony_ci{
62888c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc->base.dev;
62898c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(dev);
62908c2ecf20Sopenharmony_ci	struct ilk_wm_values *hw = &dev_priv->wm.hw;
62918c2ecf20Sopenharmony_ci	struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state);
62928c2ecf20Sopenharmony_ci	struct intel_pipe_wm *active = &crtc_state->wm.ilk.optimal;
62938c2ecf20Sopenharmony_ci	enum pipe pipe = crtc->pipe;
62948c2ecf20Sopenharmony_ci	static const i915_reg_t wm0_pipe_reg[] = {
62958c2ecf20Sopenharmony_ci		[PIPE_A] = WM0_PIPEA_ILK,
62968c2ecf20Sopenharmony_ci		[PIPE_B] = WM0_PIPEB_ILK,
62978c2ecf20Sopenharmony_ci		[PIPE_C] = WM0_PIPEC_IVB,
62988c2ecf20Sopenharmony_ci	};
62998c2ecf20Sopenharmony_ci
63008c2ecf20Sopenharmony_ci	hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]);
63018c2ecf20Sopenharmony_ci
63028c2ecf20Sopenharmony_ci	memset(active, 0, sizeof(*active));
63038c2ecf20Sopenharmony_ci
63048c2ecf20Sopenharmony_ci	active->pipe_enabled = crtc->active;
63058c2ecf20Sopenharmony_ci
63068c2ecf20Sopenharmony_ci	if (active->pipe_enabled) {
63078c2ecf20Sopenharmony_ci		u32 tmp = hw->wm_pipe[pipe];
63088c2ecf20Sopenharmony_ci
63098c2ecf20Sopenharmony_ci		/*
63108c2ecf20Sopenharmony_ci		 * For active pipes LP0 watermark is marked as
63118c2ecf20Sopenharmony_ci		 * enabled, and LP1+ watermaks as disabled since
63128c2ecf20Sopenharmony_ci		 * we can't really reverse compute them in case
63138c2ecf20Sopenharmony_ci		 * multiple pipes are active.
63148c2ecf20Sopenharmony_ci		 */
63158c2ecf20Sopenharmony_ci		active->wm[0].enable = true;
63168c2ecf20Sopenharmony_ci		active->wm[0].pri_val = (tmp & WM0_PIPE_PLANE_MASK) >> WM0_PIPE_PLANE_SHIFT;
63178c2ecf20Sopenharmony_ci		active->wm[0].spr_val = (tmp & WM0_PIPE_SPRITE_MASK) >> WM0_PIPE_SPRITE_SHIFT;
63188c2ecf20Sopenharmony_ci		active->wm[0].cur_val = tmp & WM0_PIPE_CURSOR_MASK;
63198c2ecf20Sopenharmony_ci	} else {
63208c2ecf20Sopenharmony_ci		int level, max_level = ilk_wm_max_level(dev_priv);
63218c2ecf20Sopenharmony_ci
63228c2ecf20Sopenharmony_ci		/*
63238c2ecf20Sopenharmony_ci		 * For inactive pipes, all watermark levels
63248c2ecf20Sopenharmony_ci		 * should be marked as enabled but zeroed,
63258c2ecf20Sopenharmony_ci		 * which is what we'd compute them to.
63268c2ecf20Sopenharmony_ci		 */
63278c2ecf20Sopenharmony_ci		for (level = 0; level <= max_level; level++)
63288c2ecf20Sopenharmony_ci			active->wm[level].enable = true;
63298c2ecf20Sopenharmony_ci	}
63308c2ecf20Sopenharmony_ci
63318c2ecf20Sopenharmony_ci	crtc->wm.active.ilk = *active;
63328c2ecf20Sopenharmony_ci}
63338c2ecf20Sopenharmony_ci
63348c2ecf20Sopenharmony_ci#define _FW_WM(value, plane) \
63358c2ecf20Sopenharmony_ci	(((value) & DSPFW_ ## plane ## _MASK) >> DSPFW_ ## plane ## _SHIFT)
63368c2ecf20Sopenharmony_ci#define _FW_WM_VLV(value, plane) \
63378c2ecf20Sopenharmony_ci	(((value) & DSPFW_ ## plane ## _MASK_VLV) >> DSPFW_ ## plane ## _SHIFT)
63388c2ecf20Sopenharmony_ci
63398c2ecf20Sopenharmony_cistatic void g4x_read_wm_values(struct drm_i915_private *dev_priv,
63408c2ecf20Sopenharmony_ci			       struct g4x_wm_values *wm)
63418c2ecf20Sopenharmony_ci{
63428c2ecf20Sopenharmony_ci	u32 tmp;
63438c2ecf20Sopenharmony_ci
63448c2ecf20Sopenharmony_ci	tmp = I915_READ(DSPFW1);
63458c2ecf20Sopenharmony_ci	wm->sr.plane = _FW_WM(tmp, SR);
63468c2ecf20Sopenharmony_ci	wm->pipe[PIPE_B].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORB);
63478c2ecf20Sopenharmony_ci	wm->pipe[PIPE_B].plane[PLANE_PRIMARY] = _FW_WM(tmp, PLANEB);
63488c2ecf20Sopenharmony_ci	wm->pipe[PIPE_A].plane[PLANE_PRIMARY] = _FW_WM(tmp, PLANEA);
63498c2ecf20Sopenharmony_ci
63508c2ecf20Sopenharmony_ci	tmp = I915_READ(DSPFW2);
63518c2ecf20Sopenharmony_ci	wm->fbc_en = tmp & DSPFW_FBC_SR_EN;
63528c2ecf20Sopenharmony_ci	wm->sr.fbc = _FW_WM(tmp, FBC_SR);
63538c2ecf20Sopenharmony_ci	wm->hpll.fbc = _FW_WM(tmp, FBC_HPLL_SR);
63548c2ecf20Sopenharmony_ci	wm->pipe[PIPE_B].plane[PLANE_SPRITE0] = _FW_WM(tmp, SPRITEB);
63558c2ecf20Sopenharmony_ci	wm->pipe[PIPE_A].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORA);
63568c2ecf20Sopenharmony_ci	wm->pipe[PIPE_A].plane[PLANE_SPRITE0] = _FW_WM(tmp, SPRITEA);
63578c2ecf20Sopenharmony_ci
63588c2ecf20Sopenharmony_ci	tmp = I915_READ(DSPFW3);
63598c2ecf20Sopenharmony_ci	wm->hpll_en = tmp & DSPFW_HPLL_SR_EN;
63608c2ecf20Sopenharmony_ci	wm->sr.cursor = _FW_WM(tmp, CURSOR_SR);
63618c2ecf20Sopenharmony_ci	wm->hpll.cursor = _FW_WM(tmp, HPLL_CURSOR);
63628c2ecf20Sopenharmony_ci	wm->hpll.plane = _FW_WM(tmp, HPLL_SR);
63638c2ecf20Sopenharmony_ci}
63648c2ecf20Sopenharmony_ci
63658c2ecf20Sopenharmony_cistatic void vlv_read_wm_values(struct drm_i915_private *dev_priv,
63668c2ecf20Sopenharmony_ci			       struct vlv_wm_values *wm)
63678c2ecf20Sopenharmony_ci{
63688c2ecf20Sopenharmony_ci	enum pipe pipe;
63698c2ecf20Sopenharmony_ci	u32 tmp;
63708c2ecf20Sopenharmony_ci
63718c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
63728c2ecf20Sopenharmony_ci		tmp = I915_READ(VLV_DDL(pipe));
63738c2ecf20Sopenharmony_ci
63748c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_PRIMARY] =
63758c2ecf20Sopenharmony_ci			(tmp >> DDL_PLANE_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
63768c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_CURSOR] =
63778c2ecf20Sopenharmony_ci			(tmp >> DDL_CURSOR_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
63788c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_SPRITE0] =
63798c2ecf20Sopenharmony_ci			(tmp >> DDL_SPRITE_SHIFT(0)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
63808c2ecf20Sopenharmony_ci		wm->ddl[pipe].plane[PLANE_SPRITE1] =
63818c2ecf20Sopenharmony_ci			(tmp >> DDL_SPRITE_SHIFT(1)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK);
63828c2ecf20Sopenharmony_ci	}
63838c2ecf20Sopenharmony_ci
63848c2ecf20Sopenharmony_ci	tmp = I915_READ(DSPFW1);
63858c2ecf20Sopenharmony_ci	wm->sr.plane = _FW_WM(tmp, SR);
63868c2ecf20Sopenharmony_ci	wm->pipe[PIPE_B].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORB);
63878c2ecf20Sopenharmony_ci	wm->pipe[PIPE_B].plane[PLANE_PRIMARY] = _FW_WM_VLV(tmp, PLANEB);
63888c2ecf20Sopenharmony_ci	wm->pipe[PIPE_A].plane[PLANE_PRIMARY] = _FW_WM_VLV(tmp, PLANEA);
63898c2ecf20Sopenharmony_ci
63908c2ecf20Sopenharmony_ci	tmp = I915_READ(DSPFW2);
63918c2ecf20Sopenharmony_ci	wm->pipe[PIPE_A].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITEB);
63928c2ecf20Sopenharmony_ci	wm->pipe[PIPE_A].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORA);
63938c2ecf20Sopenharmony_ci	wm->pipe[PIPE_A].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEA);
63948c2ecf20Sopenharmony_ci
63958c2ecf20Sopenharmony_ci	tmp = I915_READ(DSPFW3);
63968c2ecf20Sopenharmony_ci	wm->sr.cursor = _FW_WM(tmp, CURSOR_SR);
63978c2ecf20Sopenharmony_ci
63988c2ecf20Sopenharmony_ci	if (IS_CHERRYVIEW(dev_priv)) {
63998c2ecf20Sopenharmony_ci		tmp = I915_READ(DSPFW7_CHV);
64008c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITED);
64018c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEC);
64028c2ecf20Sopenharmony_ci
64038c2ecf20Sopenharmony_ci		tmp = I915_READ(DSPFW8_CHV);
64048c2ecf20Sopenharmony_ci		wm->pipe[PIPE_C].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITEF);
64058c2ecf20Sopenharmony_ci		wm->pipe[PIPE_C].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEE);
64068c2ecf20Sopenharmony_ci
64078c2ecf20Sopenharmony_ci		tmp = I915_READ(DSPFW9_CHV);
64088c2ecf20Sopenharmony_ci		wm->pipe[PIPE_C].plane[PLANE_PRIMARY] = _FW_WM_VLV(tmp, PLANEC);
64098c2ecf20Sopenharmony_ci		wm->pipe[PIPE_C].plane[PLANE_CURSOR] = _FW_WM(tmp, CURSORC);
64108c2ecf20Sopenharmony_ci
64118c2ecf20Sopenharmony_ci		tmp = I915_READ(DSPHOWM);
64128c2ecf20Sopenharmony_ci		wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9;
64138c2ecf20Sopenharmony_ci		wm->pipe[PIPE_C].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITEF_HI) << 8;
64148c2ecf20Sopenharmony_ci		wm->pipe[PIPE_C].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEE_HI) << 8;
64158c2ecf20Sopenharmony_ci		wm->pipe[PIPE_C].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEC_HI) << 8;
64168c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITED_HI) << 8;
64178c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEC_HI) << 8;
64188c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEB_HI) << 8;
64198c2ecf20Sopenharmony_ci		wm->pipe[PIPE_A].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITEB_HI) << 8;
64208c2ecf20Sopenharmony_ci		wm->pipe[PIPE_A].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEA_HI) << 8;
64218c2ecf20Sopenharmony_ci		wm->pipe[PIPE_A].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEA_HI) << 8;
64228c2ecf20Sopenharmony_ci	} else {
64238c2ecf20Sopenharmony_ci		tmp = I915_READ(DSPFW7);
64248c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] = _FW_WM_VLV(tmp, SPRITED);
64258c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] = _FW_WM_VLV(tmp, SPRITEC);
64268c2ecf20Sopenharmony_ci
64278c2ecf20Sopenharmony_ci		tmp = I915_READ(DSPHOWM);
64288c2ecf20Sopenharmony_ci		wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9;
64298c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITED_HI) << 8;
64308c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEC_HI) << 8;
64318c2ecf20Sopenharmony_ci		wm->pipe[PIPE_B].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEB_HI) << 8;
64328c2ecf20Sopenharmony_ci		wm->pipe[PIPE_A].plane[PLANE_SPRITE1] |= _FW_WM(tmp, SPRITEB_HI) << 8;
64338c2ecf20Sopenharmony_ci		wm->pipe[PIPE_A].plane[PLANE_SPRITE0] |= _FW_WM(tmp, SPRITEA_HI) << 8;
64348c2ecf20Sopenharmony_ci		wm->pipe[PIPE_A].plane[PLANE_PRIMARY] |= _FW_WM(tmp, PLANEA_HI) << 8;
64358c2ecf20Sopenharmony_ci	}
64368c2ecf20Sopenharmony_ci}
64378c2ecf20Sopenharmony_ci
64388c2ecf20Sopenharmony_ci#undef _FW_WM
64398c2ecf20Sopenharmony_ci#undef _FW_WM_VLV
64408c2ecf20Sopenharmony_ci
64418c2ecf20Sopenharmony_civoid g4x_wm_get_hw_state(struct drm_i915_private *dev_priv)
64428c2ecf20Sopenharmony_ci{
64438c2ecf20Sopenharmony_ci	struct g4x_wm_values *wm = &dev_priv->wm.g4x;
64448c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
64458c2ecf20Sopenharmony_ci
64468c2ecf20Sopenharmony_ci	g4x_read_wm_values(dev_priv, wm);
64478c2ecf20Sopenharmony_ci
64488c2ecf20Sopenharmony_ci	wm->cxsr = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
64498c2ecf20Sopenharmony_ci
64508c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
64518c2ecf20Sopenharmony_ci		struct intel_crtc_state *crtc_state =
64528c2ecf20Sopenharmony_ci			to_intel_crtc_state(crtc->base.state);
64538c2ecf20Sopenharmony_ci		struct g4x_wm_state *active = &crtc->wm.active.g4x;
64548c2ecf20Sopenharmony_ci		struct g4x_pipe_wm *raw;
64558c2ecf20Sopenharmony_ci		enum pipe pipe = crtc->pipe;
64568c2ecf20Sopenharmony_ci		enum plane_id plane_id;
64578c2ecf20Sopenharmony_ci		int level, max_level;
64588c2ecf20Sopenharmony_ci
64598c2ecf20Sopenharmony_ci		active->cxsr = wm->cxsr;
64608c2ecf20Sopenharmony_ci		active->hpll_en = wm->hpll_en;
64618c2ecf20Sopenharmony_ci		active->fbc_en = wm->fbc_en;
64628c2ecf20Sopenharmony_ci
64638c2ecf20Sopenharmony_ci		active->sr = wm->sr;
64648c2ecf20Sopenharmony_ci		active->hpll = wm->hpll;
64658c2ecf20Sopenharmony_ci
64668c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id) {
64678c2ecf20Sopenharmony_ci			active->wm.plane[plane_id] =
64688c2ecf20Sopenharmony_ci				wm->pipe[pipe].plane[plane_id];
64698c2ecf20Sopenharmony_ci		}
64708c2ecf20Sopenharmony_ci
64718c2ecf20Sopenharmony_ci		if (wm->cxsr && wm->hpll_en)
64728c2ecf20Sopenharmony_ci			max_level = G4X_WM_LEVEL_HPLL;
64738c2ecf20Sopenharmony_ci		else if (wm->cxsr)
64748c2ecf20Sopenharmony_ci			max_level = G4X_WM_LEVEL_SR;
64758c2ecf20Sopenharmony_ci		else
64768c2ecf20Sopenharmony_ci			max_level = G4X_WM_LEVEL_NORMAL;
64778c2ecf20Sopenharmony_ci
64788c2ecf20Sopenharmony_ci		level = G4X_WM_LEVEL_NORMAL;
64798c2ecf20Sopenharmony_ci		raw = &crtc_state->wm.g4x.raw[level];
64808c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id)
64818c2ecf20Sopenharmony_ci			raw->plane[plane_id] = active->wm.plane[plane_id];
64828c2ecf20Sopenharmony_ci
64838c2ecf20Sopenharmony_ci		if (++level > max_level)
64848c2ecf20Sopenharmony_ci			goto out;
64858c2ecf20Sopenharmony_ci
64868c2ecf20Sopenharmony_ci		raw = &crtc_state->wm.g4x.raw[level];
64878c2ecf20Sopenharmony_ci		raw->plane[PLANE_PRIMARY] = active->sr.plane;
64888c2ecf20Sopenharmony_ci		raw->plane[PLANE_CURSOR] = active->sr.cursor;
64898c2ecf20Sopenharmony_ci		raw->plane[PLANE_SPRITE0] = 0;
64908c2ecf20Sopenharmony_ci		raw->fbc = active->sr.fbc;
64918c2ecf20Sopenharmony_ci
64928c2ecf20Sopenharmony_ci		if (++level > max_level)
64938c2ecf20Sopenharmony_ci			goto out;
64948c2ecf20Sopenharmony_ci
64958c2ecf20Sopenharmony_ci		raw = &crtc_state->wm.g4x.raw[level];
64968c2ecf20Sopenharmony_ci		raw->plane[PLANE_PRIMARY] = active->hpll.plane;
64978c2ecf20Sopenharmony_ci		raw->plane[PLANE_CURSOR] = active->hpll.cursor;
64988c2ecf20Sopenharmony_ci		raw->plane[PLANE_SPRITE0] = 0;
64998c2ecf20Sopenharmony_ci		raw->fbc = active->hpll.fbc;
65008c2ecf20Sopenharmony_ci
65018c2ecf20Sopenharmony_ci	out:
65028c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id)
65038c2ecf20Sopenharmony_ci			g4x_raw_plane_wm_set(crtc_state, level,
65048c2ecf20Sopenharmony_ci					     plane_id, USHRT_MAX);
65058c2ecf20Sopenharmony_ci		g4x_raw_fbc_wm_set(crtc_state, level, USHRT_MAX);
65068c2ecf20Sopenharmony_ci
65078c2ecf20Sopenharmony_ci		crtc_state->wm.g4x.optimal = *active;
65088c2ecf20Sopenharmony_ci		crtc_state->wm.g4x.intermediate = *active;
65098c2ecf20Sopenharmony_ci
65108c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
65118c2ecf20Sopenharmony_ci			    "Initial watermarks: pipe %c, plane=%d, cursor=%d, sprite=%d\n",
65128c2ecf20Sopenharmony_ci			    pipe_name(pipe),
65138c2ecf20Sopenharmony_ci			    wm->pipe[pipe].plane[PLANE_PRIMARY],
65148c2ecf20Sopenharmony_ci			    wm->pipe[pipe].plane[PLANE_CURSOR],
65158c2ecf20Sopenharmony_ci			    wm->pipe[pipe].plane[PLANE_SPRITE0]);
65168c2ecf20Sopenharmony_ci	}
65178c2ecf20Sopenharmony_ci
65188c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
65198c2ecf20Sopenharmony_ci		    "Initial SR watermarks: plane=%d, cursor=%d fbc=%d\n",
65208c2ecf20Sopenharmony_ci		    wm->sr.plane, wm->sr.cursor, wm->sr.fbc);
65218c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
65228c2ecf20Sopenharmony_ci		    "Initial HPLL watermarks: plane=%d, SR cursor=%d fbc=%d\n",
65238c2ecf20Sopenharmony_ci		    wm->hpll.plane, wm->hpll.cursor, wm->hpll.fbc);
65248c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "Initial SR=%s HPLL=%s FBC=%s\n",
65258c2ecf20Sopenharmony_ci		    yesno(wm->cxsr), yesno(wm->hpll_en), yesno(wm->fbc_en));
65268c2ecf20Sopenharmony_ci}
65278c2ecf20Sopenharmony_ci
65288c2ecf20Sopenharmony_civoid g4x_wm_sanitize(struct drm_i915_private *dev_priv)
65298c2ecf20Sopenharmony_ci{
65308c2ecf20Sopenharmony_ci	struct intel_plane *plane;
65318c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
65328c2ecf20Sopenharmony_ci
65338c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
65348c2ecf20Sopenharmony_ci
65358c2ecf20Sopenharmony_ci	for_each_intel_plane(&dev_priv->drm, plane) {
65368c2ecf20Sopenharmony_ci		struct intel_crtc *crtc =
65378c2ecf20Sopenharmony_ci			intel_get_crtc_for_pipe(dev_priv, plane->pipe);
65388c2ecf20Sopenharmony_ci		struct intel_crtc_state *crtc_state =
65398c2ecf20Sopenharmony_ci			to_intel_crtc_state(crtc->base.state);
65408c2ecf20Sopenharmony_ci		struct intel_plane_state *plane_state =
65418c2ecf20Sopenharmony_ci			to_intel_plane_state(plane->base.state);
65428c2ecf20Sopenharmony_ci		struct g4x_wm_state *wm_state = &crtc_state->wm.g4x.optimal;
65438c2ecf20Sopenharmony_ci		enum plane_id plane_id = plane->id;
65448c2ecf20Sopenharmony_ci		int level;
65458c2ecf20Sopenharmony_ci
65468c2ecf20Sopenharmony_ci		if (plane_state->uapi.visible)
65478c2ecf20Sopenharmony_ci			continue;
65488c2ecf20Sopenharmony_ci
65498c2ecf20Sopenharmony_ci		for (level = 0; level < 3; level++) {
65508c2ecf20Sopenharmony_ci			struct g4x_pipe_wm *raw =
65518c2ecf20Sopenharmony_ci				&crtc_state->wm.g4x.raw[level];
65528c2ecf20Sopenharmony_ci
65538c2ecf20Sopenharmony_ci			raw->plane[plane_id] = 0;
65548c2ecf20Sopenharmony_ci			wm_state->wm.plane[plane_id] = 0;
65558c2ecf20Sopenharmony_ci		}
65568c2ecf20Sopenharmony_ci
65578c2ecf20Sopenharmony_ci		if (plane_id == PLANE_PRIMARY) {
65588c2ecf20Sopenharmony_ci			for (level = 0; level < 3; level++) {
65598c2ecf20Sopenharmony_ci				struct g4x_pipe_wm *raw =
65608c2ecf20Sopenharmony_ci					&crtc_state->wm.g4x.raw[level];
65618c2ecf20Sopenharmony_ci				raw->fbc = 0;
65628c2ecf20Sopenharmony_ci			}
65638c2ecf20Sopenharmony_ci
65648c2ecf20Sopenharmony_ci			wm_state->sr.fbc = 0;
65658c2ecf20Sopenharmony_ci			wm_state->hpll.fbc = 0;
65668c2ecf20Sopenharmony_ci			wm_state->fbc_en = false;
65678c2ecf20Sopenharmony_ci		}
65688c2ecf20Sopenharmony_ci	}
65698c2ecf20Sopenharmony_ci
65708c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
65718c2ecf20Sopenharmony_ci		struct intel_crtc_state *crtc_state =
65728c2ecf20Sopenharmony_ci			to_intel_crtc_state(crtc->base.state);
65738c2ecf20Sopenharmony_ci
65748c2ecf20Sopenharmony_ci		crtc_state->wm.g4x.intermediate =
65758c2ecf20Sopenharmony_ci			crtc_state->wm.g4x.optimal;
65768c2ecf20Sopenharmony_ci		crtc->wm.active.g4x = crtc_state->wm.g4x.optimal;
65778c2ecf20Sopenharmony_ci	}
65788c2ecf20Sopenharmony_ci
65798c2ecf20Sopenharmony_ci	g4x_program_watermarks(dev_priv);
65808c2ecf20Sopenharmony_ci
65818c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
65828c2ecf20Sopenharmony_ci}
65838c2ecf20Sopenharmony_ci
65848c2ecf20Sopenharmony_civoid vlv_wm_get_hw_state(struct drm_i915_private *dev_priv)
65858c2ecf20Sopenharmony_ci{
65868c2ecf20Sopenharmony_ci	struct vlv_wm_values *wm = &dev_priv->wm.vlv;
65878c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
65888c2ecf20Sopenharmony_ci	u32 val;
65898c2ecf20Sopenharmony_ci
65908c2ecf20Sopenharmony_ci	vlv_read_wm_values(dev_priv, wm);
65918c2ecf20Sopenharmony_ci
65928c2ecf20Sopenharmony_ci	wm->cxsr = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN;
65938c2ecf20Sopenharmony_ci	wm->level = VLV_WM_LEVEL_PM2;
65948c2ecf20Sopenharmony_ci
65958c2ecf20Sopenharmony_ci	if (IS_CHERRYVIEW(dev_priv)) {
65968c2ecf20Sopenharmony_ci		vlv_punit_get(dev_priv);
65978c2ecf20Sopenharmony_ci
65988c2ecf20Sopenharmony_ci		val = vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM);
65998c2ecf20Sopenharmony_ci		if (val & DSP_MAXFIFO_PM5_ENABLE)
66008c2ecf20Sopenharmony_ci			wm->level = VLV_WM_LEVEL_PM5;
66018c2ecf20Sopenharmony_ci
66028c2ecf20Sopenharmony_ci		/*
66038c2ecf20Sopenharmony_ci		 * If DDR DVFS is disabled in the BIOS, Punit
66048c2ecf20Sopenharmony_ci		 * will never ack the request. So if that happens
66058c2ecf20Sopenharmony_ci		 * assume we don't have to enable/disable DDR DVFS
66068c2ecf20Sopenharmony_ci		 * dynamically. To test that just set the REQ_ACK
66078c2ecf20Sopenharmony_ci		 * bit to poke the Punit, but don't change the
66088c2ecf20Sopenharmony_ci		 * HIGH/LOW bits so that we don't actually change
66098c2ecf20Sopenharmony_ci		 * the current state.
66108c2ecf20Sopenharmony_ci		 */
66118c2ecf20Sopenharmony_ci		val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
66128c2ecf20Sopenharmony_ci		val |= FORCE_DDR_FREQ_REQ_ACK;
66138c2ecf20Sopenharmony_ci		vlv_punit_write(dev_priv, PUNIT_REG_DDR_SETUP2, val);
66148c2ecf20Sopenharmony_ci
66158c2ecf20Sopenharmony_ci		if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2) &
66168c2ecf20Sopenharmony_ci			      FORCE_DDR_FREQ_REQ_ACK) == 0, 3)) {
66178c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
66188c2ecf20Sopenharmony_ci				    "Punit not acking DDR DVFS request, "
66198c2ecf20Sopenharmony_ci				    "assuming DDR DVFS is disabled\n");
66208c2ecf20Sopenharmony_ci			dev_priv->wm.max_level = VLV_WM_LEVEL_PM5;
66218c2ecf20Sopenharmony_ci		} else {
66228c2ecf20Sopenharmony_ci			val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
66238c2ecf20Sopenharmony_ci			if ((val & FORCE_DDR_HIGH_FREQ) == 0)
66248c2ecf20Sopenharmony_ci				wm->level = VLV_WM_LEVEL_DDR_DVFS;
66258c2ecf20Sopenharmony_ci		}
66268c2ecf20Sopenharmony_ci
66278c2ecf20Sopenharmony_ci		vlv_punit_put(dev_priv);
66288c2ecf20Sopenharmony_ci	}
66298c2ecf20Sopenharmony_ci
66308c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
66318c2ecf20Sopenharmony_ci		struct intel_crtc_state *crtc_state =
66328c2ecf20Sopenharmony_ci			to_intel_crtc_state(crtc->base.state);
66338c2ecf20Sopenharmony_ci		struct vlv_wm_state *active = &crtc->wm.active.vlv;
66348c2ecf20Sopenharmony_ci		const struct vlv_fifo_state *fifo_state =
66358c2ecf20Sopenharmony_ci			&crtc_state->wm.vlv.fifo_state;
66368c2ecf20Sopenharmony_ci		enum pipe pipe = crtc->pipe;
66378c2ecf20Sopenharmony_ci		enum plane_id plane_id;
66388c2ecf20Sopenharmony_ci		int level;
66398c2ecf20Sopenharmony_ci
66408c2ecf20Sopenharmony_ci		vlv_get_fifo_size(crtc_state);
66418c2ecf20Sopenharmony_ci
66428c2ecf20Sopenharmony_ci		active->num_levels = wm->level + 1;
66438c2ecf20Sopenharmony_ci		active->cxsr = wm->cxsr;
66448c2ecf20Sopenharmony_ci
66458c2ecf20Sopenharmony_ci		for (level = 0; level < active->num_levels; level++) {
66468c2ecf20Sopenharmony_ci			struct g4x_pipe_wm *raw =
66478c2ecf20Sopenharmony_ci				&crtc_state->wm.vlv.raw[level];
66488c2ecf20Sopenharmony_ci
66498c2ecf20Sopenharmony_ci			active->sr[level].plane = wm->sr.plane;
66508c2ecf20Sopenharmony_ci			active->sr[level].cursor = wm->sr.cursor;
66518c2ecf20Sopenharmony_ci
66528c2ecf20Sopenharmony_ci			for_each_plane_id_on_crtc(crtc, plane_id) {
66538c2ecf20Sopenharmony_ci				active->wm[level].plane[plane_id] =
66548c2ecf20Sopenharmony_ci					wm->pipe[pipe].plane[plane_id];
66558c2ecf20Sopenharmony_ci
66568c2ecf20Sopenharmony_ci				raw->plane[plane_id] =
66578c2ecf20Sopenharmony_ci					vlv_invert_wm_value(active->wm[level].plane[plane_id],
66588c2ecf20Sopenharmony_ci							    fifo_state->plane[plane_id]);
66598c2ecf20Sopenharmony_ci			}
66608c2ecf20Sopenharmony_ci		}
66618c2ecf20Sopenharmony_ci
66628c2ecf20Sopenharmony_ci		for_each_plane_id_on_crtc(crtc, plane_id)
66638c2ecf20Sopenharmony_ci			vlv_raw_plane_wm_set(crtc_state, level,
66648c2ecf20Sopenharmony_ci					     plane_id, USHRT_MAX);
66658c2ecf20Sopenharmony_ci		vlv_invalidate_wms(crtc, active, level);
66668c2ecf20Sopenharmony_ci
66678c2ecf20Sopenharmony_ci		crtc_state->wm.vlv.optimal = *active;
66688c2ecf20Sopenharmony_ci		crtc_state->wm.vlv.intermediate = *active;
66698c2ecf20Sopenharmony_ci
66708c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
66718c2ecf20Sopenharmony_ci			    "Initial watermarks: pipe %c, plane=%d, cursor=%d, sprite0=%d, sprite1=%d\n",
66728c2ecf20Sopenharmony_ci			    pipe_name(pipe),
66738c2ecf20Sopenharmony_ci			    wm->pipe[pipe].plane[PLANE_PRIMARY],
66748c2ecf20Sopenharmony_ci			    wm->pipe[pipe].plane[PLANE_CURSOR],
66758c2ecf20Sopenharmony_ci			    wm->pipe[pipe].plane[PLANE_SPRITE0],
66768c2ecf20Sopenharmony_ci			    wm->pipe[pipe].plane[PLANE_SPRITE1]);
66778c2ecf20Sopenharmony_ci	}
66788c2ecf20Sopenharmony_ci
66798c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
66808c2ecf20Sopenharmony_ci		    "Initial watermarks: SR plane=%d, SR cursor=%d level=%d cxsr=%d\n",
66818c2ecf20Sopenharmony_ci		    wm->sr.plane, wm->sr.cursor, wm->level, wm->cxsr);
66828c2ecf20Sopenharmony_ci}
66838c2ecf20Sopenharmony_ci
66848c2ecf20Sopenharmony_civoid vlv_wm_sanitize(struct drm_i915_private *dev_priv)
66858c2ecf20Sopenharmony_ci{
66868c2ecf20Sopenharmony_ci	struct intel_plane *plane;
66878c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
66888c2ecf20Sopenharmony_ci
66898c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->wm.wm_mutex);
66908c2ecf20Sopenharmony_ci
66918c2ecf20Sopenharmony_ci	for_each_intel_plane(&dev_priv->drm, plane) {
66928c2ecf20Sopenharmony_ci		struct intel_crtc *crtc =
66938c2ecf20Sopenharmony_ci			intel_get_crtc_for_pipe(dev_priv, plane->pipe);
66948c2ecf20Sopenharmony_ci		struct intel_crtc_state *crtc_state =
66958c2ecf20Sopenharmony_ci			to_intel_crtc_state(crtc->base.state);
66968c2ecf20Sopenharmony_ci		struct intel_plane_state *plane_state =
66978c2ecf20Sopenharmony_ci			to_intel_plane_state(plane->base.state);
66988c2ecf20Sopenharmony_ci		struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
66998c2ecf20Sopenharmony_ci		const struct vlv_fifo_state *fifo_state =
67008c2ecf20Sopenharmony_ci			&crtc_state->wm.vlv.fifo_state;
67018c2ecf20Sopenharmony_ci		enum plane_id plane_id = plane->id;
67028c2ecf20Sopenharmony_ci		int level;
67038c2ecf20Sopenharmony_ci
67048c2ecf20Sopenharmony_ci		if (plane_state->uapi.visible)
67058c2ecf20Sopenharmony_ci			continue;
67068c2ecf20Sopenharmony_ci
67078c2ecf20Sopenharmony_ci		for (level = 0; level < wm_state->num_levels; level++) {
67088c2ecf20Sopenharmony_ci			struct g4x_pipe_wm *raw =
67098c2ecf20Sopenharmony_ci				&crtc_state->wm.vlv.raw[level];
67108c2ecf20Sopenharmony_ci
67118c2ecf20Sopenharmony_ci			raw->plane[plane_id] = 0;
67128c2ecf20Sopenharmony_ci
67138c2ecf20Sopenharmony_ci			wm_state->wm[level].plane[plane_id] =
67148c2ecf20Sopenharmony_ci				vlv_invert_wm_value(raw->plane[plane_id],
67158c2ecf20Sopenharmony_ci						    fifo_state->plane[plane_id]);
67168c2ecf20Sopenharmony_ci		}
67178c2ecf20Sopenharmony_ci	}
67188c2ecf20Sopenharmony_ci
67198c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc) {
67208c2ecf20Sopenharmony_ci		struct intel_crtc_state *crtc_state =
67218c2ecf20Sopenharmony_ci			to_intel_crtc_state(crtc->base.state);
67228c2ecf20Sopenharmony_ci
67238c2ecf20Sopenharmony_ci		crtc_state->wm.vlv.intermediate =
67248c2ecf20Sopenharmony_ci			crtc_state->wm.vlv.optimal;
67258c2ecf20Sopenharmony_ci		crtc->wm.active.vlv = crtc_state->wm.vlv.optimal;
67268c2ecf20Sopenharmony_ci	}
67278c2ecf20Sopenharmony_ci
67288c2ecf20Sopenharmony_ci	vlv_program_watermarks(dev_priv);
67298c2ecf20Sopenharmony_ci
67308c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->wm.wm_mutex);
67318c2ecf20Sopenharmony_ci}
67328c2ecf20Sopenharmony_ci
67338c2ecf20Sopenharmony_ci/*
67348c2ecf20Sopenharmony_ci * FIXME should probably kill this and improve
67358c2ecf20Sopenharmony_ci * the real watermark readout/sanitation instead
67368c2ecf20Sopenharmony_ci */
67378c2ecf20Sopenharmony_cistatic void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv)
67388c2ecf20Sopenharmony_ci{
67398c2ecf20Sopenharmony_ci	I915_WRITE(WM3_LP_ILK, I915_READ(WM3_LP_ILK) & ~WM1_LP_SR_EN);
67408c2ecf20Sopenharmony_ci	I915_WRITE(WM2_LP_ILK, I915_READ(WM2_LP_ILK) & ~WM1_LP_SR_EN);
67418c2ecf20Sopenharmony_ci	I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
67428c2ecf20Sopenharmony_ci
67438c2ecf20Sopenharmony_ci	/*
67448c2ecf20Sopenharmony_ci	 * Don't touch WM1S_LP_EN here.
67458c2ecf20Sopenharmony_ci	 * Doing so could cause underruns.
67468c2ecf20Sopenharmony_ci	 */
67478c2ecf20Sopenharmony_ci}
67488c2ecf20Sopenharmony_ci
67498c2ecf20Sopenharmony_civoid ilk_wm_get_hw_state(struct drm_i915_private *dev_priv)
67508c2ecf20Sopenharmony_ci{
67518c2ecf20Sopenharmony_ci	struct ilk_wm_values *hw = &dev_priv->wm.hw;
67528c2ecf20Sopenharmony_ci	struct intel_crtc *crtc;
67538c2ecf20Sopenharmony_ci
67548c2ecf20Sopenharmony_ci	ilk_init_lp_watermarks(dev_priv);
67558c2ecf20Sopenharmony_ci
67568c2ecf20Sopenharmony_ci	for_each_intel_crtc(&dev_priv->drm, crtc)
67578c2ecf20Sopenharmony_ci		ilk_pipe_wm_get_hw_state(crtc);
67588c2ecf20Sopenharmony_ci
67598c2ecf20Sopenharmony_ci	hw->wm_lp[0] = I915_READ(WM1_LP_ILK);
67608c2ecf20Sopenharmony_ci	hw->wm_lp[1] = I915_READ(WM2_LP_ILK);
67618c2ecf20Sopenharmony_ci	hw->wm_lp[2] = I915_READ(WM3_LP_ILK);
67628c2ecf20Sopenharmony_ci
67638c2ecf20Sopenharmony_ci	hw->wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
67648c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 7) {
67658c2ecf20Sopenharmony_ci		hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
67668c2ecf20Sopenharmony_ci		hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
67678c2ecf20Sopenharmony_ci	}
67688c2ecf20Sopenharmony_ci
67698c2ecf20Sopenharmony_ci	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
67708c2ecf20Sopenharmony_ci		hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
67718c2ecf20Sopenharmony_ci			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
67728c2ecf20Sopenharmony_ci	else if (IS_IVYBRIDGE(dev_priv))
67738c2ecf20Sopenharmony_ci		hw->partitioning = (I915_READ(DISP_ARB_CTL2) & DISP_DATA_PARTITION_5_6) ?
67748c2ecf20Sopenharmony_ci			INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
67758c2ecf20Sopenharmony_ci
67768c2ecf20Sopenharmony_ci	hw->enable_fbc_wm =
67778c2ecf20Sopenharmony_ci		!(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
67788c2ecf20Sopenharmony_ci}
67798c2ecf20Sopenharmony_ci
67808c2ecf20Sopenharmony_ci/**
67818c2ecf20Sopenharmony_ci * intel_update_watermarks - update FIFO watermark values based on current modes
67828c2ecf20Sopenharmony_ci * @crtc: the #intel_crtc on which to compute the WM
67838c2ecf20Sopenharmony_ci *
67848c2ecf20Sopenharmony_ci * Calculate watermark values for the various WM regs based on current mode
67858c2ecf20Sopenharmony_ci * and plane configuration.
67868c2ecf20Sopenharmony_ci *
67878c2ecf20Sopenharmony_ci * There are several cases to deal with here:
67888c2ecf20Sopenharmony_ci *   - normal (i.e. non-self-refresh)
67898c2ecf20Sopenharmony_ci *   - self-refresh (SR) mode
67908c2ecf20Sopenharmony_ci *   - lines are large relative to FIFO size (buffer can hold up to 2)
67918c2ecf20Sopenharmony_ci *   - lines are small relative to FIFO size (buffer can hold more than 2
67928c2ecf20Sopenharmony_ci *     lines), so need to account for TLB latency
67938c2ecf20Sopenharmony_ci *
67948c2ecf20Sopenharmony_ci *   The normal calculation is:
67958c2ecf20Sopenharmony_ci *     watermark = dotclock * bytes per pixel * latency
67968c2ecf20Sopenharmony_ci *   where latency is platform & configuration dependent (we assume pessimal
67978c2ecf20Sopenharmony_ci *   values here).
67988c2ecf20Sopenharmony_ci *
67998c2ecf20Sopenharmony_ci *   The SR calculation is:
68008c2ecf20Sopenharmony_ci *     watermark = (trunc(latency/line time)+1) * surface width *
68018c2ecf20Sopenharmony_ci *       bytes per pixel
68028c2ecf20Sopenharmony_ci *   where
68038c2ecf20Sopenharmony_ci *     line time = htotal / dotclock
68048c2ecf20Sopenharmony_ci *     surface width = hdisplay for normal plane and 64 for cursor
68058c2ecf20Sopenharmony_ci *   and latency is assumed to be high, as above.
68068c2ecf20Sopenharmony_ci *
68078c2ecf20Sopenharmony_ci * The final value programmed to the register should always be rounded up,
68088c2ecf20Sopenharmony_ci * and include an extra 2 entries to account for clock crossings.
68098c2ecf20Sopenharmony_ci *
68108c2ecf20Sopenharmony_ci * We don't use the sprite, so we can ignore that.  And on Crestline we have
68118c2ecf20Sopenharmony_ci * to set the non-SR watermarks to 8.
68128c2ecf20Sopenharmony_ci */
68138c2ecf20Sopenharmony_civoid intel_update_watermarks(struct intel_crtc *crtc)
68148c2ecf20Sopenharmony_ci{
68158c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
68168c2ecf20Sopenharmony_ci
68178c2ecf20Sopenharmony_ci	if (dev_priv->display.update_wm)
68188c2ecf20Sopenharmony_ci		dev_priv->display.update_wm(crtc);
68198c2ecf20Sopenharmony_ci}
68208c2ecf20Sopenharmony_ci
68218c2ecf20Sopenharmony_civoid intel_enable_ipc(struct drm_i915_private *dev_priv)
68228c2ecf20Sopenharmony_ci{
68238c2ecf20Sopenharmony_ci	u32 val;
68248c2ecf20Sopenharmony_ci
68258c2ecf20Sopenharmony_ci	if (!HAS_IPC(dev_priv))
68268c2ecf20Sopenharmony_ci		return;
68278c2ecf20Sopenharmony_ci
68288c2ecf20Sopenharmony_ci	val = I915_READ(DISP_ARB_CTL2);
68298c2ecf20Sopenharmony_ci
68308c2ecf20Sopenharmony_ci	if (dev_priv->ipc_enabled)
68318c2ecf20Sopenharmony_ci		val |= DISP_IPC_ENABLE;
68328c2ecf20Sopenharmony_ci	else
68338c2ecf20Sopenharmony_ci		val &= ~DISP_IPC_ENABLE;
68348c2ecf20Sopenharmony_ci
68358c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL2, val);
68368c2ecf20Sopenharmony_ci}
68378c2ecf20Sopenharmony_ci
68388c2ecf20Sopenharmony_cistatic bool intel_can_enable_ipc(struct drm_i915_private *dev_priv)
68398c2ecf20Sopenharmony_ci{
68408c2ecf20Sopenharmony_ci	/* Display WA #0477 WaDisableIPC: skl */
68418c2ecf20Sopenharmony_ci	if (IS_SKYLAKE(dev_priv))
68428c2ecf20Sopenharmony_ci		return false;
68438c2ecf20Sopenharmony_ci
68448c2ecf20Sopenharmony_ci	/* Display WA #1141: SKL:all KBL:all CFL */
68458c2ecf20Sopenharmony_ci	if (IS_KABYLAKE(dev_priv) ||
68468c2ecf20Sopenharmony_ci	    IS_COFFEELAKE(dev_priv) ||
68478c2ecf20Sopenharmony_ci	    IS_COMETLAKE(dev_priv))
68488c2ecf20Sopenharmony_ci		return dev_priv->dram_info.symmetric_memory;
68498c2ecf20Sopenharmony_ci
68508c2ecf20Sopenharmony_ci	return true;
68518c2ecf20Sopenharmony_ci}
68528c2ecf20Sopenharmony_ci
68538c2ecf20Sopenharmony_civoid intel_init_ipc(struct drm_i915_private *dev_priv)
68548c2ecf20Sopenharmony_ci{
68558c2ecf20Sopenharmony_ci	if (!HAS_IPC(dev_priv))
68568c2ecf20Sopenharmony_ci		return;
68578c2ecf20Sopenharmony_ci
68588c2ecf20Sopenharmony_ci	dev_priv->ipc_enabled = intel_can_enable_ipc(dev_priv);
68598c2ecf20Sopenharmony_ci
68608c2ecf20Sopenharmony_ci	intel_enable_ipc(dev_priv);
68618c2ecf20Sopenharmony_ci}
68628c2ecf20Sopenharmony_ci
68638c2ecf20Sopenharmony_cistatic void ibx_init_clock_gating(struct drm_i915_private *dev_priv)
68648c2ecf20Sopenharmony_ci{
68658c2ecf20Sopenharmony_ci	/*
68668c2ecf20Sopenharmony_ci	 * On Ibex Peak and Cougar Point, we need to disable clock
68678c2ecf20Sopenharmony_ci	 * gating for the panel power sequencer or it will fail to
68688c2ecf20Sopenharmony_ci	 * start up when no ports are active.
68698c2ecf20Sopenharmony_ci	 */
68708c2ecf20Sopenharmony_ci	I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
68718c2ecf20Sopenharmony_ci}
68728c2ecf20Sopenharmony_ci
68738c2ecf20Sopenharmony_cistatic void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv)
68748c2ecf20Sopenharmony_ci{
68758c2ecf20Sopenharmony_ci	enum pipe pipe;
68768c2ecf20Sopenharmony_ci
68778c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
68788c2ecf20Sopenharmony_ci		I915_WRITE(DSPCNTR(pipe),
68798c2ecf20Sopenharmony_ci			   I915_READ(DSPCNTR(pipe)) |
68808c2ecf20Sopenharmony_ci			   DISPPLANE_TRICKLE_FEED_DISABLE);
68818c2ecf20Sopenharmony_ci
68828c2ecf20Sopenharmony_ci		I915_WRITE(DSPSURF(pipe), I915_READ(DSPSURF(pipe)));
68838c2ecf20Sopenharmony_ci		POSTING_READ(DSPSURF(pipe));
68848c2ecf20Sopenharmony_ci	}
68858c2ecf20Sopenharmony_ci}
68868c2ecf20Sopenharmony_ci
68878c2ecf20Sopenharmony_cistatic void ilk_init_clock_gating(struct drm_i915_private *dev_priv)
68888c2ecf20Sopenharmony_ci{
68898c2ecf20Sopenharmony_ci	u32 dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
68908c2ecf20Sopenharmony_ci
68918c2ecf20Sopenharmony_ci	/*
68928c2ecf20Sopenharmony_ci	 * Required for FBC
68938c2ecf20Sopenharmony_ci	 * WaFbcDisableDpfcClockGating:ilk
68948c2ecf20Sopenharmony_ci	 */
68958c2ecf20Sopenharmony_ci	dspclk_gate |= ILK_DPFCRUNIT_CLOCK_GATE_DISABLE |
68968c2ecf20Sopenharmony_ci		   ILK_DPFCUNIT_CLOCK_GATE_DISABLE |
68978c2ecf20Sopenharmony_ci		   ILK_DPFDUNIT_CLOCK_GATE_ENABLE;
68988c2ecf20Sopenharmony_ci
68998c2ecf20Sopenharmony_ci	I915_WRITE(PCH_3DCGDIS0,
69008c2ecf20Sopenharmony_ci		   MARIUNIT_CLOCK_GATE_DISABLE |
69018c2ecf20Sopenharmony_ci		   SVSMUNIT_CLOCK_GATE_DISABLE);
69028c2ecf20Sopenharmony_ci	I915_WRITE(PCH_3DCGDIS1,
69038c2ecf20Sopenharmony_ci		   VFMUNIT_CLOCK_GATE_DISABLE);
69048c2ecf20Sopenharmony_ci
69058c2ecf20Sopenharmony_ci	/*
69068c2ecf20Sopenharmony_ci	 * According to the spec the following bits should be set in
69078c2ecf20Sopenharmony_ci	 * order to enable memory self-refresh
69088c2ecf20Sopenharmony_ci	 * The bit 22/21 of 0x42004
69098c2ecf20Sopenharmony_ci	 * The bit 5 of 0x42020
69108c2ecf20Sopenharmony_ci	 * The bit 15 of 0x45000
69118c2ecf20Sopenharmony_ci	 */
69128c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DISPLAY_CHICKEN2,
69138c2ecf20Sopenharmony_ci		   (I915_READ(ILK_DISPLAY_CHICKEN2) |
69148c2ecf20Sopenharmony_ci		    ILK_DPARB_GATE | ILK_VSDPFD_FULL));
69158c2ecf20Sopenharmony_ci	dspclk_gate |= ILK_DPARBUNIT_CLOCK_GATE_ENABLE;
69168c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL,
69178c2ecf20Sopenharmony_ci		   (I915_READ(DISP_ARB_CTL) |
69188c2ecf20Sopenharmony_ci		    DISP_FBC_WM_DIS));
69198c2ecf20Sopenharmony_ci
69208c2ecf20Sopenharmony_ci	/*
69218c2ecf20Sopenharmony_ci	 * Based on the document from hardware guys the following bits
69228c2ecf20Sopenharmony_ci	 * should be set unconditionally in order to enable FBC.
69238c2ecf20Sopenharmony_ci	 * The bit 22 of 0x42000
69248c2ecf20Sopenharmony_ci	 * The bit 22 of 0x42004
69258c2ecf20Sopenharmony_ci	 * The bit 7,8,9 of 0x42020.
69268c2ecf20Sopenharmony_ci	 */
69278c2ecf20Sopenharmony_ci	if (IS_IRONLAKE_M(dev_priv)) {
69288c2ecf20Sopenharmony_ci		/* WaFbcAsynchFlipDisableFbcQueue:ilk */
69298c2ecf20Sopenharmony_ci		I915_WRITE(ILK_DISPLAY_CHICKEN1,
69308c2ecf20Sopenharmony_ci			   I915_READ(ILK_DISPLAY_CHICKEN1) |
69318c2ecf20Sopenharmony_ci			   ILK_FBCQ_DIS);
69328c2ecf20Sopenharmony_ci		I915_WRITE(ILK_DISPLAY_CHICKEN2,
69338c2ecf20Sopenharmony_ci			   I915_READ(ILK_DISPLAY_CHICKEN2) |
69348c2ecf20Sopenharmony_ci			   ILK_DPARB_GATE);
69358c2ecf20Sopenharmony_ci	}
69368c2ecf20Sopenharmony_ci
69378c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DSPCLK_GATE_D, dspclk_gate);
69388c2ecf20Sopenharmony_ci
69398c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DISPLAY_CHICKEN2,
69408c2ecf20Sopenharmony_ci		   I915_READ(ILK_DISPLAY_CHICKEN2) |
69418c2ecf20Sopenharmony_ci		   ILK_ELPIN_409_SELECT);
69428c2ecf20Sopenharmony_ci
69438c2ecf20Sopenharmony_ci	g4x_disable_trickle_feed(dev_priv);
69448c2ecf20Sopenharmony_ci
69458c2ecf20Sopenharmony_ci	ibx_init_clock_gating(dev_priv);
69468c2ecf20Sopenharmony_ci}
69478c2ecf20Sopenharmony_ci
69488c2ecf20Sopenharmony_cistatic void cpt_init_clock_gating(struct drm_i915_private *dev_priv)
69498c2ecf20Sopenharmony_ci{
69508c2ecf20Sopenharmony_ci	enum pipe pipe;
69518c2ecf20Sopenharmony_ci	u32 val;
69528c2ecf20Sopenharmony_ci
69538c2ecf20Sopenharmony_ci	/*
69548c2ecf20Sopenharmony_ci	 * On Ibex Peak and Cougar Point, we need to disable clock
69558c2ecf20Sopenharmony_ci	 * gating for the panel power sequencer or it will fail to
69568c2ecf20Sopenharmony_ci	 * start up when no ports are active.
69578c2ecf20Sopenharmony_ci	 */
69588c2ecf20Sopenharmony_ci	I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE |
69598c2ecf20Sopenharmony_ci		   PCH_DPLUNIT_CLOCK_GATE_DISABLE |
69608c2ecf20Sopenharmony_ci		   PCH_CPUNIT_CLOCK_GATE_DISABLE);
69618c2ecf20Sopenharmony_ci	I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
69628c2ecf20Sopenharmony_ci		   DPLS_EDP_PPS_FIX_DIS);
69638c2ecf20Sopenharmony_ci	/* The below fixes the weird display corruption, a few pixels shifted
69648c2ecf20Sopenharmony_ci	 * downward, on (only) LVDS of some HP laptops with IVY.
69658c2ecf20Sopenharmony_ci	 */
69668c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
69678c2ecf20Sopenharmony_ci		val = I915_READ(TRANS_CHICKEN2(pipe));
69688c2ecf20Sopenharmony_ci		val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
69698c2ecf20Sopenharmony_ci		val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
69708c2ecf20Sopenharmony_ci		if (dev_priv->vbt.fdi_rx_polarity_inverted)
69718c2ecf20Sopenharmony_ci			val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
69728c2ecf20Sopenharmony_ci		val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER;
69738c2ecf20Sopenharmony_ci		val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH;
69748c2ecf20Sopenharmony_ci		I915_WRITE(TRANS_CHICKEN2(pipe), val);
69758c2ecf20Sopenharmony_ci	}
69768c2ecf20Sopenharmony_ci	/* WADP0ClockGatingDisable */
69778c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
69788c2ecf20Sopenharmony_ci		I915_WRITE(TRANS_CHICKEN1(pipe),
69798c2ecf20Sopenharmony_ci			   TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
69808c2ecf20Sopenharmony_ci	}
69818c2ecf20Sopenharmony_ci}
69828c2ecf20Sopenharmony_ci
69838c2ecf20Sopenharmony_cistatic void gen6_check_mch_setup(struct drm_i915_private *dev_priv)
69848c2ecf20Sopenharmony_ci{
69858c2ecf20Sopenharmony_ci	u32 tmp;
69868c2ecf20Sopenharmony_ci
69878c2ecf20Sopenharmony_ci	tmp = I915_READ(MCH_SSKPD);
69888c2ecf20Sopenharmony_ci	if ((tmp & MCH_SSKPD_WM0_MASK) != MCH_SSKPD_WM0_VAL)
69898c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
69908c2ecf20Sopenharmony_ci			    "Wrong MCH_SSKPD value: 0x%08x This can cause underruns.\n",
69918c2ecf20Sopenharmony_ci			    tmp);
69928c2ecf20Sopenharmony_ci}
69938c2ecf20Sopenharmony_ci
69948c2ecf20Sopenharmony_cistatic void gen6_init_clock_gating(struct drm_i915_private *dev_priv)
69958c2ecf20Sopenharmony_ci{
69968c2ecf20Sopenharmony_ci	u32 dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
69978c2ecf20Sopenharmony_ci
69988c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DSPCLK_GATE_D, dspclk_gate);
69998c2ecf20Sopenharmony_ci
70008c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DISPLAY_CHICKEN2,
70018c2ecf20Sopenharmony_ci		   I915_READ(ILK_DISPLAY_CHICKEN2) |
70028c2ecf20Sopenharmony_ci		   ILK_ELPIN_409_SELECT);
70038c2ecf20Sopenharmony_ci
70048c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_UCGCTL1,
70058c2ecf20Sopenharmony_ci		   I915_READ(GEN6_UCGCTL1) |
70068c2ecf20Sopenharmony_ci		   GEN6_BLBUNIT_CLOCK_GATE_DISABLE |
70078c2ecf20Sopenharmony_ci		   GEN6_CSUNIT_CLOCK_GATE_DISABLE);
70088c2ecf20Sopenharmony_ci
70098c2ecf20Sopenharmony_ci	/* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
70108c2ecf20Sopenharmony_ci	 * gating disable must be set.  Failure to set it results in
70118c2ecf20Sopenharmony_ci	 * flickering pixels due to Z write ordering failures after
70128c2ecf20Sopenharmony_ci	 * some amount of runtime in the Mesa "fire" demo, and Unigine
70138c2ecf20Sopenharmony_ci	 * Sanctuary and Tropics, and apparently anything else with
70148c2ecf20Sopenharmony_ci	 * alpha test or pixel discard.
70158c2ecf20Sopenharmony_ci	 *
70168c2ecf20Sopenharmony_ci	 * According to the spec, bit 11 (RCCUNIT) must also be set,
70178c2ecf20Sopenharmony_ci	 * but we didn't debug actual testcases to find it out.
70188c2ecf20Sopenharmony_ci	 *
70198c2ecf20Sopenharmony_ci	 * WaDisableRCCUnitClockGating:snb
70208c2ecf20Sopenharmony_ci	 * WaDisableRCPBUnitClockGating:snb
70218c2ecf20Sopenharmony_ci	 */
70228c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_UCGCTL2,
70238c2ecf20Sopenharmony_ci		   GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
70248c2ecf20Sopenharmony_ci		   GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
70258c2ecf20Sopenharmony_ci
70268c2ecf20Sopenharmony_ci	/*
70278c2ecf20Sopenharmony_ci	 * According to the spec the following bits should be
70288c2ecf20Sopenharmony_ci	 * set in order to enable memory self-refresh and fbc:
70298c2ecf20Sopenharmony_ci	 * The bit21 and bit22 of 0x42000
70308c2ecf20Sopenharmony_ci	 * The bit21 and bit22 of 0x42004
70318c2ecf20Sopenharmony_ci	 * The bit5 and bit7 of 0x42020
70328c2ecf20Sopenharmony_ci	 * The bit14 of 0x70180
70338c2ecf20Sopenharmony_ci	 * The bit14 of 0x71180
70348c2ecf20Sopenharmony_ci	 *
70358c2ecf20Sopenharmony_ci	 * WaFbcAsynchFlipDisableFbcQueue:snb
70368c2ecf20Sopenharmony_ci	 */
70378c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DISPLAY_CHICKEN1,
70388c2ecf20Sopenharmony_ci		   I915_READ(ILK_DISPLAY_CHICKEN1) |
70398c2ecf20Sopenharmony_ci		   ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
70408c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DISPLAY_CHICKEN2,
70418c2ecf20Sopenharmony_ci		   I915_READ(ILK_DISPLAY_CHICKEN2) |
70428c2ecf20Sopenharmony_ci		   ILK_DPARB_GATE | ILK_VSDPFD_FULL);
70438c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DSPCLK_GATE_D,
70448c2ecf20Sopenharmony_ci		   I915_READ(ILK_DSPCLK_GATE_D) |
70458c2ecf20Sopenharmony_ci		   ILK_DPARBUNIT_CLOCK_GATE_ENABLE  |
70468c2ecf20Sopenharmony_ci		   ILK_DPFDUNIT_CLOCK_GATE_ENABLE);
70478c2ecf20Sopenharmony_ci
70488c2ecf20Sopenharmony_ci	g4x_disable_trickle_feed(dev_priv);
70498c2ecf20Sopenharmony_ci
70508c2ecf20Sopenharmony_ci	cpt_init_clock_gating(dev_priv);
70518c2ecf20Sopenharmony_ci
70528c2ecf20Sopenharmony_ci	gen6_check_mch_setup(dev_priv);
70538c2ecf20Sopenharmony_ci}
70548c2ecf20Sopenharmony_ci
70558c2ecf20Sopenharmony_cistatic void lpt_init_clock_gating(struct drm_i915_private *dev_priv)
70568c2ecf20Sopenharmony_ci{
70578c2ecf20Sopenharmony_ci	/*
70588c2ecf20Sopenharmony_ci	 * TODO: this bit should only be enabled when really needed, then
70598c2ecf20Sopenharmony_ci	 * disabled when not needed anymore in order to save power.
70608c2ecf20Sopenharmony_ci	 */
70618c2ecf20Sopenharmony_ci	if (HAS_PCH_LPT_LP(dev_priv))
70628c2ecf20Sopenharmony_ci		I915_WRITE(SOUTH_DSPCLK_GATE_D,
70638c2ecf20Sopenharmony_ci			   I915_READ(SOUTH_DSPCLK_GATE_D) |
70648c2ecf20Sopenharmony_ci			   PCH_LP_PARTITION_LEVEL_DISABLE);
70658c2ecf20Sopenharmony_ci
70668c2ecf20Sopenharmony_ci	/* WADPOClockGatingDisable:hsw */
70678c2ecf20Sopenharmony_ci	I915_WRITE(TRANS_CHICKEN1(PIPE_A),
70688c2ecf20Sopenharmony_ci		   I915_READ(TRANS_CHICKEN1(PIPE_A)) |
70698c2ecf20Sopenharmony_ci		   TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
70708c2ecf20Sopenharmony_ci}
70718c2ecf20Sopenharmony_ci
70728c2ecf20Sopenharmony_cistatic void lpt_suspend_hw(struct drm_i915_private *dev_priv)
70738c2ecf20Sopenharmony_ci{
70748c2ecf20Sopenharmony_ci	if (HAS_PCH_LPT_LP(dev_priv)) {
70758c2ecf20Sopenharmony_ci		u32 val = I915_READ(SOUTH_DSPCLK_GATE_D);
70768c2ecf20Sopenharmony_ci
70778c2ecf20Sopenharmony_ci		val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
70788c2ecf20Sopenharmony_ci		I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
70798c2ecf20Sopenharmony_ci	}
70808c2ecf20Sopenharmony_ci}
70818c2ecf20Sopenharmony_ci
70828c2ecf20Sopenharmony_cistatic void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv,
70838c2ecf20Sopenharmony_ci				   int general_prio_credits,
70848c2ecf20Sopenharmony_ci				   int high_prio_credits)
70858c2ecf20Sopenharmony_ci{
70868c2ecf20Sopenharmony_ci	u32 misccpctl;
70878c2ecf20Sopenharmony_ci	u32 val;
70888c2ecf20Sopenharmony_ci
70898c2ecf20Sopenharmony_ci	/* WaTempDisableDOPClkGating:bdw */
70908c2ecf20Sopenharmony_ci	misccpctl = I915_READ(GEN7_MISCCPCTL);
70918c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
70928c2ecf20Sopenharmony_ci
70938c2ecf20Sopenharmony_ci	val = I915_READ(GEN8_L3SQCREG1);
70948c2ecf20Sopenharmony_ci	val &= ~L3_PRIO_CREDITS_MASK;
70958c2ecf20Sopenharmony_ci	val |= L3_GENERAL_PRIO_CREDITS(general_prio_credits);
70968c2ecf20Sopenharmony_ci	val |= L3_HIGH_PRIO_CREDITS(high_prio_credits);
70978c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_L3SQCREG1, val);
70988c2ecf20Sopenharmony_ci
70998c2ecf20Sopenharmony_ci	/*
71008c2ecf20Sopenharmony_ci	 * Wait at least 100 clocks before re-enabling clock gating.
71018c2ecf20Sopenharmony_ci	 * See the definition of L3SQCREG1 in BSpec.
71028c2ecf20Sopenharmony_ci	 */
71038c2ecf20Sopenharmony_ci	POSTING_READ(GEN8_L3SQCREG1);
71048c2ecf20Sopenharmony_ci	udelay(1);
71058c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
71068c2ecf20Sopenharmony_ci}
71078c2ecf20Sopenharmony_ci
71088c2ecf20Sopenharmony_cistatic void icl_init_clock_gating(struct drm_i915_private *dev_priv)
71098c2ecf20Sopenharmony_ci{
71108c2ecf20Sopenharmony_ci	/* Wa_1409120013:icl,ehl */
71118c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DPFC_CHICKEN,
71128c2ecf20Sopenharmony_ci		   ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL);
71138c2ecf20Sopenharmony_ci
71148c2ecf20Sopenharmony_ci	/* This is not an Wa. Enable to reduce Sampler power */
71158c2ecf20Sopenharmony_ci	I915_WRITE(GEN10_DFR_RATIO_EN_AND_CHICKEN,
71168c2ecf20Sopenharmony_ci		   I915_READ(GEN10_DFR_RATIO_EN_AND_CHICKEN) & ~DFR_DISABLE);
71178c2ecf20Sopenharmony_ci
71188c2ecf20Sopenharmony_ci	/*Wa_14010594013:icl, ehl */
71198c2ecf20Sopenharmony_ci	intel_uncore_rmw(&dev_priv->uncore, GEN8_CHICKEN_DCPR_1,
71208c2ecf20Sopenharmony_ci			 0, CNL_DELAY_PMRSP);
71218c2ecf20Sopenharmony_ci}
71228c2ecf20Sopenharmony_ci
71238c2ecf20Sopenharmony_cistatic void tgl_init_clock_gating(struct drm_i915_private *dev_priv)
71248c2ecf20Sopenharmony_ci{
71258c2ecf20Sopenharmony_ci	/* Wa_1409120013:tgl */
71268c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DPFC_CHICKEN,
71278c2ecf20Sopenharmony_ci		   ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL);
71288c2ecf20Sopenharmony_ci
71298c2ecf20Sopenharmony_ci	/* Wa_1409825376:tgl (pre-prod)*/
71308c2ecf20Sopenharmony_ci	if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B1))
71318c2ecf20Sopenharmony_ci		I915_WRITE(GEN9_CLKGATE_DIS_3, I915_READ(GEN9_CLKGATE_DIS_3) |
71328c2ecf20Sopenharmony_ci			   TGL_VRH_GATING_DIS);
71338c2ecf20Sopenharmony_ci
71348c2ecf20Sopenharmony_ci	/* Wa_14011059788:tgl */
71358c2ecf20Sopenharmony_ci	intel_uncore_rmw(&dev_priv->uncore, GEN10_DFR_RATIO_EN_AND_CHICKEN,
71368c2ecf20Sopenharmony_ci			 0, DFR_DISABLE);
71378c2ecf20Sopenharmony_ci}
71388c2ecf20Sopenharmony_ci
71398c2ecf20Sopenharmony_cistatic void cnp_init_clock_gating(struct drm_i915_private *dev_priv)
71408c2ecf20Sopenharmony_ci{
71418c2ecf20Sopenharmony_ci	if (!HAS_PCH_CNP(dev_priv))
71428c2ecf20Sopenharmony_ci		return;
71438c2ecf20Sopenharmony_ci
71448c2ecf20Sopenharmony_ci	/* Display WA #1181 WaSouthDisplayDisablePWMCGEGating: cnp */
71458c2ecf20Sopenharmony_ci	I915_WRITE(SOUTH_DSPCLK_GATE_D, I915_READ(SOUTH_DSPCLK_GATE_D) |
71468c2ecf20Sopenharmony_ci		   CNP_PWM_CGE_GATING_DISABLE);
71478c2ecf20Sopenharmony_ci}
71488c2ecf20Sopenharmony_ci
71498c2ecf20Sopenharmony_cistatic void cnl_init_clock_gating(struct drm_i915_private *dev_priv)
71508c2ecf20Sopenharmony_ci{
71518c2ecf20Sopenharmony_ci	u32 val;
71528c2ecf20Sopenharmony_ci	cnp_init_clock_gating(dev_priv);
71538c2ecf20Sopenharmony_ci
71548c2ecf20Sopenharmony_ci	/* This is not an Wa. Enable for better image quality */
71558c2ecf20Sopenharmony_ci	I915_WRITE(_3D_CHICKEN3,
71568c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(_3D_CHICKEN3_AA_LINE_QUALITY_FIX_ENABLE));
71578c2ecf20Sopenharmony_ci
71588c2ecf20Sopenharmony_ci	/* WaEnableChickenDCPR:cnl */
71598c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_CHICKEN_DCPR_1,
71608c2ecf20Sopenharmony_ci		   I915_READ(GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM);
71618c2ecf20Sopenharmony_ci
71628c2ecf20Sopenharmony_ci	/*
71638c2ecf20Sopenharmony_ci	 * WaFbcWakeMemOn:cnl
71648c2ecf20Sopenharmony_ci	 * Display WA #0859: cnl
71658c2ecf20Sopenharmony_ci	 */
71668c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
71678c2ecf20Sopenharmony_ci		   DISP_FBC_MEMORY_WAKE);
71688c2ecf20Sopenharmony_ci
71698c2ecf20Sopenharmony_ci	val = I915_READ(SLICE_UNIT_LEVEL_CLKGATE);
71708c2ecf20Sopenharmony_ci	/* ReadHitWriteOnlyDisable:cnl */
71718c2ecf20Sopenharmony_ci	val |= RCCUNIT_CLKGATE_DIS;
71728c2ecf20Sopenharmony_ci	I915_WRITE(SLICE_UNIT_LEVEL_CLKGATE, val);
71738c2ecf20Sopenharmony_ci
71748c2ecf20Sopenharmony_ci	/* Wa_2201832410:cnl */
71758c2ecf20Sopenharmony_ci	val = I915_READ(SUBSLICE_UNIT_LEVEL_CLKGATE);
71768c2ecf20Sopenharmony_ci	val |= GWUNIT_CLKGATE_DIS;
71778c2ecf20Sopenharmony_ci	I915_WRITE(SUBSLICE_UNIT_LEVEL_CLKGATE, val);
71788c2ecf20Sopenharmony_ci
71798c2ecf20Sopenharmony_ci	/* WaDisableVFclkgate:cnl */
71808c2ecf20Sopenharmony_ci	/* WaVFUnitClockGatingDisable:cnl */
71818c2ecf20Sopenharmony_ci	val = I915_READ(UNSLICE_UNIT_LEVEL_CLKGATE);
71828c2ecf20Sopenharmony_ci	val |= VFUNIT_CLKGATE_DIS;
71838c2ecf20Sopenharmony_ci	I915_WRITE(UNSLICE_UNIT_LEVEL_CLKGATE, val);
71848c2ecf20Sopenharmony_ci}
71858c2ecf20Sopenharmony_ci
71868c2ecf20Sopenharmony_cistatic void cfl_init_clock_gating(struct drm_i915_private *dev_priv)
71878c2ecf20Sopenharmony_ci{
71888c2ecf20Sopenharmony_ci	cnp_init_clock_gating(dev_priv);
71898c2ecf20Sopenharmony_ci	gen9_init_clock_gating(dev_priv);
71908c2ecf20Sopenharmony_ci
71918c2ecf20Sopenharmony_ci	/*
71928c2ecf20Sopenharmony_ci	 * WaFbcTurnOffFbcWatermark:cfl
71938c2ecf20Sopenharmony_ci	 * Display WA #0562: cfl
71948c2ecf20Sopenharmony_ci	 */
71958c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
71968c2ecf20Sopenharmony_ci		   DISP_FBC_WM_DIS);
71978c2ecf20Sopenharmony_ci
71988c2ecf20Sopenharmony_ci	/*
71998c2ecf20Sopenharmony_ci	 * WaFbcNukeOnHostModify:cfl
72008c2ecf20Sopenharmony_ci	 * Display WA #0873: cfl
72018c2ecf20Sopenharmony_ci	 */
72028c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) |
72038c2ecf20Sopenharmony_ci		   ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
72048c2ecf20Sopenharmony_ci}
72058c2ecf20Sopenharmony_ci
72068c2ecf20Sopenharmony_cistatic void kbl_init_clock_gating(struct drm_i915_private *dev_priv)
72078c2ecf20Sopenharmony_ci{
72088c2ecf20Sopenharmony_ci	gen9_init_clock_gating(dev_priv);
72098c2ecf20Sopenharmony_ci
72108c2ecf20Sopenharmony_ci	/* WaDisableSDEUnitClockGating:kbl */
72118c2ecf20Sopenharmony_ci	if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0))
72128c2ecf20Sopenharmony_ci		I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
72138c2ecf20Sopenharmony_ci			   GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
72148c2ecf20Sopenharmony_ci
72158c2ecf20Sopenharmony_ci	/* WaDisableGamClockGating:kbl */
72168c2ecf20Sopenharmony_ci	if (IS_KBL_GT_REVID(dev_priv, 0, KBL_REVID_B0))
72178c2ecf20Sopenharmony_ci		I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
72188c2ecf20Sopenharmony_ci			   GEN6_GAMUNIT_CLOCK_GATE_DISABLE);
72198c2ecf20Sopenharmony_ci
72208c2ecf20Sopenharmony_ci	/*
72218c2ecf20Sopenharmony_ci	 * WaFbcTurnOffFbcWatermark:kbl
72228c2ecf20Sopenharmony_ci	 * Display WA #0562: kbl
72238c2ecf20Sopenharmony_ci	 */
72248c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
72258c2ecf20Sopenharmony_ci		   DISP_FBC_WM_DIS);
72268c2ecf20Sopenharmony_ci
72278c2ecf20Sopenharmony_ci	/*
72288c2ecf20Sopenharmony_ci	 * WaFbcNukeOnHostModify:kbl
72298c2ecf20Sopenharmony_ci	 * Display WA #0873: kbl
72308c2ecf20Sopenharmony_ci	 */
72318c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) |
72328c2ecf20Sopenharmony_ci		   ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
72338c2ecf20Sopenharmony_ci}
72348c2ecf20Sopenharmony_ci
72358c2ecf20Sopenharmony_cistatic void skl_init_clock_gating(struct drm_i915_private *dev_priv)
72368c2ecf20Sopenharmony_ci{
72378c2ecf20Sopenharmony_ci	gen9_init_clock_gating(dev_priv);
72388c2ecf20Sopenharmony_ci
72398c2ecf20Sopenharmony_ci	/* WaDisableDopClockGating:skl */
72408c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_MISCCPCTL, I915_READ(GEN7_MISCCPCTL) &
72418c2ecf20Sopenharmony_ci		   ~GEN7_DOP_CLOCK_GATE_ENABLE);
72428c2ecf20Sopenharmony_ci
72438c2ecf20Sopenharmony_ci	/* WAC6entrylatency:skl */
72448c2ecf20Sopenharmony_ci	I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) |
72458c2ecf20Sopenharmony_ci		   FBC_LLC_FULLY_OPEN);
72468c2ecf20Sopenharmony_ci
72478c2ecf20Sopenharmony_ci	/*
72488c2ecf20Sopenharmony_ci	 * WaFbcTurnOffFbcWatermark:skl
72498c2ecf20Sopenharmony_ci	 * Display WA #0562: skl
72508c2ecf20Sopenharmony_ci	 */
72518c2ecf20Sopenharmony_ci	I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
72528c2ecf20Sopenharmony_ci		   DISP_FBC_WM_DIS);
72538c2ecf20Sopenharmony_ci
72548c2ecf20Sopenharmony_ci	/*
72558c2ecf20Sopenharmony_ci	 * WaFbcNukeOnHostModify:skl
72568c2ecf20Sopenharmony_ci	 * Display WA #0873: skl
72578c2ecf20Sopenharmony_ci	 */
72588c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) |
72598c2ecf20Sopenharmony_ci		   ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
72608c2ecf20Sopenharmony_ci
72618c2ecf20Sopenharmony_ci	/*
72628c2ecf20Sopenharmony_ci	 * WaFbcHighMemBwCorruptionAvoidance:skl
72638c2ecf20Sopenharmony_ci	 * Display WA #0883: skl
72648c2ecf20Sopenharmony_ci	 */
72658c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) |
72668c2ecf20Sopenharmony_ci		   ILK_DPFC_DISABLE_DUMMY0);
72678c2ecf20Sopenharmony_ci}
72688c2ecf20Sopenharmony_ci
72698c2ecf20Sopenharmony_cistatic void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
72708c2ecf20Sopenharmony_ci{
72718c2ecf20Sopenharmony_ci	enum pipe pipe;
72728c2ecf20Sopenharmony_ci
72738c2ecf20Sopenharmony_ci	/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
72748c2ecf20Sopenharmony_ci	I915_WRITE(CHICKEN_PIPESL_1(PIPE_A),
72758c2ecf20Sopenharmony_ci		   I915_READ(CHICKEN_PIPESL_1(PIPE_A)) |
72768c2ecf20Sopenharmony_ci		   HSW_FBCQ_DIS);
72778c2ecf20Sopenharmony_ci
72788c2ecf20Sopenharmony_ci	/* WaSwitchSolVfFArbitrationPriority:bdw */
72798c2ecf20Sopenharmony_ci	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
72808c2ecf20Sopenharmony_ci
72818c2ecf20Sopenharmony_ci	/* WaPsrDPAMaskVBlankInSRD:bdw */
72828c2ecf20Sopenharmony_ci	I915_WRITE(CHICKEN_PAR1_1,
72838c2ecf20Sopenharmony_ci		   I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
72848c2ecf20Sopenharmony_ci
72858c2ecf20Sopenharmony_ci	/* WaPsrDPRSUnmaskVBlankInSRD:bdw */
72868c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
72878c2ecf20Sopenharmony_ci		I915_WRITE(CHICKEN_PIPESL_1(pipe),
72888c2ecf20Sopenharmony_ci			   I915_READ(CHICKEN_PIPESL_1(pipe)) |
72898c2ecf20Sopenharmony_ci			   BDW_DPRS_MASK_VBLANK_SRD);
72908c2ecf20Sopenharmony_ci	}
72918c2ecf20Sopenharmony_ci
72928c2ecf20Sopenharmony_ci	/* WaVSRefCountFullforceMissDisable:bdw */
72938c2ecf20Sopenharmony_ci	/* WaDSRefCountFullforceMissDisable:bdw */
72948c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_FF_THREAD_MODE,
72958c2ecf20Sopenharmony_ci		   I915_READ(GEN7_FF_THREAD_MODE) &
72968c2ecf20Sopenharmony_ci		   ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
72978c2ecf20Sopenharmony_ci
72988c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL,
72998c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
73008c2ecf20Sopenharmony_ci
73018c2ecf20Sopenharmony_ci	/* WaDisableSDEUnitClockGating:bdw */
73028c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
73038c2ecf20Sopenharmony_ci		   GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
73048c2ecf20Sopenharmony_ci
73058c2ecf20Sopenharmony_ci	/* WaProgramL3SqcReg1Default:bdw */
73068c2ecf20Sopenharmony_ci	gen8_set_l3sqc_credits(dev_priv, 30, 2);
73078c2ecf20Sopenharmony_ci
73088c2ecf20Sopenharmony_ci	/* WaKVMNotificationOnConfigChange:bdw */
73098c2ecf20Sopenharmony_ci	I915_WRITE(CHICKEN_PAR2_1, I915_READ(CHICKEN_PAR2_1)
73108c2ecf20Sopenharmony_ci		   | KVM_CONFIG_CHANGE_NOTIFICATION_SELECT);
73118c2ecf20Sopenharmony_ci
73128c2ecf20Sopenharmony_ci	lpt_init_clock_gating(dev_priv);
73138c2ecf20Sopenharmony_ci
73148c2ecf20Sopenharmony_ci	/* WaDisableDopClockGating:bdw
73158c2ecf20Sopenharmony_ci	 *
73168c2ecf20Sopenharmony_ci	 * Also see the CHICKEN2 write in bdw_init_workarounds() to disable DOP
73178c2ecf20Sopenharmony_ci	 * clock gating.
73188c2ecf20Sopenharmony_ci	 */
73198c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_UCGCTL1,
73208c2ecf20Sopenharmony_ci		   I915_READ(GEN6_UCGCTL1) | GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE);
73218c2ecf20Sopenharmony_ci}
73228c2ecf20Sopenharmony_ci
73238c2ecf20Sopenharmony_cistatic void hsw_init_clock_gating(struct drm_i915_private *dev_priv)
73248c2ecf20Sopenharmony_ci{
73258c2ecf20Sopenharmony_ci	/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
73268c2ecf20Sopenharmony_ci	I915_WRITE(CHICKEN_PIPESL_1(PIPE_A),
73278c2ecf20Sopenharmony_ci		   I915_READ(CHICKEN_PIPESL_1(PIPE_A)) |
73288c2ecf20Sopenharmony_ci		   HSW_FBCQ_DIS);
73298c2ecf20Sopenharmony_ci
73308c2ecf20Sopenharmony_ci	/* This is required by WaCatErrorRejectionIssue:hsw */
73318c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
73328c2ecf20Sopenharmony_ci		   I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
73338c2ecf20Sopenharmony_ci		   GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
73348c2ecf20Sopenharmony_ci
73358c2ecf20Sopenharmony_ci	/* WaSwitchSolVfFArbitrationPriority:hsw */
73368c2ecf20Sopenharmony_ci	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
73378c2ecf20Sopenharmony_ci
73388c2ecf20Sopenharmony_ci	lpt_init_clock_gating(dev_priv);
73398c2ecf20Sopenharmony_ci}
73408c2ecf20Sopenharmony_ci
73418c2ecf20Sopenharmony_cistatic void ivb_init_clock_gating(struct drm_i915_private *dev_priv)
73428c2ecf20Sopenharmony_ci{
73438c2ecf20Sopenharmony_ci	u32 snpcr;
73448c2ecf20Sopenharmony_ci
73458c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE);
73468c2ecf20Sopenharmony_ci
73478c2ecf20Sopenharmony_ci	/* WaFbcAsynchFlipDisableFbcQueue:ivb */
73488c2ecf20Sopenharmony_ci	I915_WRITE(ILK_DISPLAY_CHICKEN1,
73498c2ecf20Sopenharmony_ci		   I915_READ(ILK_DISPLAY_CHICKEN1) |
73508c2ecf20Sopenharmony_ci		   ILK_FBCQ_DIS);
73518c2ecf20Sopenharmony_ci
73528c2ecf20Sopenharmony_ci	/* WaDisableBackToBackFlipFix:ivb */
73538c2ecf20Sopenharmony_ci	I915_WRITE(IVB_CHICKEN3,
73548c2ecf20Sopenharmony_ci		   CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
73558c2ecf20Sopenharmony_ci		   CHICKEN3_DGMG_DONE_FIX_DISABLE);
73568c2ecf20Sopenharmony_ci
73578c2ecf20Sopenharmony_ci	if (IS_IVB_GT1(dev_priv))
73588c2ecf20Sopenharmony_ci		I915_WRITE(GEN7_ROW_CHICKEN2,
73598c2ecf20Sopenharmony_ci			   _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
73608c2ecf20Sopenharmony_ci	else {
73618c2ecf20Sopenharmony_ci		/* must write both registers */
73628c2ecf20Sopenharmony_ci		I915_WRITE(GEN7_ROW_CHICKEN2,
73638c2ecf20Sopenharmony_ci			   _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
73648c2ecf20Sopenharmony_ci		I915_WRITE(GEN7_ROW_CHICKEN2_GT2,
73658c2ecf20Sopenharmony_ci			   _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
73668c2ecf20Sopenharmony_ci	}
73678c2ecf20Sopenharmony_ci
73688c2ecf20Sopenharmony_ci	/*
73698c2ecf20Sopenharmony_ci	 * According to the spec, bit 13 (RCZUNIT) must be set on IVB.
73708c2ecf20Sopenharmony_ci	 * This implements the WaDisableRCZUnitClockGating:ivb workaround.
73718c2ecf20Sopenharmony_ci	 */
73728c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_UCGCTL2,
73738c2ecf20Sopenharmony_ci		   GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
73748c2ecf20Sopenharmony_ci
73758c2ecf20Sopenharmony_ci	/* This is required by WaCatErrorRejectionIssue:ivb */
73768c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
73778c2ecf20Sopenharmony_ci			I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
73788c2ecf20Sopenharmony_ci			GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
73798c2ecf20Sopenharmony_ci
73808c2ecf20Sopenharmony_ci	g4x_disable_trickle_feed(dev_priv);
73818c2ecf20Sopenharmony_ci
73828c2ecf20Sopenharmony_ci	snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
73838c2ecf20Sopenharmony_ci	snpcr &= ~GEN6_MBC_SNPCR_MASK;
73848c2ecf20Sopenharmony_ci	snpcr |= GEN6_MBC_SNPCR_MED;
73858c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
73868c2ecf20Sopenharmony_ci
73878c2ecf20Sopenharmony_ci	if (!HAS_PCH_NOP(dev_priv))
73888c2ecf20Sopenharmony_ci		cpt_init_clock_gating(dev_priv);
73898c2ecf20Sopenharmony_ci
73908c2ecf20Sopenharmony_ci	gen6_check_mch_setup(dev_priv);
73918c2ecf20Sopenharmony_ci}
73928c2ecf20Sopenharmony_ci
73938c2ecf20Sopenharmony_cistatic void vlv_init_clock_gating(struct drm_i915_private *dev_priv)
73948c2ecf20Sopenharmony_ci{
73958c2ecf20Sopenharmony_ci	/* WaDisableBackToBackFlipFix:vlv */
73968c2ecf20Sopenharmony_ci	I915_WRITE(IVB_CHICKEN3,
73978c2ecf20Sopenharmony_ci		   CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
73988c2ecf20Sopenharmony_ci		   CHICKEN3_DGMG_DONE_FIX_DISABLE);
73998c2ecf20Sopenharmony_ci
74008c2ecf20Sopenharmony_ci	/* WaDisableDopClockGating:vlv */
74018c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_ROW_CHICKEN2,
74028c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
74038c2ecf20Sopenharmony_ci
74048c2ecf20Sopenharmony_ci	/* This is required by WaCatErrorRejectionIssue:vlv */
74058c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
74068c2ecf20Sopenharmony_ci		   I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
74078c2ecf20Sopenharmony_ci		   GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
74088c2ecf20Sopenharmony_ci
74098c2ecf20Sopenharmony_ci	/*
74108c2ecf20Sopenharmony_ci	 * According to the spec, bit 13 (RCZUNIT) must be set on IVB.
74118c2ecf20Sopenharmony_ci	 * This implements the WaDisableRCZUnitClockGating:vlv workaround.
74128c2ecf20Sopenharmony_ci	 */
74138c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_UCGCTL2,
74148c2ecf20Sopenharmony_ci		   GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
74158c2ecf20Sopenharmony_ci
74168c2ecf20Sopenharmony_ci	/* WaDisableL3Bank2xClockGate:vlv
74178c2ecf20Sopenharmony_ci	 * Disabling L3 clock gating- MMIO 940c[25] = 1
74188c2ecf20Sopenharmony_ci	 * Set bit 25, to disable L3_BANK_2x_CLK_GATING */
74198c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_UCGCTL4,
74208c2ecf20Sopenharmony_ci		   I915_READ(GEN7_UCGCTL4) | GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
74218c2ecf20Sopenharmony_ci
74228c2ecf20Sopenharmony_ci	/*
74238c2ecf20Sopenharmony_ci	 * WaDisableVLVClockGating_VBIIssue:vlv
74248c2ecf20Sopenharmony_ci	 * Disable clock gating on th GCFG unit to prevent a delay
74258c2ecf20Sopenharmony_ci	 * in the reporting of vblank events.
74268c2ecf20Sopenharmony_ci	 */
74278c2ecf20Sopenharmony_ci	I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS);
74288c2ecf20Sopenharmony_ci}
74298c2ecf20Sopenharmony_ci
74308c2ecf20Sopenharmony_cistatic void chv_init_clock_gating(struct drm_i915_private *dev_priv)
74318c2ecf20Sopenharmony_ci{
74328c2ecf20Sopenharmony_ci	/* WaVSRefCountFullforceMissDisable:chv */
74338c2ecf20Sopenharmony_ci	/* WaDSRefCountFullforceMissDisable:chv */
74348c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_FF_THREAD_MODE,
74358c2ecf20Sopenharmony_ci		   I915_READ(GEN7_FF_THREAD_MODE) &
74368c2ecf20Sopenharmony_ci		   ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
74378c2ecf20Sopenharmony_ci
74388c2ecf20Sopenharmony_ci	/* WaDisableSemaphoreAndSyncFlipWait:chv */
74398c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL,
74408c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
74418c2ecf20Sopenharmony_ci
74428c2ecf20Sopenharmony_ci	/* WaDisableCSUnitClockGating:chv */
74438c2ecf20Sopenharmony_ci	I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
74448c2ecf20Sopenharmony_ci		   GEN6_CSUNIT_CLOCK_GATE_DISABLE);
74458c2ecf20Sopenharmony_ci
74468c2ecf20Sopenharmony_ci	/* WaDisableSDEUnitClockGating:chv */
74478c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
74488c2ecf20Sopenharmony_ci		   GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
74498c2ecf20Sopenharmony_ci
74508c2ecf20Sopenharmony_ci	/*
74518c2ecf20Sopenharmony_ci	 * WaProgramL3SqcReg1Default:chv
74528c2ecf20Sopenharmony_ci	 * See gfxspecs/Related Documents/Performance Guide/
74538c2ecf20Sopenharmony_ci	 * LSQC Setting Recommendations.
74548c2ecf20Sopenharmony_ci	 */
74558c2ecf20Sopenharmony_ci	gen8_set_l3sqc_credits(dev_priv, 38, 2);
74568c2ecf20Sopenharmony_ci}
74578c2ecf20Sopenharmony_ci
74588c2ecf20Sopenharmony_cistatic void g4x_init_clock_gating(struct drm_i915_private *dev_priv)
74598c2ecf20Sopenharmony_ci{
74608c2ecf20Sopenharmony_ci	u32 dspclk_gate;
74618c2ecf20Sopenharmony_ci
74628c2ecf20Sopenharmony_ci	I915_WRITE(RENCLK_GATE_D1, 0);
74638c2ecf20Sopenharmony_ci	I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
74648c2ecf20Sopenharmony_ci		   GS_UNIT_CLOCK_GATE_DISABLE |
74658c2ecf20Sopenharmony_ci		   CL_UNIT_CLOCK_GATE_DISABLE);
74668c2ecf20Sopenharmony_ci	I915_WRITE(RAMCLK_GATE_D, 0);
74678c2ecf20Sopenharmony_ci	dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
74688c2ecf20Sopenharmony_ci		OVRUNIT_CLOCK_GATE_DISABLE |
74698c2ecf20Sopenharmony_ci		OVCUNIT_CLOCK_GATE_DISABLE;
74708c2ecf20Sopenharmony_ci	if (IS_GM45(dev_priv))
74718c2ecf20Sopenharmony_ci		dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
74728c2ecf20Sopenharmony_ci	I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
74738c2ecf20Sopenharmony_ci
74748c2ecf20Sopenharmony_ci	g4x_disable_trickle_feed(dev_priv);
74758c2ecf20Sopenharmony_ci}
74768c2ecf20Sopenharmony_ci
74778c2ecf20Sopenharmony_cistatic void i965gm_init_clock_gating(struct drm_i915_private *dev_priv)
74788c2ecf20Sopenharmony_ci{
74798c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
74808c2ecf20Sopenharmony_ci
74818c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
74828c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, RENCLK_GATE_D2, 0);
74838c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, DSPCLK_GATE_D, 0);
74848c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, RAMCLK_GATE_D, 0);
74858c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, DEUC, 0);
74868c2ecf20Sopenharmony_ci	intel_uncore_write(uncore,
74878c2ecf20Sopenharmony_ci			   MI_ARB_STATE,
74888c2ecf20Sopenharmony_ci			   _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
74898c2ecf20Sopenharmony_ci}
74908c2ecf20Sopenharmony_ci
74918c2ecf20Sopenharmony_cistatic void i965g_init_clock_gating(struct drm_i915_private *dev_priv)
74928c2ecf20Sopenharmony_ci{
74938c2ecf20Sopenharmony_ci	I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
74948c2ecf20Sopenharmony_ci		   I965_RCC_CLOCK_GATE_DISABLE |
74958c2ecf20Sopenharmony_ci		   I965_RCPB_CLOCK_GATE_DISABLE |
74968c2ecf20Sopenharmony_ci		   I965_ISC_CLOCK_GATE_DISABLE |
74978c2ecf20Sopenharmony_ci		   I965_FBC_CLOCK_GATE_DISABLE);
74988c2ecf20Sopenharmony_ci	I915_WRITE(RENCLK_GATE_D2, 0);
74998c2ecf20Sopenharmony_ci	I915_WRITE(MI_ARB_STATE,
75008c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
75018c2ecf20Sopenharmony_ci}
75028c2ecf20Sopenharmony_ci
75038c2ecf20Sopenharmony_cistatic void gen3_init_clock_gating(struct drm_i915_private *dev_priv)
75048c2ecf20Sopenharmony_ci{
75058c2ecf20Sopenharmony_ci	u32 dstate = I915_READ(D_STATE);
75068c2ecf20Sopenharmony_ci
75078c2ecf20Sopenharmony_ci	dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
75088c2ecf20Sopenharmony_ci		DSTATE_DOT_CLOCK_GATING;
75098c2ecf20Sopenharmony_ci	I915_WRITE(D_STATE, dstate);
75108c2ecf20Sopenharmony_ci
75118c2ecf20Sopenharmony_ci	if (IS_PINEVIEW(dev_priv))
75128c2ecf20Sopenharmony_ci		I915_WRITE(ECOSKPD, _MASKED_BIT_ENABLE(ECO_GATING_CX_ONLY));
75138c2ecf20Sopenharmony_ci
75148c2ecf20Sopenharmony_ci	/* IIR "flip pending" means done if this bit is set */
75158c2ecf20Sopenharmony_ci	I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE));
75168c2ecf20Sopenharmony_ci
75178c2ecf20Sopenharmony_ci	/* interrupts should cause a wake up from C3 */
75188c2ecf20Sopenharmony_ci	I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_INT_EN));
75198c2ecf20Sopenharmony_ci
75208c2ecf20Sopenharmony_ci	/* On GEN3 we really need to make sure the ARB C3 LP bit is set */
75218c2ecf20Sopenharmony_ci	I915_WRITE(MI_ARB_STATE, _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
75228c2ecf20Sopenharmony_ci
75238c2ecf20Sopenharmony_ci	I915_WRITE(MI_ARB_STATE,
75248c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
75258c2ecf20Sopenharmony_ci}
75268c2ecf20Sopenharmony_ci
75278c2ecf20Sopenharmony_cistatic void i85x_init_clock_gating(struct drm_i915_private *dev_priv)
75288c2ecf20Sopenharmony_ci{
75298c2ecf20Sopenharmony_ci	I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
75308c2ecf20Sopenharmony_ci
75318c2ecf20Sopenharmony_ci	/* interrupts should cause a wake up from C3 */
75328c2ecf20Sopenharmony_ci	I915_WRITE(MI_STATE, _MASKED_BIT_ENABLE(MI_AGPBUSY_INT_EN) |
75338c2ecf20Sopenharmony_ci		   _MASKED_BIT_DISABLE(MI_AGPBUSY_830_MODE));
75348c2ecf20Sopenharmony_ci
75358c2ecf20Sopenharmony_ci	I915_WRITE(MEM_MODE,
75368c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(MEM_DISPLAY_TRICKLE_FEED_DISABLE));
75378c2ecf20Sopenharmony_ci
75388c2ecf20Sopenharmony_ci	/*
75398c2ecf20Sopenharmony_ci	 * Have FBC ignore 3D activity since we use software
75408c2ecf20Sopenharmony_ci	 * render tracking, and otherwise a pure 3D workload
75418c2ecf20Sopenharmony_ci	 * (even if it just renders a single frame and then does
75428c2ecf20Sopenharmony_ci	 * abosultely nothing) would not allow FBC to recompress
75438c2ecf20Sopenharmony_ci	 * until a 2D blit occurs.
75448c2ecf20Sopenharmony_ci	 */
75458c2ecf20Sopenharmony_ci	I915_WRITE(SCPD0,
75468c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(SCPD_FBC_IGNORE_3D));
75478c2ecf20Sopenharmony_ci}
75488c2ecf20Sopenharmony_ci
75498c2ecf20Sopenharmony_cistatic void i830_init_clock_gating(struct drm_i915_private *dev_priv)
75508c2ecf20Sopenharmony_ci{
75518c2ecf20Sopenharmony_ci	I915_WRITE(MEM_MODE,
75528c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(MEM_DISPLAY_A_TRICKLE_FEED_DISABLE) |
75538c2ecf20Sopenharmony_ci		   _MASKED_BIT_ENABLE(MEM_DISPLAY_B_TRICKLE_FEED_DISABLE));
75548c2ecf20Sopenharmony_ci}
75558c2ecf20Sopenharmony_ci
75568c2ecf20Sopenharmony_civoid intel_init_clock_gating(struct drm_i915_private *dev_priv)
75578c2ecf20Sopenharmony_ci{
75588c2ecf20Sopenharmony_ci	dev_priv->display.init_clock_gating(dev_priv);
75598c2ecf20Sopenharmony_ci}
75608c2ecf20Sopenharmony_ci
75618c2ecf20Sopenharmony_civoid intel_suspend_hw(struct drm_i915_private *dev_priv)
75628c2ecf20Sopenharmony_ci{
75638c2ecf20Sopenharmony_ci	if (HAS_PCH_LPT(dev_priv))
75648c2ecf20Sopenharmony_ci		lpt_suspend_hw(dev_priv);
75658c2ecf20Sopenharmony_ci}
75668c2ecf20Sopenharmony_ci
75678c2ecf20Sopenharmony_cistatic void nop_init_clock_gating(struct drm_i915_private *dev_priv)
75688c2ecf20Sopenharmony_ci{
75698c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
75708c2ecf20Sopenharmony_ci		    "No clock gating settings or workarounds applied.\n");
75718c2ecf20Sopenharmony_ci}
75728c2ecf20Sopenharmony_ci
75738c2ecf20Sopenharmony_ci/**
75748c2ecf20Sopenharmony_ci * intel_init_clock_gating_hooks - setup the clock gating hooks
75758c2ecf20Sopenharmony_ci * @dev_priv: device private
75768c2ecf20Sopenharmony_ci *
75778c2ecf20Sopenharmony_ci * Setup the hooks that configure which clocks of a given platform can be
75788c2ecf20Sopenharmony_ci * gated and also apply various GT and display specific workarounds for these
75798c2ecf20Sopenharmony_ci * platforms. Note that some GT specific workarounds are applied separately
75808c2ecf20Sopenharmony_ci * when GPU contexts or batchbuffers start their execution.
75818c2ecf20Sopenharmony_ci */
75828c2ecf20Sopenharmony_civoid intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv)
75838c2ecf20Sopenharmony_ci{
75848c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 12))
75858c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = tgl_init_clock_gating;
75868c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 11))
75878c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = icl_init_clock_gating;
75888c2ecf20Sopenharmony_ci	else if (IS_CANNONLAKE(dev_priv))
75898c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = cnl_init_clock_gating;
75908c2ecf20Sopenharmony_ci	else if (IS_COFFEELAKE(dev_priv) || IS_COMETLAKE(dev_priv))
75918c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = cfl_init_clock_gating;
75928c2ecf20Sopenharmony_ci	else if (IS_SKYLAKE(dev_priv))
75938c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = skl_init_clock_gating;
75948c2ecf20Sopenharmony_ci	else if (IS_KABYLAKE(dev_priv))
75958c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = kbl_init_clock_gating;
75968c2ecf20Sopenharmony_ci	else if (IS_BROXTON(dev_priv))
75978c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = bxt_init_clock_gating;
75988c2ecf20Sopenharmony_ci	else if (IS_GEMINILAKE(dev_priv))
75998c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = glk_init_clock_gating;
76008c2ecf20Sopenharmony_ci	else if (IS_BROADWELL(dev_priv))
76018c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = bdw_init_clock_gating;
76028c2ecf20Sopenharmony_ci	else if (IS_CHERRYVIEW(dev_priv))
76038c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = chv_init_clock_gating;
76048c2ecf20Sopenharmony_ci	else if (IS_HASWELL(dev_priv))
76058c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = hsw_init_clock_gating;
76068c2ecf20Sopenharmony_ci	else if (IS_IVYBRIDGE(dev_priv))
76078c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = ivb_init_clock_gating;
76088c2ecf20Sopenharmony_ci	else if (IS_VALLEYVIEW(dev_priv))
76098c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = vlv_init_clock_gating;
76108c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 6))
76118c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = gen6_init_clock_gating;
76128c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 5))
76138c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = ilk_init_clock_gating;
76148c2ecf20Sopenharmony_ci	else if (IS_G4X(dev_priv))
76158c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = g4x_init_clock_gating;
76168c2ecf20Sopenharmony_ci	else if (IS_I965GM(dev_priv))
76178c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = i965gm_init_clock_gating;
76188c2ecf20Sopenharmony_ci	else if (IS_I965G(dev_priv))
76198c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = i965g_init_clock_gating;
76208c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 3))
76218c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = gen3_init_clock_gating;
76228c2ecf20Sopenharmony_ci	else if (IS_I85X(dev_priv) || IS_I865G(dev_priv))
76238c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = i85x_init_clock_gating;
76248c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 2))
76258c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = i830_init_clock_gating;
76268c2ecf20Sopenharmony_ci	else {
76278c2ecf20Sopenharmony_ci		MISSING_CASE(INTEL_DEVID(dev_priv));
76288c2ecf20Sopenharmony_ci		dev_priv->display.init_clock_gating = nop_init_clock_gating;
76298c2ecf20Sopenharmony_ci	}
76308c2ecf20Sopenharmony_ci}
76318c2ecf20Sopenharmony_ci
76328c2ecf20Sopenharmony_ci/* Set up chip specific power management-related functions */
76338c2ecf20Sopenharmony_civoid intel_init_pm(struct drm_i915_private *dev_priv)
76348c2ecf20Sopenharmony_ci{
76358c2ecf20Sopenharmony_ci	/* For cxsr */
76368c2ecf20Sopenharmony_ci	if (IS_PINEVIEW(dev_priv))
76378c2ecf20Sopenharmony_ci		pnv_get_mem_freq(dev_priv);
76388c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 5))
76398c2ecf20Sopenharmony_ci		ilk_get_mem_freq(dev_priv);
76408c2ecf20Sopenharmony_ci
76418c2ecf20Sopenharmony_ci	if (intel_has_sagv(dev_priv))
76428c2ecf20Sopenharmony_ci		skl_setup_sagv_block_time(dev_priv);
76438c2ecf20Sopenharmony_ci
76448c2ecf20Sopenharmony_ci	/* For FIFO watermark updates */
76458c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 9) {
76468c2ecf20Sopenharmony_ci		skl_setup_wm_latency(dev_priv);
76478c2ecf20Sopenharmony_ci		dev_priv->display.compute_global_watermarks = skl_compute_wm;
76488c2ecf20Sopenharmony_ci	} else if (HAS_PCH_SPLIT(dev_priv)) {
76498c2ecf20Sopenharmony_ci		ilk_setup_wm_latency(dev_priv);
76508c2ecf20Sopenharmony_ci
76518c2ecf20Sopenharmony_ci		if ((IS_GEN(dev_priv, 5) && dev_priv->wm.pri_latency[1] &&
76528c2ecf20Sopenharmony_ci		     dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
76538c2ecf20Sopenharmony_ci		    (!IS_GEN(dev_priv, 5) && dev_priv->wm.pri_latency[0] &&
76548c2ecf20Sopenharmony_ci		     dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
76558c2ecf20Sopenharmony_ci			dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
76568c2ecf20Sopenharmony_ci			dev_priv->display.compute_intermediate_wm =
76578c2ecf20Sopenharmony_ci				ilk_compute_intermediate_wm;
76588c2ecf20Sopenharmony_ci			dev_priv->display.initial_watermarks =
76598c2ecf20Sopenharmony_ci				ilk_initial_watermarks;
76608c2ecf20Sopenharmony_ci			dev_priv->display.optimize_watermarks =
76618c2ecf20Sopenharmony_ci				ilk_optimize_watermarks;
76628c2ecf20Sopenharmony_ci		} else {
76638c2ecf20Sopenharmony_ci			drm_dbg_kms(&dev_priv->drm,
76648c2ecf20Sopenharmony_ci				    "Failed to read display plane latency. "
76658c2ecf20Sopenharmony_ci				    "Disable CxSR\n");
76668c2ecf20Sopenharmony_ci		}
76678c2ecf20Sopenharmony_ci	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
76688c2ecf20Sopenharmony_ci		vlv_setup_wm_latency(dev_priv);
76698c2ecf20Sopenharmony_ci		dev_priv->display.compute_pipe_wm = vlv_compute_pipe_wm;
76708c2ecf20Sopenharmony_ci		dev_priv->display.compute_intermediate_wm = vlv_compute_intermediate_wm;
76718c2ecf20Sopenharmony_ci		dev_priv->display.initial_watermarks = vlv_initial_watermarks;
76728c2ecf20Sopenharmony_ci		dev_priv->display.optimize_watermarks = vlv_optimize_watermarks;
76738c2ecf20Sopenharmony_ci		dev_priv->display.atomic_update_watermarks = vlv_atomic_update_fifo;
76748c2ecf20Sopenharmony_ci	} else if (IS_G4X(dev_priv)) {
76758c2ecf20Sopenharmony_ci		g4x_setup_wm_latency(dev_priv);
76768c2ecf20Sopenharmony_ci		dev_priv->display.compute_pipe_wm = g4x_compute_pipe_wm;
76778c2ecf20Sopenharmony_ci		dev_priv->display.compute_intermediate_wm = g4x_compute_intermediate_wm;
76788c2ecf20Sopenharmony_ci		dev_priv->display.initial_watermarks = g4x_initial_watermarks;
76798c2ecf20Sopenharmony_ci		dev_priv->display.optimize_watermarks = g4x_optimize_watermarks;
76808c2ecf20Sopenharmony_ci	} else if (IS_PINEVIEW(dev_priv)) {
76818c2ecf20Sopenharmony_ci		if (!intel_get_cxsr_latency(!IS_MOBILE(dev_priv),
76828c2ecf20Sopenharmony_ci					    dev_priv->is_ddr3,
76838c2ecf20Sopenharmony_ci					    dev_priv->fsb_freq,
76848c2ecf20Sopenharmony_ci					    dev_priv->mem_freq)) {
76858c2ecf20Sopenharmony_ci			drm_info(&dev_priv->drm,
76868c2ecf20Sopenharmony_ci				 "failed to find known CxSR latency "
76878c2ecf20Sopenharmony_ci				 "(found ddr%s fsb freq %d, mem freq %d), "
76888c2ecf20Sopenharmony_ci				 "disabling CxSR\n",
76898c2ecf20Sopenharmony_ci				 (dev_priv->is_ddr3 == 1) ? "3" : "2",
76908c2ecf20Sopenharmony_ci				 dev_priv->fsb_freq, dev_priv->mem_freq);
76918c2ecf20Sopenharmony_ci			/* Disable CxSR and never update its watermark again */
76928c2ecf20Sopenharmony_ci			intel_set_memory_cxsr(dev_priv, false);
76938c2ecf20Sopenharmony_ci			dev_priv->display.update_wm = NULL;
76948c2ecf20Sopenharmony_ci		} else
76958c2ecf20Sopenharmony_ci			dev_priv->display.update_wm = pnv_update_wm;
76968c2ecf20Sopenharmony_ci	} else if (IS_GEN(dev_priv, 4)) {
76978c2ecf20Sopenharmony_ci		dev_priv->display.update_wm = i965_update_wm;
76988c2ecf20Sopenharmony_ci	} else if (IS_GEN(dev_priv, 3)) {
76998c2ecf20Sopenharmony_ci		dev_priv->display.update_wm = i9xx_update_wm;
77008c2ecf20Sopenharmony_ci		dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
77018c2ecf20Sopenharmony_ci	} else if (IS_GEN(dev_priv, 2)) {
77028c2ecf20Sopenharmony_ci		if (INTEL_NUM_PIPES(dev_priv) == 1) {
77038c2ecf20Sopenharmony_ci			dev_priv->display.update_wm = i845_update_wm;
77048c2ecf20Sopenharmony_ci			dev_priv->display.get_fifo_size = i845_get_fifo_size;
77058c2ecf20Sopenharmony_ci		} else {
77068c2ecf20Sopenharmony_ci			dev_priv->display.update_wm = i9xx_update_wm;
77078c2ecf20Sopenharmony_ci			dev_priv->display.get_fifo_size = i830_get_fifo_size;
77088c2ecf20Sopenharmony_ci		}
77098c2ecf20Sopenharmony_ci	} else {
77108c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm,
77118c2ecf20Sopenharmony_ci			"unexpected fall-through in %s\n", __func__);
77128c2ecf20Sopenharmony_ci	}
77138c2ecf20Sopenharmony_ci}
77148c2ecf20Sopenharmony_ci
77158c2ecf20Sopenharmony_civoid intel_pm_setup(struct drm_i915_private *dev_priv)
77168c2ecf20Sopenharmony_ci{
77178c2ecf20Sopenharmony_ci	dev_priv->runtime_pm.suspended = false;
77188c2ecf20Sopenharmony_ci	atomic_set(&dev_priv->runtime_pm.wakeref_count, 0);
77198c2ecf20Sopenharmony_ci}
77208c2ecf20Sopenharmony_ci
77218c2ecf20Sopenharmony_cistatic struct intel_global_state *intel_dbuf_duplicate_state(struct intel_global_obj *obj)
77228c2ecf20Sopenharmony_ci{
77238c2ecf20Sopenharmony_ci	struct intel_dbuf_state *dbuf_state;
77248c2ecf20Sopenharmony_ci
77258c2ecf20Sopenharmony_ci	dbuf_state = kmemdup(obj->state, sizeof(*dbuf_state), GFP_KERNEL);
77268c2ecf20Sopenharmony_ci	if (!dbuf_state)
77278c2ecf20Sopenharmony_ci		return NULL;
77288c2ecf20Sopenharmony_ci
77298c2ecf20Sopenharmony_ci	return &dbuf_state->base;
77308c2ecf20Sopenharmony_ci}
77318c2ecf20Sopenharmony_ci
77328c2ecf20Sopenharmony_cistatic void intel_dbuf_destroy_state(struct intel_global_obj *obj,
77338c2ecf20Sopenharmony_ci				     struct intel_global_state *state)
77348c2ecf20Sopenharmony_ci{
77358c2ecf20Sopenharmony_ci	kfree(state);
77368c2ecf20Sopenharmony_ci}
77378c2ecf20Sopenharmony_ci
77388c2ecf20Sopenharmony_cistatic const struct intel_global_state_funcs intel_dbuf_funcs = {
77398c2ecf20Sopenharmony_ci	.atomic_duplicate_state = intel_dbuf_duplicate_state,
77408c2ecf20Sopenharmony_ci	.atomic_destroy_state = intel_dbuf_destroy_state,
77418c2ecf20Sopenharmony_ci};
77428c2ecf20Sopenharmony_ci
77438c2ecf20Sopenharmony_cistruct intel_dbuf_state *
77448c2ecf20Sopenharmony_ciintel_atomic_get_dbuf_state(struct intel_atomic_state *state)
77458c2ecf20Sopenharmony_ci{
77468c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
77478c2ecf20Sopenharmony_ci	struct intel_global_state *dbuf_state;
77488c2ecf20Sopenharmony_ci
77498c2ecf20Sopenharmony_ci	dbuf_state = intel_atomic_get_global_obj_state(state, &dev_priv->dbuf.obj);
77508c2ecf20Sopenharmony_ci	if (IS_ERR(dbuf_state))
77518c2ecf20Sopenharmony_ci		return ERR_CAST(dbuf_state);
77528c2ecf20Sopenharmony_ci
77538c2ecf20Sopenharmony_ci	return to_intel_dbuf_state(dbuf_state);
77548c2ecf20Sopenharmony_ci}
77558c2ecf20Sopenharmony_ci
77568c2ecf20Sopenharmony_ciint intel_dbuf_init(struct drm_i915_private *dev_priv)
77578c2ecf20Sopenharmony_ci{
77588c2ecf20Sopenharmony_ci	struct intel_dbuf_state *dbuf_state;
77598c2ecf20Sopenharmony_ci
77608c2ecf20Sopenharmony_ci	dbuf_state = kzalloc(sizeof(*dbuf_state), GFP_KERNEL);
77618c2ecf20Sopenharmony_ci	if (!dbuf_state)
77628c2ecf20Sopenharmony_ci		return -ENOMEM;
77638c2ecf20Sopenharmony_ci
77648c2ecf20Sopenharmony_ci	intel_atomic_global_obj_init(dev_priv, &dev_priv->dbuf.obj,
77658c2ecf20Sopenharmony_ci				     &dbuf_state->base, &intel_dbuf_funcs);
77668c2ecf20Sopenharmony_ci
77678c2ecf20Sopenharmony_ci	return 0;
77688c2ecf20Sopenharmony_ci}
77698c2ecf20Sopenharmony_ci
77708c2ecf20Sopenharmony_civoid intel_dbuf_pre_plane_update(struct intel_atomic_state *state)
77718c2ecf20Sopenharmony_ci{
77728c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
77738c2ecf20Sopenharmony_ci	const struct intel_dbuf_state *new_dbuf_state =
77748c2ecf20Sopenharmony_ci		intel_atomic_get_new_dbuf_state(state);
77758c2ecf20Sopenharmony_ci	const struct intel_dbuf_state *old_dbuf_state =
77768c2ecf20Sopenharmony_ci		intel_atomic_get_old_dbuf_state(state);
77778c2ecf20Sopenharmony_ci
77788c2ecf20Sopenharmony_ci	if (!new_dbuf_state ||
77798c2ecf20Sopenharmony_ci	    new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices)
77808c2ecf20Sopenharmony_ci		return;
77818c2ecf20Sopenharmony_ci
77828c2ecf20Sopenharmony_ci	WARN_ON(!new_dbuf_state->base.changed);
77838c2ecf20Sopenharmony_ci
77848c2ecf20Sopenharmony_ci	gen9_dbuf_slices_update(dev_priv,
77858c2ecf20Sopenharmony_ci				old_dbuf_state->enabled_slices |
77868c2ecf20Sopenharmony_ci				new_dbuf_state->enabled_slices);
77878c2ecf20Sopenharmony_ci}
77888c2ecf20Sopenharmony_ci
77898c2ecf20Sopenharmony_civoid intel_dbuf_post_plane_update(struct intel_atomic_state *state)
77908c2ecf20Sopenharmony_ci{
77918c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
77928c2ecf20Sopenharmony_ci	const struct intel_dbuf_state *new_dbuf_state =
77938c2ecf20Sopenharmony_ci		intel_atomic_get_new_dbuf_state(state);
77948c2ecf20Sopenharmony_ci	const struct intel_dbuf_state *old_dbuf_state =
77958c2ecf20Sopenharmony_ci		intel_atomic_get_old_dbuf_state(state);
77968c2ecf20Sopenharmony_ci
77978c2ecf20Sopenharmony_ci	if (!new_dbuf_state ||
77988c2ecf20Sopenharmony_ci	    new_dbuf_state->enabled_slices == old_dbuf_state->enabled_slices)
77998c2ecf20Sopenharmony_ci		return;
78008c2ecf20Sopenharmony_ci
78018c2ecf20Sopenharmony_ci	WARN_ON(!new_dbuf_state->base.changed);
78028c2ecf20Sopenharmony_ci
78038c2ecf20Sopenharmony_ci	gen9_dbuf_slices_update(dev_priv,
78048c2ecf20Sopenharmony_ci				new_dbuf_state->enabled_slices);
78058c2ecf20Sopenharmony_ci}
7806