18c2ecf20Sopenharmony_ci/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
28c2ecf20Sopenharmony_ci */
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
58c2ecf20Sopenharmony_ci * All Rights Reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
88c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
98c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
108c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
118c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
128c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
138c2ecf20Sopenharmony_ci * the following conditions:
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
168c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
178c2ecf20Sopenharmony_ci * of the Software.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
208c2ecf20Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
218c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
228c2ecf20Sopenharmony_ci * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
238c2ecf20Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
248c2ecf20Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
258c2ecf20Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <linux/circ_buf.h>
328c2ecf20Sopenharmony_ci#include <linux/slab.h>
338c2ecf20Sopenharmony_ci#include <linux/sysrq.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <drm/drm_drv.h>
368c2ecf20Sopenharmony_ci#include <drm/drm_irq.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include "display/intel_display_types.h"
398c2ecf20Sopenharmony_ci#include "display/intel_fifo_underrun.h"
408c2ecf20Sopenharmony_ci#include "display/intel_hotplug.h"
418c2ecf20Sopenharmony_ci#include "display/intel_lpe_audio.h"
428c2ecf20Sopenharmony_ci#include "display/intel_psr.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#include "gt/intel_breadcrumbs.h"
458c2ecf20Sopenharmony_ci#include "gt/intel_gt.h"
468c2ecf20Sopenharmony_ci#include "gt/intel_gt_irq.h"
478c2ecf20Sopenharmony_ci#include "gt/intel_gt_pm_irq.h"
488c2ecf20Sopenharmony_ci#include "gt/intel_rps.h"
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include "i915_drv.h"
518c2ecf20Sopenharmony_ci#include "i915_irq.h"
528c2ecf20Sopenharmony_ci#include "i915_trace.h"
538c2ecf20Sopenharmony_ci#include "intel_pm.h"
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/**
568c2ecf20Sopenharmony_ci * DOC: interrupt handling
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * These functions provide the basic support for enabling and disabling the
598c2ecf20Sopenharmony_ci * interrupt handling support. There's a lot more functionality in i915_irq.c
608c2ecf20Sopenharmony_ci * and related files, but that will be described in separate chapters.
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_citypedef bool (*long_pulse_detect_func)(enum hpd_pin pin, u32 val);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const u32 hpd_ilk[HPD_NUM_PINS] = {
668c2ecf20Sopenharmony_ci	[HPD_PORT_A] = DE_DP_A_HOTPLUG,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic const u32 hpd_ivb[HPD_NUM_PINS] = {
708c2ecf20Sopenharmony_ci	[HPD_PORT_A] = DE_DP_A_HOTPLUG_IVB,
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic const u32 hpd_bdw[HPD_NUM_PINS] = {
748c2ecf20Sopenharmony_ci	[HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG,
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic const u32 hpd_ibx[HPD_NUM_PINS] = {
788c2ecf20Sopenharmony_ci	[HPD_CRT] = SDE_CRT_HOTPLUG,
798c2ecf20Sopenharmony_ci	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
808c2ecf20Sopenharmony_ci	[HPD_PORT_B] = SDE_PORTB_HOTPLUG,
818c2ecf20Sopenharmony_ci	[HPD_PORT_C] = SDE_PORTC_HOTPLUG,
828c2ecf20Sopenharmony_ci	[HPD_PORT_D] = SDE_PORTD_HOTPLUG,
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic const u32 hpd_cpt[HPD_NUM_PINS] = {
868c2ecf20Sopenharmony_ci	[HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
878c2ecf20Sopenharmony_ci	[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
888c2ecf20Sopenharmony_ci	[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
898c2ecf20Sopenharmony_ci	[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
908c2ecf20Sopenharmony_ci	[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
918c2ecf20Sopenharmony_ci};
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic const u32 hpd_spt[HPD_NUM_PINS] = {
948c2ecf20Sopenharmony_ci	[HPD_PORT_A] = SDE_PORTA_HOTPLUG_SPT,
958c2ecf20Sopenharmony_ci	[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
968c2ecf20Sopenharmony_ci	[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
978c2ecf20Sopenharmony_ci	[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
988c2ecf20Sopenharmony_ci	[HPD_PORT_E] = SDE_PORTE_HOTPLUG_SPT,
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const u32 hpd_mask_i915[HPD_NUM_PINS] = {
1028c2ecf20Sopenharmony_ci	[HPD_CRT] = CRT_HOTPLUG_INT_EN,
1038c2ecf20Sopenharmony_ci	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
1048c2ecf20Sopenharmony_ci	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
1058c2ecf20Sopenharmony_ci	[HPD_PORT_B] = PORTB_HOTPLUG_INT_EN,
1068c2ecf20Sopenharmony_ci	[HPD_PORT_C] = PORTC_HOTPLUG_INT_EN,
1078c2ecf20Sopenharmony_ci	[HPD_PORT_D] = PORTD_HOTPLUG_INT_EN,
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic const u32 hpd_status_g4x[HPD_NUM_PINS] = {
1118c2ecf20Sopenharmony_ci	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
1128c2ecf20Sopenharmony_ci	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
1138c2ecf20Sopenharmony_ci	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
1148c2ecf20Sopenharmony_ci	[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
1158c2ecf20Sopenharmony_ci	[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
1168c2ecf20Sopenharmony_ci	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS,
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic const u32 hpd_status_i915[HPD_NUM_PINS] = {
1208c2ecf20Sopenharmony_ci	[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
1218c2ecf20Sopenharmony_ci	[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
1228c2ecf20Sopenharmony_ci	[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
1238c2ecf20Sopenharmony_ci	[HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
1248c2ecf20Sopenharmony_ci	[HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
1258c2ecf20Sopenharmony_ci	[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS,
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const u32 hpd_bxt[HPD_NUM_PINS] = {
1298c2ecf20Sopenharmony_ci	[HPD_PORT_A] = BXT_DE_PORT_HP_DDIA,
1308c2ecf20Sopenharmony_ci	[HPD_PORT_B] = BXT_DE_PORT_HP_DDIB,
1318c2ecf20Sopenharmony_ci	[HPD_PORT_C] = BXT_DE_PORT_HP_DDIC,
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic const u32 hpd_gen11[HPD_NUM_PINS] = {
1358c2ecf20Sopenharmony_ci	[HPD_PORT_TC1] = GEN11_TC_HOTPLUG(PORT_TC1) | GEN11_TBT_HOTPLUG(PORT_TC1),
1368c2ecf20Sopenharmony_ci	[HPD_PORT_TC2] = GEN11_TC_HOTPLUG(PORT_TC2) | GEN11_TBT_HOTPLUG(PORT_TC2),
1378c2ecf20Sopenharmony_ci	[HPD_PORT_TC3] = GEN11_TC_HOTPLUG(PORT_TC3) | GEN11_TBT_HOTPLUG(PORT_TC3),
1388c2ecf20Sopenharmony_ci	[HPD_PORT_TC4] = GEN11_TC_HOTPLUG(PORT_TC4) | GEN11_TBT_HOTPLUG(PORT_TC4),
1398c2ecf20Sopenharmony_ci	[HPD_PORT_TC5] = GEN11_TC_HOTPLUG(PORT_TC5) | GEN11_TBT_HOTPLUG(PORT_TC5),
1408c2ecf20Sopenharmony_ci	[HPD_PORT_TC6] = GEN11_TC_HOTPLUG(PORT_TC6) | GEN11_TBT_HOTPLUG(PORT_TC6),
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic const u32 hpd_icp[HPD_NUM_PINS] = {
1448c2ecf20Sopenharmony_ci	[HPD_PORT_A] = SDE_DDI_HOTPLUG_ICP(PORT_A),
1458c2ecf20Sopenharmony_ci	[HPD_PORT_B] = SDE_DDI_HOTPLUG_ICP(PORT_B),
1468c2ecf20Sopenharmony_ci	[HPD_PORT_C] = SDE_DDI_HOTPLUG_ICP(PORT_C),
1478c2ecf20Sopenharmony_ci	[HPD_PORT_TC1] = SDE_TC_HOTPLUG_ICP(PORT_TC1),
1488c2ecf20Sopenharmony_ci	[HPD_PORT_TC2] = SDE_TC_HOTPLUG_ICP(PORT_TC2),
1498c2ecf20Sopenharmony_ci	[HPD_PORT_TC3] = SDE_TC_HOTPLUG_ICP(PORT_TC3),
1508c2ecf20Sopenharmony_ci	[HPD_PORT_TC4] = SDE_TC_HOTPLUG_ICP(PORT_TC4),
1518c2ecf20Sopenharmony_ci	[HPD_PORT_TC5] = SDE_TC_HOTPLUG_ICP(PORT_TC5),
1528c2ecf20Sopenharmony_ci	[HPD_PORT_TC6] = SDE_TC_HOTPLUG_ICP(PORT_TC6),
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic void intel_hpd_init_pins(struct drm_i915_private *dev_priv)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct i915_hotplug *hpd = &dev_priv->hotplug;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (HAS_GMCH(dev_priv)) {
1608c2ecf20Sopenharmony_ci		if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
1618c2ecf20Sopenharmony_ci		    IS_CHERRYVIEW(dev_priv))
1628c2ecf20Sopenharmony_ci			hpd->hpd = hpd_status_g4x;
1638c2ecf20Sopenharmony_ci		else
1648c2ecf20Sopenharmony_ci			hpd->hpd = hpd_status_i915;
1658c2ecf20Sopenharmony_ci		return;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11)
1698c2ecf20Sopenharmony_ci		hpd->hpd = hpd_gen11;
1708c2ecf20Sopenharmony_ci	else if (IS_GEN9_LP(dev_priv))
1718c2ecf20Sopenharmony_ci		hpd->hpd = hpd_bxt;
1728c2ecf20Sopenharmony_ci	else if (INTEL_GEN(dev_priv) >= 8)
1738c2ecf20Sopenharmony_ci		hpd->hpd = hpd_bdw;
1748c2ecf20Sopenharmony_ci	else if (INTEL_GEN(dev_priv) >= 7)
1758c2ecf20Sopenharmony_ci		hpd->hpd = hpd_ivb;
1768c2ecf20Sopenharmony_ci	else
1778c2ecf20Sopenharmony_ci		hpd->hpd = hpd_ilk;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (!HAS_PCH_SPLIT(dev_priv) || HAS_PCH_NOP(dev_priv))
1808c2ecf20Sopenharmony_ci		return;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) ||
1838c2ecf20Sopenharmony_ci	    HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv))
1848c2ecf20Sopenharmony_ci		hpd->pch_hpd = hpd_icp;
1858c2ecf20Sopenharmony_ci	else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv))
1868c2ecf20Sopenharmony_ci		hpd->pch_hpd = hpd_spt;
1878c2ecf20Sopenharmony_ci	else if (HAS_PCH_LPT(dev_priv) || HAS_PCH_CPT(dev_priv))
1888c2ecf20Sopenharmony_ci		hpd->pch_hpd = hpd_cpt;
1898c2ecf20Sopenharmony_ci	else if (HAS_PCH_IBX(dev_priv))
1908c2ecf20Sopenharmony_ci		hpd->pch_hpd = hpd_ibx;
1918c2ecf20Sopenharmony_ci	else
1928c2ecf20Sopenharmony_ci		MISSING_CASE(INTEL_PCH_TYPE(dev_priv));
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void
1968c2ecf20Sopenharmony_ciintel_handle_vblank(struct drm_i915_private *dev_priv, enum pipe pipe)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	drm_crtc_handle_vblank(&crtc->base);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_civoid gen3_irq_reset(struct intel_uncore *uncore, i915_reg_t imr,
2048c2ecf20Sopenharmony_ci		    i915_reg_t iir, i915_reg_t ier)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, imr, 0xffffffff);
2078c2ecf20Sopenharmony_ci	intel_uncore_posting_read(uncore, imr);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, ier, 0);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* IIR can theoretically queue up two events. Be paranoid. */
2128c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, iir, 0xffffffff);
2138c2ecf20Sopenharmony_ci	intel_uncore_posting_read(uncore, iir);
2148c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, iir, 0xffffffff);
2158c2ecf20Sopenharmony_ci	intel_uncore_posting_read(uncore, iir);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_civoid gen2_irq_reset(struct intel_uncore *uncore)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IMR, 0xffff);
2218c2ecf20Sopenharmony_ci	intel_uncore_posting_read16(uncore, GEN2_IMR);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IER, 0);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/* IIR can theoretically queue up two events. Be paranoid. */
2268c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IIR, 0xffff);
2278c2ecf20Sopenharmony_ci	intel_uncore_posting_read16(uncore, GEN2_IIR);
2288c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IIR, 0xffff);
2298c2ecf20Sopenharmony_ci	intel_uncore_posting_read16(uncore, GEN2_IIR);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/*
2338c2ecf20Sopenharmony_ci * We should clear IMR at preinstall/uninstall, and just check at postinstall.
2348c2ecf20Sopenharmony_ci */
2358c2ecf20Sopenharmony_cistatic void gen3_assert_iir_is_zero(struct intel_uncore *uncore, i915_reg_t reg)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	u32 val = intel_uncore_read(uncore, reg);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (val == 0)
2408c2ecf20Sopenharmony_ci		return;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	drm_WARN(&uncore->i915->drm, 1,
2438c2ecf20Sopenharmony_ci		 "Interrupt register 0x%x is not zero: 0x%08x\n",
2448c2ecf20Sopenharmony_ci		 i915_mmio_reg_offset(reg), val);
2458c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, reg, 0xffffffff);
2468c2ecf20Sopenharmony_ci	intel_uncore_posting_read(uncore, reg);
2478c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, reg, 0xffffffff);
2488c2ecf20Sopenharmony_ci	intel_uncore_posting_read(uncore, reg);
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic void gen2_assert_iir_is_zero(struct intel_uncore *uncore)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	u16 val = intel_uncore_read16(uncore, GEN2_IIR);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (val == 0)
2568c2ecf20Sopenharmony_ci		return;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	drm_WARN(&uncore->i915->drm, 1,
2598c2ecf20Sopenharmony_ci		 "Interrupt register 0x%x is not zero: 0x%08x\n",
2608c2ecf20Sopenharmony_ci		 i915_mmio_reg_offset(GEN2_IIR), val);
2618c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IIR, 0xffff);
2628c2ecf20Sopenharmony_ci	intel_uncore_posting_read16(uncore, GEN2_IIR);
2638c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IIR, 0xffff);
2648c2ecf20Sopenharmony_ci	intel_uncore_posting_read16(uncore, GEN2_IIR);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_civoid gen3_irq_init(struct intel_uncore *uncore,
2688c2ecf20Sopenharmony_ci		   i915_reg_t imr, u32 imr_val,
2698c2ecf20Sopenharmony_ci		   i915_reg_t ier, u32 ier_val,
2708c2ecf20Sopenharmony_ci		   i915_reg_t iir)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	gen3_assert_iir_is_zero(uncore, iir);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, ier, ier_val);
2758c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, imr, imr_val);
2768c2ecf20Sopenharmony_ci	intel_uncore_posting_read(uncore, imr);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_civoid gen2_irq_init(struct intel_uncore *uncore,
2808c2ecf20Sopenharmony_ci		   u32 imr_val, u32 ier_val)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	gen2_assert_iir_is_zero(uncore);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IER, ier_val);
2858c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, GEN2_IMR, imr_val);
2868c2ecf20Sopenharmony_ci	intel_uncore_posting_read16(uncore, GEN2_IMR);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/* For display hotplug interrupt */
2908c2ecf20Sopenharmony_cistatic inline void
2918c2ecf20Sopenharmony_cii915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv,
2928c2ecf20Sopenharmony_ci				     u32 mask,
2938c2ecf20Sopenharmony_ci				     u32 bits)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	u32 val;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
2988c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, bits & ~mask);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	val = I915_READ(PORT_HOTPLUG_EN);
3018c2ecf20Sopenharmony_ci	val &= ~mask;
3028c2ecf20Sopenharmony_ci	val |= bits;
3038c2ecf20Sopenharmony_ci	I915_WRITE(PORT_HOTPLUG_EN, val);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/**
3078c2ecf20Sopenharmony_ci * i915_hotplug_interrupt_update - update hotplug interrupt enable
3088c2ecf20Sopenharmony_ci * @dev_priv: driver private
3098c2ecf20Sopenharmony_ci * @mask: bits to update
3108c2ecf20Sopenharmony_ci * @bits: bits to enable
3118c2ecf20Sopenharmony_ci * NOTE: the HPD enable bits are modified both inside and outside
3128c2ecf20Sopenharmony_ci * of an interrupt context. To avoid that read-modify-write cycles
3138c2ecf20Sopenharmony_ci * interfer, these bits are protected by a spinlock. Since this
3148c2ecf20Sopenharmony_ci * function is usually not called from a context where the lock is
3158c2ecf20Sopenharmony_ci * held already, this function acquires the lock itself. A non-locking
3168c2ecf20Sopenharmony_ci * version is also available.
3178c2ecf20Sopenharmony_ci */
3188c2ecf20Sopenharmony_civoid i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
3198c2ecf20Sopenharmony_ci				   u32 mask,
3208c2ecf20Sopenharmony_ci				   u32 bits)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
3238c2ecf20Sopenharmony_ci	i915_hotplug_interrupt_update_locked(dev_priv, mask, bits);
3248c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci/**
3288c2ecf20Sopenharmony_ci * ilk_update_display_irq - update DEIMR
3298c2ecf20Sopenharmony_ci * @dev_priv: driver private
3308c2ecf20Sopenharmony_ci * @interrupt_mask: mask of interrupt bits to update
3318c2ecf20Sopenharmony_ci * @enabled_irq_mask: mask of interrupt bits to enable
3328c2ecf20Sopenharmony_ci */
3338c2ecf20Sopenharmony_civoid ilk_update_display_irq(struct drm_i915_private *dev_priv,
3348c2ecf20Sopenharmony_ci			    u32 interrupt_mask,
3358c2ecf20Sopenharmony_ci			    u32 enabled_irq_mask)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	u32 new_val;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
3448c2ecf20Sopenharmony_ci		return;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	new_val = dev_priv->irq_mask;
3478c2ecf20Sopenharmony_ci	new_val &= ~interrupt_mask;
3488c2ecf20Sopenharmony_ci	new_val |= (~enabled_irq_mask & interrupt_mask);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (new_val != dev_priv->irq_mask) {
3518c2ecf20Sopenharmony_ci		dev_priv->irq_mask = new_val;
3528c2ecf20Sopenharmony_ci		I915_WRITE(DEIMR, dev_priv->irq_mask);
3538c2ecf20Sopenharmony_ci		POSTING_READ(DEIMR);
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci/**
3588c2ecf20Sopenharmony_ci * bdw_update_port_irq - update DE port interrupt
3598c2ecf20Sopenharmony_ci * @dev_priv: driver private
3608c2ecf20Sopenharmony_ci * @interrupt_mask: mask of interrupt bits to update
3618c2ecf20Sopenharmony_ci * @enabled_irq_mask: mask of interrupt bits to enable
3628c2ecf20Sopenharmony_ci */
3638c2ecf20Sopenharmony_cistatic void bdw_update_port_irq(struct drm_i915_private *dev_priv,
3648c2ecf20Sopenharmony_ci				u32 interrupt_mask,
3658c2ecf20Sopenharmony_ci				u32 enabled_irq_mask)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	u32 new_val;
3688c2ecf20Sopenharmony_ci	u32 old_val;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
3758c2ecf20Sopenharmony_ci		return;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	old_val = I915_READ(GEN8_DE_PORT_IMR);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	new_val = old_val;
3808c2ecf20Sopenharmony_ci	new_val &= ~interrupt_mask;
3818c2ecf20Sopenharmony_ci	new_val |= (~enabled_irq_mask & interrupt_mask);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (new_val != old_val) {
3848c2ecf20Sopenharmony_ci		I915_WRITE(GEN8_DE_PORT_IMR, new_val);
3858c2ecf20Sopenharmony_ci		POSTING_READ(GEN8_DE_PORT_IMR);
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci/**
3908c2ecf20Sopenharmony_ci * bdw_update_pipe_irq - update DE pipe interrupt
3918c2ecf20Sopenharmony_ci * @dev_priv: driver private
3928c2ecf20Sopenharmony_ci * @pipe: pipe whose interrupt to update
3938c2ecf20Sopenharmony_ci * @interrupt_mask: mask of interrupt bits to update
3948c2ecf20Sopenharmony_ci * @enabled_irq_mask: mask of interrupt bits to enable
3958c2ecf20Sopenharmony_ci */
3968c2ecf20Sopenharmony_civoid bdw_update_pipe_irq(struct drm_i915_private *dev_priv,
3978c2ecf20Sopenharmony_ci			 enum pipe pipe,
3988c2ecf20Sopenharmony_ci			 u32 interrupt_mask,
3998c2ecf20Sopenharmony_ci			 u32 enabled_irq_mask)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	u32 new_val;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
4088c2ecf20Sopenharmony_ci		return;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	new_val = dev_priv->de_irq_mask[pipe];
4118c2ecf20Sopenharmony_ci	new_val &= ~interrupt_mask;
4128c2ecf20Sopenharmony_ci	new_val |= (~enabled_irq_mask & interrupt_mask);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (new_val != dev_priv->de_irq_mask[pipe]) {
4158c2ecf20Sopenharmony_ci		dev_priv->de_irq_mask[pipe] = new_val;
4168c2ecf20Sopenharmony_ci		I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
4178c2ecf20Sopenharmony_ci		POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/**
4228c2ecf20Sopenharmony_ci * ibx_display_interrupt_update - update SDEIMR
4238c2ecf20Sopenharmony_ci * @dev_priv: driver private
4248c2ecf20Sopenharmony_ci * @interrupt_mask: mask of interrupt bits to update
4258c2ecf20Sopenharmony_ci * @enabled_irq_mask: mask of interrupt bits to enable
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_civoid ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
4288c2ecf20Sopenharmony_ci				  u32 interrupt_mask,
4298c2ecf20Sopenharmony_ci				  u32 enabled_irq_mask)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	u32 sdeimr = I915_READ(SDEIMR);
4328c2ecf20Sopenharmony_ci	sdeimr &= ~interrupt_mask;
4338c2ecf20Sopenharmony_ci	sdeimr |= (~enabled_irq_mask & interrupt_mask);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, enabled_irq_mask & ~interrupt_mask);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv)))
4408c2ecf20Sopenharmony_ci		return;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	I915_WRITE(SDEIMR, sdeimr);
4438c2ecf20Sopenharmony_ci	POSTING_READ(SDEIMR);
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ciu32 i915_pipestat_enable_mask(struct drm_i915_private *dev_priv,
4478c2ecf20Sopenharmony_ci			      enum pipe pipe)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	u32 status_mask = dev_priv->pipestat_irq_mask[pipe];
4508c2ecf20Sopenharmony_ci	u32 enable_mask = status_mask << 16;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) < 5)
4558c2ecf20Sopenharmony_ci		goto out;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/*
4588c2ecf20Sopenharmony_ci	 * On pipe A we don't support the PSR interrupt yet,
4598c2ecf20Sopenharmony_ci	 * on pipe B and C the same bit MBZ.
4608c2ecf20Sopenharmony_ci	 */
4618c2ecf20Sopenharmony_ci	if (drm_WARN_ON_ONCE(&dev_priv->drm,
4628c2ecf20Sopenharmony_ci			     status_mask & PIPE_A_PSR_STATUS_VLV))
4638c2ecf20Sopenharmony_ci		return 0;
4648c2ecf20Sopenharmony_ci	/*
4658c2ecf20Sopenharmony_ci	 * On pipe B and C we don't support the PSR interrupt yet, on pipe
4668c2ecf20Sopenharmony_ci	 * A the same bit is for perf counters which we don't use either.
4678c2ecf20Sopenharmony_ci	 */
4688c2ecf20Sopenharmony_ci	if (drm_WARN_ON_ONCE(&dev_priv->drm,
4698c2ecf20Sopenharmony_ci			     status_mask & PIPE_B_PSR_STATUS_VLV))
4708c2ecf20Sopenharmony_ci		return 0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS |
4738c2ecf20Sopenharmony_ci			 SPRITE0_FLIP_DONE_INT_EN_VLV |
4748c2ecf20Sopenharmony_ci			 SPRITE1_FLIP_DONE_INT_EN_VLV);
4758c2ecf20Sopenharmony_ci	if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV)
4768c2ecf20Sopenharmony_ci		enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV;
4778c2ecf20Sopenharmony_ci	if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
4788c2ecf20Sopenharmony_ci		enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ciout:
4818c2ecf20Sopenharmony_ci	drm_WARN_ONCE(&dev_priv->drm,
4828c2ecf20Sopenharmony_ci		      enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
4838c2ecf20Sopenharmony_ci		      status_mask & ~PIPESTAT_INT_STATUS_MASK,
4848c2ecf20Sopenharmony_ci		      "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
4858c2ecf20Sopenharmony_ci		      pipe_name(pipe), enable_mask, status_mask);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return enable_mask;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_civoid i915_enable_pipestat(struct drm_i915_private *dev_priv,
4918c2ecf20Sopenharmony_ci			  enum pipe pipe, u32 status_mask)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	i915_reg_t reg = PIPESTAT(pipe);
4948c2ecf20Sopenharmony_ci	u32 enable_mask;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	drm_WARN_ONCE(&dev_priv->drm, status_mask & ~PIPESTAT_INT_STATUS_MASK,
4978c2ecf20Sopenharmony_ci		      "pipe %c: status_mask=0x%x\n",
4988c2ecf20Sopenharmony_ci		      pipe_name(pipe), status_mask);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
5018c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv));
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == status_mask)
5048c2ecf20Sopenharmony_ci		return;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	dev_priv->pipestat_irq_mask[pipe] |= status_mask;
5078c2ecf20Sopenharmony_ci	enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	I915_WRITE(reg, enable_mask | status_mask);
5108c2ecf20Sopenharmony_ci	POSTING_READ(reg);
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_civoid i915_disable_pipestat(struct drm_i915_private *dev_priv,
5148c2ecf20Sopenharmony_ci			   enum pipe pipe, u32 status_mask)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	i915_reg_t reg = PIPESTAT(pipe);
5178c2ecf20Sopenharmony_ci	u32 enable_mask;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	drm_WARN_ONCE(&dev_priv->drm, status_mask & ~PIPESTAT_INT_STATUS_MASK,
5208c2ecf20Sopenharmony_ci		      "pipe %c: status_mask=0x%x\n",
5218c2ecf20Sopenharmony_ci		      pipe_name(pipe), status_mask);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
5248c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, !intel_irqs_enabled(dev_priv));
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if ((dev_priv->pipestat_irq_mask[pipe] & status_mask) == 0)
5278c2ecf20Sopenharmony_ci		return;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
5308c2ecf20Sopenharmony_ci	enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	I915_WRITE(reg, enable_mask | status_mask);
5338c2ecf20Sopenharmony_ci	POSTING_READ(reg);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic bool i915_has_asle(struct drm_i915_private *dev_priv)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	if (!dev_priv->opregion.asle)
5398c2ecf20Sopenharmony_ci		return false;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci/**
5458c2ecf20Sopenharmony_ci * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
5468c2ecf20Sopenharmony_ci * @dev_priv: i915 device private
5478c2ecf20Sopenharmony_ci */
5488c2ecf20Sopenharmony_cistatic void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	if (!i915_has_asle(dev_priv))
5518c2ecf20Sopenharmony_ci		return;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
5568c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 4)
5578c2ecf20Sopenharmony_ci		i915_enable_pipestat(dev_priv, PIPE_A,
5588c2ecf20Sopenharmony_ci				     PIPE_LEGACY_BLC_EVENT_STATUS);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci/*
5648c2ecf20Sopenharmony_ci * This timing diagram depicts the video signal in and
5658c2ecf20Sopenharmony_ci * around the vertical blanking period.
5668c2ecf20Sopenharmony_ci *
5678c2ecf20Sopenharmony_ci * Assumptions about the fictitious mode used in this example:
5688c2ecf20Sopenharmony_ci *  vblank_start >= 3
5698c2ecf20Sopenharmony_ci *  vsync_start = vblank_start + 1
5708c2ecf20Sopenharmony_ci *  vsync_end = vblank_start + 2
5718c2ecf20Sopenharmony_ci *  vtotal = vblank_start + 3
5728c2ecf20Sopenharmony_ci *
5738c2ecf20Sopenharmony_ci *           start of vblank:
5748c2ecf20Sopenharmony_ci *           latch double buffered registers
5758c2ecf20Sopenharmony_ci *           increment frame counter (ctg+)
5768c2ecf20Sopenharmony_ci *           generate start of vblank interrupt (gen4+)
5778c2ecf20Sopenharmony_ci *           |
5788c2ecf20Sopenharmony_ci *           |          frame start:
5798c2ecf20Sopenharmony_ci *           |          generate frame start interrupt (aka. vblank interrupt) (gmch)
5808c2ecf20Sopenharmony_ci *           |          may be shifted forward 1-3 extra lines via PIPECONF
5818c2ecf20Sopenharmony_ci *           |          |
5828c2ecf20Sopenharmony_ci *           |          |  start of vsync:
5838c2ecf20Sopenharmony_ci *           |          |  generate vsync interrupt
5848c2ecf20Sopenharmony_ci *           |          |  |
5858c2ecf20Sopenharmony_ci * ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx
5868c2ecf20Sopenharmony_ci *       .   \hs/   .      \hs/          \hs/          \hs/   .      \hs/
5878c2ecf20Sopenharmony_ci * ----va---> <-----------------vb--------------------> <--------va-------------
5888c2ecf20Sopenharmony_ci *       |          |       <----vs----->                     |
5898c2ecf20Sopenharmony_ci * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
5908c2ecf20Sopenharmony_ci * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
5918c2ecf20Sopenharmony_ci * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
5928c2ecf20Sopenharmony_ci *       |          |                                         |
5938c2ecf20Sopenharmony_ci *       last visible pixel                                   first visible pixel
5948c2ecf20Sopenharmony_ci *                  |                                         increment frame counter (gen3/4)
5958c2ecf20Sopenharmony_ci *                  pixel counter = vblank_start * htotal     pixel counter = 0 (gen3/4)
5968c2ecf20Sopenharmony_ci *
5978c2ecf20Sopenharmony_ci * x  = horizontal active
5988c2ecf20Sopenharmony_ci * _  = horizontal blanking
5998c2ecf20Sopenharmony_ci * hs = horizontal sync
6008c2ecf20Sopenharmony_ci * va = vertical active
6018c2ecf20Sopenharmony_ci * vb = vertical blanking
6028c2ecf20Sopenharmony_ci * vs = vertical sync
6038c2ecf20Sopenharmony_ci * vbs = vblank_start (number)
6048c2ecf20Sopenharmony_ci *
6058c2ecf20Sopenharmony_ci * Summary:
6068c2ecf20Sopenharmony_ci * - most events happen at the start of horizontal sync
6078c2ecf20Sopenharmony_ci * - frame start happens at the start of horizontal blank, 1-4 lines
6088c2ecf20Sopenharmony_ci *   (depending on PIPECONF settings) after the start of vblank
6098c2ecf20Sopenharmony_ci * - gen3/4 pixel and frame counter are synchronized with the start
6108c2ecf20Sopenharmony_ci *   of horizontal active on the first line of vertical active
6118c2ecf20Sopenharmony_ci */
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci/* Called from drm generic code, passed a 'crtc', which
6148c2ecf20Sopenharmony_ci * we use as a pipe index
6158c2ecf20Sopenharmony_ci */
6168c2ecf20Sopenharmony_ciu32 i915_get_vblank_counter(struct drm_crtc *crtc)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
6198c2ecf20Sopenharmony_ci	struct drm_vblank_crtc *vblank = &dev_priv->drm.vblank[drm_crtc_index(crtc)];
6208c2ecf20Sopenharmony_ci	const struct drm_display_mode *mode = &vblank->hwmode;
6218c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
6228c2ecf20Sopenharmony_ci	i915_reg_t high_frame, low_frame;
6238c2ecf20Sopenharmony_ci	u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
6248c2ecf20Sopenharmony_ci	unsigned long irqflags;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	/*
6278c2ecf20Sopenharmony_ci	 * On i965gm TV output the frame counter only works up to
6288c2ecf20Sopenharmony_ci	 * the point when we enable the TV encoder. After that the
6298c2ecf20Sopenharmony_ci	 * frame counter ceases to work and reads zero. We need a
6308c2ecf20Sopenharmony_ci	 * vblank wait before enabling the TV encoder and so we
6318c2ecf20Sopenharmony_ci	 * have to enable vblank interrupts while the frame counter
6328c2ecf20Sopenharmony_ci	 * is still in a working state. However the core vblank code
6338c2ecf20Sopenharmony_ci	 * does not like us returning non-zero frame counter values
6348c2ecf20Sopenharmony_ci	 * when we've told it that we don't have a working frame
6358c2ecf20Sopenharmony_ci	 * counter. Thus we must stop non-zero values leaking out.
6368c2ecf20Sopenharmony_ci	 */
6378c2ecf20Sopenharmony_ci	if (!vblank->max_vblank_count)
6388c2ecf20Sopenharmony_ci		return 0;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	htotal = mode->crtc_htotal;
6418c2ecf20Sopenharmony_ci	hsync_start = mode->crtc_hsync_start;
6428c2ecf20Sopenharmony_ci	vbl_start = mode->crtc_vblank_start;
6438c2ecf20Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
6448c2ecf20Sopenharmony_ci		vbl_start = DIV_ROUND_UP(vbl_start, 2);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	/* Convert to pixel count */
6478c2ecf20Sopenharmony_ci	vbl_start *= htotal;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	/* Start of vblank event occurs at start of hsync */
6508c2ecf20Sopenharmony_ci	vbl_start -= htotal - hsync_start;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	high_frame = PIPEFRAME(pipe);
6538c2ecf20Sopenharmony_ci	low_frame = PIPEFRAMEPIXEL(pipe);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/*
6588c2ecf20Sopenharmony_ci	 * High & low register fields aren't synchronized, so make sure
6598c2ecf20Sopenharmony_ci	 * we get a low value that's stable across two reads of the high
6608c2ecf20Sopenharmony_ci	 * register.
6618c2ecf20Sopenharmony_ci	 */
6628c2ecf20Sopenharmony_ci	do {
6638c2ecf20Sopenharmony_ci		high1 = intel_de_read_fw(dev_priv, high_frame) & PIPE_FRAME_HIGH_MASK;
6648c2ecf20Sopenharmony_ci		low   = intel_de_read_fw(dev_priv, low_frame);
6658c2ecf20Sopenharmony_ci		high2 = intel_de_read_fw(dev_priv, high_frame) & PIPE_FRAME_HIGH_MASK;
6668c2ecf20Sopenharmony_ci	} while (high1 != high2);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	high1 >>= PIPE_FRAME_HIGH_SHIFT;
6718c2ecf20Sopenharmony_ci	pixel = low & PIPE_PIXEL_MASK;
6728c2ecf20Sopenharmony_ci	low >>= PIPE_FRAME_LOW_SHIFT;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	/*
6758c2ecf20Sopenharmony_ci	 * The frame counter increments at beginning of active.
6768c2ecf20Sopenharmony_ci	 * Cook up a vblank counter by also checking the pixel
6778c2ecf20Sopenharmony_ci	 * counter against vblank start.
6788c2ecf20Sopenharmony_ci	 */
6798c2ecf20Sopenharmony_ci	return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ciu32 g4x_get_vblank_counter(struct drm_crtc *crtc)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
6858c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci/*
6918c2ecf20Sopenharmony_ci * On certain encoders on certain platforms, pipe
6928c2ecf20Sopenharmony_ci * scanline register will not work to get the scanline,
6938c2ecf20Sopenharmony_ci * since the timings are driven from the PORT or issues
6948c2ecf20Sopenharmony_ci * with scanline register updates.
6958c2ecf20Sopenharmony_ci * This function will use Framestamp and current
6968c2ecf20Sopenharmony_ci * timestamp registers to calculate the scanline.
6978c2ecf20Sopenharmony_ci */
6988c2ecf20Sopenharmony_cistatic u32 __intel_get_crtc_scanline_from_timestamp(struct intel_crtc *crtc)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
7018c2ecf20Sopenharmony_ci	struct drm_vblank_crtc *vblank =
7028c2ecf20Sopenharmony_ci		&crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
7038c2ecf20Sopenharmony_ci	const struct drm_display_mode *mode = &vblank->hwmode;
7048c2ecf20Sopenharmony_ci	u32 vblank_start = mode->crtc_vblank_start;
7058c2ecf20Sopenharmony_ci	u32 vtotal = mode->crtc_vtotal;
7068c2ecf20Sopenharmony_ci	u32 htotal = mode->crtc_htotal;
7078c2ecf20Sopenharmony_ci	u32 clock = mode->crtc_clock;
7088c2ecf20Sopenharmony_ci	u32 scanline, scan_prev_time, scan_curr_time, scan_post_time;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	/*
7118c2ecf20Sopenharmony_ci	 * To avoid the race condition where we might cross into the
7128c2ecf20Sopenharmony_ci	 * next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
7138c2ecf20Sopenharmony_ci	 * reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
7148c2ecf20Sopenharmony_ci	 * during the same frame.
7158c2ecf20Sopenharmony_ci	 */
7168c2ecf20Sopenharmony_ci	do {
7178c2ecf20Sopenharmony_ci		/*
7188c2ecf20Sopenharmony_ci		 * This field provides read back of the display
7198c2ecf20Sopenharmony_ci		 * pipe frame time stamp. The time stamp value
7208c2ecf20Sopenharmony_ci		 * is sampled at every start of vertical blank.
7218c2ecf20Sopenharmony_ci		 */
7228c2ecf20Sopenharmony_ci		scan_prev_time = intel_de_read_fw(dev_priv,
7238c2ecf20Sopenharmony_ci						  PIPE_FRMTMSTMP(crtc->pipe));
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		/*
7268c2ecf20Sopenharmony_ci		 * The TIMESTAMP_CTR register has the current
7278c2ecf20Sopenharmony_ci		 * time stamp value.
7288c2ecf20Sopenharmony_ci		 */
7298c2ecf20Sopenharmony_ci		scan_curr_time = intel_de_read_fw(dev_priv, IVB_TIMESTAMP_CTR);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		scan_post_time = intel_de_read_fw(dev_priv,
7328c2ecf20Sopenharmony_ci						  PIPE_FRMTMSTMP(crtc->pipe));
7338c2ecf20Sopenharmony_ci	} while (scan_post_time != scan_prev_time);
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	scanline = div_u64(mul_u32_u32(scan_curr_time - scan_prev_time,
7368c2ecf20Sopenharmony_ci					clock), 1000 * htotal);
7378c2ecf20Sopenharmony_ci	scanline = min(scanline, vtotal - 1);
7388c2ecf20Sopenharmony_ci	scanline = (scanline + vblank_start) % vtotal;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	return scanline;
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci/*
7448c2ecf20Sopenharmony_ci * intel_de_read_fw(), only for fast reads of display block, no need for
7458c2ecf20Sopenharmony_ci * forcewake etc.
7468c2ecf20Sopenharmony_ci */
7478c2ecf20Sopenharmony_cistatic int __intel_get_crtc_scanline(struct intel_crtc *crtc)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	struct drm_device *dev = crtc->base.dev;
7508c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(dev);
7518c2ecf20Sopenharmony_ci	const struct drm_display_mode *mode;
7528c2ecf20Sopenharmony_ci	struct drm_vblank_crtc *vblank;
7538c2ecf20Sopenharmony_ci	enum pipe pipe = crtc->pipe;
7548c2ecf20Sopenharmony_ci	int position, vtotal;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (!crtc->active)
7578c2ecf20Sopenharmony_ci		return -1;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)];
7608c2ecf20Sopenharmony_ci	mode = &vblank->hwmode;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	if (crtc->mode_flags & I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP)
7638c2ecf20Sopenharmony_ci		return __intel_get_crtc_scanline_from_timestamp(crtc);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	vtotal = mode->crtc_vtotal;
7668c2ecf20Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
7678c2ecf20Sopenharmony_ci		vtotal /= 2;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 2))
7708c2ecf20Sopenharmony_ci		position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
7718c2ecf20Sopenharmony_ci	else
7728c2ecf20Sopenharmony_ci		position = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	/*
7758c2ecf20Sopenharmony_ci	 * On HSW, the DSL reg (0x70000) appears to return 0 if we
7768c2ecf20Sopenharmony_ci	 * read it just before the start of vblank.  So try it again
7778c2ecf20Sopenharmony_ci	 * so we don't accidentally end up spanning a vblank frame
7788c2ecf20Sopenharmony_ci	 * increment, causing the pipe_update_end() code to squak at us.
7798c2ecf20Sopenharmony_ci	 *
7808c2ecf20Sopenharmony_ci	 * The nature of this problem means we can't simply check the ISR
7818c2ecf20Sopenharmony_ci	 * bit and return the vblank start value; nor can we use the scanline
7828c2ecf20Sopenharmony_ci	 * debug register in the transcoder as it appears to have the same
7838c2ecf20Sopenharmony_ci	 * problem.  We may need to extend this to include other platforms,
7848c2ecf20Sopenharmony_ci	 * but so far testing only shows the problem on HSW.
7858c2ecf20Sopenharmony_ci	 */
7868c2ecf20Sopenharmony_ci	if (HAS_DDI(dev_priv) && !position) {
7878c2ecf20Sopenharmony_ci		int i, temp;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		for (i = 0; i < 100; i++) {
7908c2ecf20Sopenharmony_ci			udelay(1);
7918c2ecf20Sopenharmony_ci			temp = intel_de_read_fw(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
7928c2ecf20Sopenharmony_ci			if (temp != position) {
7938c2ecf20Sopenharmony_ci				position = temp;
7948c2ecf20Sopenharmony_ci				break;
7958c2ecf20Sopenharmony_ci			}
7968c2ecf20Sopenharmony_ci		}
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/*
8008c2ecf20Sopenharmony_ci	 * See update_scanline_offset() for the details on the
8018c2ecf20Sopenharmony_ci	 * scanline_offset adjustment.
8028c2ecf20Sopenharmony_ci	 */
8038c2ecf20Sopenharmony_ci	return (position + crtc->scanline_offset) % vtotal;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
8078c2ecf20Sopenharmony_ci				     bool in_vblank_irq,
8088c2ecf20Sopenharmony_ci				     int *vpos, int *hpos,
8098c2ecf20Sopenharmony_ci				     ktime_t *stime, ktime_t *etime,
8108c2ecf20Sopenharmony_ci				     const struct drm_display_mode *mode)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct drm_device *dev = _crtc->dev;
8138c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(dev);
8148c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = to_intel_crtc(_crtc);
8158c2ecf20Sopenharmony_ci	enum pipe pipe = crtc->pipe;
8168c2ecf20Sopenharmony_ci	int position;
8178c2ecf20Sopenharmony_ci	int vbl_start, vbl_end, hsync_start, htotal, vtotal;
8188c2ecf20Sopenharmony_ci	unsigned long irqflags;
8198c2ecf20Sopenharmony_ci	bool use_scanline_counter = INTEL_GEN(dev_priv) >= 5 ||
8208c2ecf20Sopenharmony_ci		IS_G4X(dev_priv) || IS_GEN(dev_priv, 2) ||
8218c2ecf20Sopenharmony_ci		crtc->mode_flags & I915_MODE_FLAG_USE_SCANLINE_COUNTER;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm, !mode->crtc_clock)) {
8248c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm,
8258c2ecf20Sopenharmony_ci			"trying to get scanoutpos for disabled "
8268c2ecf20Sopenharmony_ci			"pipe %c\n", pipe_name(pipe));
8278c2ecf20Sopenharmony_ci		return false;
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	htotal = mode->crtc_htotal;
8318c2ecf20Sopenharmony_ci	hsync_start = mode->crtc_hsync_start;
8328c2ecf20Sopenharmony_ci	vtotal = mode->crtc_vtotal;
8338c2ecf20Sopenharmony_ci	vbl_start = mode->crtc_vblank_start;
8348c2ecf20Sopenharmony_ci	vbl_end = mode->crtc_vblank_end;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
8378c2ecf20Sopenharmony_ci		vbl_start = DIV_ROUND_UP(vbl_start, 2);
8388c2ecf20Sopenharmony_ci		vbl_end /= 2;
8398c2ecf20Sopenharmony_ci		vtotal /= 2;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	/*
8438c2ecf20Sopenharmony_ci	 * Lock uncore.lock, as we will do multiple timing critical raw
8448c2ecf20Sopenharmony_ci	 * register reads, potentially with preemption disabled, so the
8458c2ecf20Sopenharmony_ci	 * following code must not block on uncore.lock.
8468c2ecf20Sopenharmony_ci	 */
8478c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	/* Get optional system timestamp before query. */
8528c2ecf20Sopenharmony_ci	if (stime)
8538c2ecf20Sopenharmony_ci		*stime = ktime_get();
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (use_scanline_counter) {
8568c2ecf20Sopenharmony_ci		/* No obvious pixelcount register. Only query vertical
8578c2ecf20Sopenharmony_ci		 * scanout position from Display scan line register.
8588c2ecf20Sopenharmony_ci		 */
8598c2ecf20Sopenharmony_ci		position = __intel_get_crtc_scanline(crtc);
8608c2ecf20Sopenharmony_ci	} else {
8618c2ecf20Sopenharmony_ci		/* Have access to pixelcount since start of frame.
8628c2ecf20Sopenharmony_ci		 * We can split this into vertical and horizontal
8638c2ecf20Sopenharmony_ci		 * scanout position.
8648c2ecf20Sopenharmony_ci		 */
8658c2ecf20Sopenharmony_ci		position = (intel_de_read_fw(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci		/* convert to pixel counts */
8688c2ecf20Sopenharmony_ci		vbl_start *= htotal;
8698c2ecf20Sopenharmony_ci		vbl_end *= htotal;
8708c2ecf20Sopenharmony_ci		vtotal *= htotal;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci		/*
8738c2ecf20Sopenharmony_ci		 * In interlaced modes, the pixel counter counts all pixels,
8748c2ecf20Sopenharmony_ci		 * so one field will have htotal more pixels. In order to avoid
8758c2ecf20Sopenharmony_ci		 * the reported position from jumping backwards when the pixel
8768c2ecf20Sopenharmony_ci		 * counter is beyond the length of the shorter field, just
8778c2ecf20Sopenharmony_ci		 * clamp the position the length of the shorter field. This
8788c2ecf20Sopenharmony_ci		 * matches how the scanline counter based position works since
8798c2ecf20Sopenharmony_ci		 * the scanline counter doesn't count the two half lines.
8808c2ecf20Sopenharmony_ci		 */
8818c2ecf20Sopenharmony_ci		if (position >= vtotal)
8828c2ecf20Sopenharmony_ci			position = vtotal - 1;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		/*
8858c2ecf20Sopenharmony_ci		 * Start of vblank interrupt is triggered at start of hsync,
8868c2ecf20Sopenharmony_ci		 * just prior to the first active line of vblank. However we
8878c2ecf20Sopenharmony_ci		 * consider lines to start at the leading edge of horizontal
8888c2ecf20Sopenharmony_ci		 * active. So, should we get here before we've crossed into
8898c2ecf20Sopenharmony_ci		 * the horizontal active of the first line in vblank, we would
8908c2ecf20Sopenharmony_ci		 * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
8918c2ecf20Sopenharmony_ci		 * always add htotal-hsync_start to the current pixel position.
8928c2ecf20Sopenharmony_ci		 */
8938c2ecf20Sopenharmony_ci		position = (position + htotal - hsync_start) % vtotal;
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	/* Get optional system timestamp after query. */
8978c2ecf20Sopenharmony_ci	if (etime)
8988c2ecf20Sopenharmony_ci		*etime = ktime_get();
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	/* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/*
9058c2ecf20Sopenharmony_ci	 * While in vblank, position will be negative
9068c2ecf20Sopenharmony_ci	 * counting up towards 0 at vbl_end. And outside
9078c2ecf20Sopenharmony_ci	 * vblank, position will be positive counting
9088c2ecf20Sopenharmony_ci	 * up since vbl_end.
9098c2ecf20Sopenharmony_ci	 */
9108c2ecf20Sopenharmony_ci	if (position >= vbl_start)
9118c2ecf20Sopenharmony_ci		position -= vbl_end;
9128c2ecf20Sopenharmony_ci	else
9138c2ecf20Sopenharmony_ci		position += vtotal - vbl_end;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (use_scanline_counter) {
9168c2ecf20Sopenharmony_ci		*vpos = position;
9178c2ecf20Sopenharmony_ci		*hpos = 0;
9188c2ecf20Sopenharmony_ci	} else {
9198c2ecf20Sopenharmony_ci		*vpos = position / htotal;
9208c2ecf20Sopenharmony_ci		*hpos = position - (*vpos * htotal);
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	return true;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_cibool intel_crtc_get_vblank_timestamp(struct drm_crtc *crtc, int *max_error,
9278c2ecf20Sopenharmony_ci				     ktime_t *vblank_time, bool in_vblank_irq)
9288c2ecf20Sopenharmony_ci{
9298c2ecf20Sopenharmony_ci	return drm_crtc_vblank_helper_get_vblank_timestamp_internal(
9308c2ecf20Sopenharmony_ci		crtc, max_error, vblank_time, in_vblank_irq,
9318c2ecf20Sopenharmony_ci		i915_get_crtc_scanoutpos);
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ciint intel_get_crtc_scanline(struct intel_crtc *crtc)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
9378c2ecf20Sopenharmony_ci	unsigned long irqflags;
9388c2ecf20Sopenharmony_ci	int position;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
9418c2ecf20Sopenharmony_ci	position = __intel_get_crtc_scanline(crtc);
9428c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	return position;
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci/**
9488c2ecf20Sopenharmony_ci * ivb_parity_work - Workqueue called when a parity error interrupt
9498c2ecf20Sopenharmony_ci * occurred.
9508c2ecf20Sopenharmony_ci * @work: workqueue struct
9518c2ecf20Sopenharmony_ci *
9528c2ecf20Sopenharmony_ci * Doesn't actually do anything except notify userspace. As a consequence of
9538c2ecf20Sopenharmony_ci * this event, userspace should try to remap the bad rows since statistically
9548c2ecf20Sopenharmony_ci * it is likely the same row is more likely to go bad again.
9558c2ecf20Sopenharmony_ci */
9568c2ecf20Sopenharmony_cistatic void ivb_parity_work(struct work_struct *work)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv =
9598c2ecf20Sopenharmony_ci		container_of(work, typeof(*dev_priv), l3_parity.error_work);
9608c2ecf20Sopenharmony_ci	struct intel_gt *gt = &dev_priv->gt;
9618c2ecf20Sopenharmony_ci	u32 error_status, row, bank, subbank;
9628c2ecf20Sopenharmony_ci	char *parity_event[6];
9638c2ecf20Sopenharmony_ci	u32 misccpctl;
9648c2ecf20Sopenharmony_ci	u8 slice = 0;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/* We must turn off DOP level clock gating to access the L3 registers.
9678c2ecf20Sopenharmony_ci	 * In order to prevent a get/put style interface, acquire struct mutex
9688c2ecf20Sopenharmony_ci	 * any time we access those registers.
9698c2ecf20Sopenharmony_ci	 */
9708c2ecf20Sopenharmony_ci	mutex_lock(&dev_priv->drm.struct_mutex);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	/* If we've screwed up tracking, just let the interrupt fire again */
9738c2ecf20Sopenharmony_ci	if (drm_WARN_ON(&dev_priv->drm, !dev_priv->l3_parity.which_slice))
9748c2ecf20Sopenharmony_ci		goto out;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	misccpctl = I915_READ(GEN7_MISCCPCTL);
9778c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
9788c2ecf20Sopenharmony_ci	POSTING_READ(GEN7_MISCCPCTL);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
9818c2ecf20Sopenharmony_ci		i915_reg_t reg;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		slice--;
9848c2ecf20Sopenharmony_ci		if (drm_WARN_ON_ONCE(&dev_priv->drm,
9858c2ecf20Sopenharmony_ci				     slice >= NUM_L3_SLICES(dev_priv)))
9868c2ecf20Sopenharmony_ci			break;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		dev_priv->l3_parity.which_slice &= ~(1<<slice);
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		reg = GEN7_L3CDERRST1(slice);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci		error_status = I915_READ(reg);
9938c2ecf20Sopenharmony_ci		row = GEN7_PARITY_ERROR_ROW(error_status);
9948c2ecf20Sopenharmony_ci		bank = GEN7_PARITY_ERROR_BANK(error_status);
9958c2ecf20Sopenharmony_ci		subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci		I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE);
9988c2ecf20Sopenharmony_ci		POSTING_READ(reg);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci		parity_event[0] = I915_L3_PARITY_UEVENT "=1";
10018c2ecf20Sopenharmony_ci		parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
10028c2ecf20Sopenharmony_ci		parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
10038c2ecf20Sopenharmony_ci		parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
10048c2ecf20Sopenharmony_ci		parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice);
10058c2ecf20Sopenharmony_ci		parity_event[5] = NULL;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci		kobject_uevent_env(&dev_priv->drm.primary->kdev->kobj,
10088c2ecf20Sopenharmony_ci				   KOBJ_CHANGE, parity_event);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci		DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
10118c2ecf20Sopenharmony_ci			  slice, row, bank, subbank);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci		kfree(parity_event[4]);
10148c2ecf20Sopenharmony_ci		kfree(parity_event[3]);
10158c2ecf20Sopenharmony_ci		kfree(parity_event[2]);
10168c2ecf20Sopenharmony_ci		kfree(parity_event[1]);
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_MISCCPCTL, misccpctl);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ciout:
10228c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, dev_priv->l3_parity.which_slice);
10238c2ecf20Sopenharmony_ci	spin_lock_irq(&gt->irq_lock);
10248c2ecf20Sopenharmony_ci	gen5_gt_enable_irq(gt, GT_PARITY_ERROR(dev_priv));
10258c2ecf20Sopenharmony_ci	spin_unlock_irq(&gt->irq_lock);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	mutex_unlock(&dev_priv->drm.struct_mutex);
10288c2ecf20Sopenharmony_ci}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_cistatic bool gen11_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
10318c2ecf20Sopenharmony_ci{
10328c2ecf20Sopenharmony_ci	switch (pin) {
10338c2ecf20Sopenharmony_ci	case HPD_PORT_TC1:
10348c2ecf20Sopenharmony_ci		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC1);
10358c2ecf20Sopenharmony_ci	case HPD_PORT_TC2:
10368c2ecf20Sopenharmony_ci		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC2);
10378c2ecf20Sopenharmony_ci	case HPD_PORT_TC3:
10388c2ecf20Sopenharmony_ci		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC3);
10398c2ecf20Sopenharmony_ci	case HPD_PORT_TC4:
10408c2ecf20Sopenharmony_ci		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC4);
10418c2ecf20Sopenharmony_ci	case HPD_PORT_TC5:
10428c2ecf20Sopenharmony_ci		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC5);
10438c2ecf20Sopenharmony_ci	case HPD_PORT_TC6:
10448c2ecf20Sopenharmony_ci		return val & GEN11_HOTPLUG_CTL_LONG_DETECT(PORT_TC6);
10458c2ecf20Sopenharmony_ci	default:
10468c2ecf20Sopenharmony_ci		return false;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic bool bxt_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	switch (pin) {
10538c2ecf20Sopenharmony_ci	case HPD_PORT_A:
10548c2ecf20Sopenharmony_ci		return val & PORTA_HOTPLUG_LONG_DETECT;
10558c2ecf20Sopenharmony_ci	case HPD_PORT_B:
10568c2ecf20Sopenharmony_ci		return val & PORTB_HOTPLUG_LONG_DETECT;
10578c2ecf20Sopenharmony_ci	case HPD_PORT_C:
10588c2ecf20Sopenharmony_ci		return val & PORTC_HOTPLUG_LONG_DETECT;
10598c2ecf20Sopenharmony_ci	default:
10608c2ecf20Sopenharmony_ci		return false;
10618c2ecf20Sopenharmony_ci	}
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic bool icp_ddi_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	switch (pin) {
10678c2ecf20Sopenharmony_ci	case HPD_PORT_A:
10688c2ecf20Sopenharmony_ci		return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_A);
10698c2ecf20Sopenharmony_ci	case HPD_PORT_B:
10708c2ecf20Sopenharmony_ci		return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_B);
10718c2ecf20Sopenharmony_ci	case HPD_PORT_C:
10728c2ecf20Sopenharmony_ci		return val & SHOTPLUG_CTL_DDI_HPD_LONG_DETECT(PORT_C);
10738c2ecf20Sopenharmony_ci	default:
10748c2ecf20Sopenharmony_ci		return false;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cistatic bool icp_tc_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
10798c2ecf20Sopenharmony_ci{
10808c2ecf20Sopenharmony_ci	switch (pin) {
10818c2ecf20Sopenharmony_ci	case HPD_PORT_TC1:
10828c2ecf20Sopenharmony_ci		return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1);
10838c2ecf20Sopenharmony_ci	case HPD_PORT_TC2:
10848c2ecf20Sopenharmony_ci		return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2);
10858c2ecf20Sopenharmony_ci	case HPD_PORT_TC3:
10868c2ecf20Sopenharmony_ci		return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3);
10878c2ecf20Sopenharmony_ci	case HPD_PORT_TC4:
10888c2ecf20Sopenharmony_ci		return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4);
10898c2ecf20Sopenharmony_ci	case HPD_PORT_TC5:
10908c2ecf20Sopenharmony_ci		return val & ICP_TC_HPD_LONG_DETECT(PORT_TC5);
10918c2ecf20Sopenharmony_ci	case HPD_PORT_TC6:
10928c2ecf20Sopenharmony_ci		return val & ICP_TC_HPD_LONG_DETECT(PORT_TC6);
10938c2ecf20Sopenharmony_ci	default:
10948c2ecf20Sopenharmony_ci		return false;
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic bool spt_port_hotplug2_long_detect(enum hpd_pin pin, u32 val)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	switch (pin) {
11018c2ecf20Sopenharmony_ci	case HPD_PORT_E:
11028c2ecf20Sopenharmony_ci		return val & PORTE_HOTPLUG_LONG_DETECT;
11038c2ecf20Sopenharmony_ci	default:
11048c2ecf20Sopenharmony_ci		return false;
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cistatic bool spt_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	switch (pin) {
11118c2ecf20Sopenharmony_ci	case HPD_PORT_A:
11128c2ecf20Sopenharmony_ci		return val & PORTA_HOTPLUG_LONG_DETECT;
11138c2ecf20Sopenharmony_ci	case HPD_PORT_B:
11148c2ecf20Sopenharmony_ci		return val & PORTB_HOTPLUG_LONG_DETECT;
11158c2ecf20Sopenharmony_ci	case HPD_PORT_C:
11168c2ecf20Sopenharmony_ci		return val & PORTC_HOTPLUG_LONG_DETECT;
11178c2ecf20Sopenharmony_ci	case HPD_PORT_D:
11188c2ecf20Sopenharmony_ci		return val & PORTD_HOTPLUG_LONG_DETECT;
11198c2ecf20Sopenharmony_ci	default:
11208c2ecf20Sopenharmony_ci		return false;
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cistatic bool ilk_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
11258c2ecf20Sopenharmony_ci{
11268c2ecf20Sopenharmony_ci	switch (pin) {
11278c2ecf20Sopenharmony_ci	case HPD_PORT_A:
11288c2ecf20Sopenharmony_ci		return val & DIGITAL_PORTA_HOTPLUG_LONG_DETECT;
11298c2ecf20Sopenharmony_ci	default:
11308c2ecf20Sopenharmony_ci		return false;
11318c2ecf20Sopenharmony_ci	}
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_cistatic bool pch_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
11358c2ecf20Sopenharmony_ci{
11368c2ecf20Sopenharmony_ci	switch (pin) {
11378c2ecf20Sopenharmony_ci	case HPD_PORT_B:
11388c2ecf20Sopenharmony_ci		return val & PORTB_HOTPLUG_LONG_DETECT;
11398c2ecf20Sopenharmony_ci	case HPD_PORT_C:
11408c2ecf20Sopenharmony_ci		return val & PORTC_HOTPLUG_LONG_DETECT;
11418c2ecf20Sopenharmony_ci	case HPD_PORT_D:
11428c2ecf20Sopenharmony_ci		return val & PORTD_HOTPLUG_LONG_DETECT;
11438c2ecf20Sopenharmony_ci	default:
11448c2ecf20Sopenharmony_ci		return false;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_cistatic bool i9xx_port_hotplug_long_detect(enum hpd_pin pin, u32 val)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	switch (pin) {
11518c2ecf20Sopenharmony_ci	case HPD_PORT_B:
11528c2ecf20Sopenharmony_ci		return val & PORTB_HOTPLUG_INT_LONG_PULSE;
11538c2ecf20Sopenharmony_ci	case HPD_PORT_C:
11548c2ecf20Sopenharmony_ci		return val & PORTC_HOTPLUG_INT_LONG_PULSE;
11558c2ecf20Sopenharmony_ci	case HPD_PORT_D:
11568c2ecf20Sopenharmony_ci		return val & PORTD_HOTPLUG_INT_LONG_PULSE;
11578c2ecf20Sopenharmony_ci	default:
11588c2ecf20Sopenharmony_ci		return false;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci}
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci/*
11638c2ecf20Sopenharmony_ci * Get a bit mask of pins that have triggered, and which ones may be long.
11648c2ecf20Sopenharmony_ci * This can be called multiple times with the same masks to accumulate
11658c2ecf20Sopenharmony_ci * hotplug detection results from several registers.
11668c2ecf20Sopenharmony_ci *
11678c2ecf20Sopenharmony_ci * Note that the caller is expected to zero out the masks initially.
11688c2ecf20Sopenharmony_ci */
11698c2ecf20Sopenharmony_cistatic void intel_get_hpd_pins(struct drm_i915_private *dev_priv,
11708c2ecf20Sopenharmony_ci			       u32 *pin_mask, u32 *long_mask,
11718c2ecf20Sopenharmony_ci			       u32 hotplug_trigger, u32 dig_hotplug_reg,
11728c2ecf20Sopenharmony_ci			       const u32 hpd[HPD_NUM_PINS],
11738c2ecf20Sopenharmony_ci			       bool long_pulse_detect(enum hpd_pin pin, u32 val))
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	enum hpd_pin pin;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	BUILD_BUG_ON(BITS_PER_TYPE(*pin_mask) < HPD_NUM_PINS);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	for_each_hpd_pin(pin) {
11808c2ecf20Sopenharmony_ci		if ((hpd[pin] & hotplug_trigger) == 0)
11818c2ecf20Sopenharmony_ci			continue;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci		*pin_mask |= BIT(pin);
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci		if (long_pulse_detect(pin, dig_hotplug_reg))
11868c2ecf20Sopenharmony_ci			*long_mask |= BIT(pin);
11878c2ecf20Sopenharmony_ci	}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	drm_dbg(&dev_priv->drm,
11908c2ecf20Sopenharmony_ci		"hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x, long 0x%08x\n",
11918c2ecf20Sopenharmony_ci		hotplug_trigger, dig_hotplug_reg, *pin_mask, *long_mask);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_cistatic void gmbus_irq_handler(struct drm_i915_private *dev_priv)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	wake_up_all(&dev_priv->gmbus_wait_queue);
11988c2ecf20Sopenharmony_ci}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_cistatic void dp_aux_irq_handler(struct drm_i915_private *dev_priv)
12018c2ecf20Sopenharmony_ci{
12028c2ecf20Sopenharmony_ci	wake_up_all(&dev_priv->gmbus_wait_queue);
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
12068c2ecf20Sopenharmony_cistatic void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
12078c2ecf20Sopenharmony_ci					 enum pipe pipe,
12088c2ecf20Sopenharmony_ci					 u32 crc0, u32 crc1,
12098c2ecf20Sopenharmony_ci					 u32 crc2, u32 crc3,
12108c2ecf20Sopenharmony_ci					 u32 crc4)
12118c2ecf20Sopenharmony_ci{
12128c2ecf20Sopenharmony_ci	struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
12138c2ecf20Sopenharmony_ci	struct intel_pipe_crc *pipe_crc = &crtc->pipe_crc;
12148c2ecf20Sopenharmony_ci	u32 crcs[5] = { crc0, crc1, crc2, crc3, crc4 };
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	trace_intel_pipe_crc(crtc, crcs);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	spin_lock(&pipe_crc->lock);
12198c2ecf20Sopenharmony_ci	/*
12208c2ecf20Sopenharmony_ci	 * For some not yet identified reason, the first CRC is
12218c2ecf20Sopenharmony_ci	 * bonkers. So let's just wait for the next vblank and read
12228c2ecf20Sopenharmony_ci	 * out the buggy result.
12238c2ecf20Sopenharmony_ci	 *
12248c2ecf20Sopenharmony_ci	 * On GEN8+ sometimes the second CRC is bonkers as well, so
12258c2ecf20Sopenharmony_ci	 * don't trust that one either.
12268c2ecf20Sopenharmony_ci	 */
12278c2ecf20Sopenharmony_ci	if (pipe_crc->skipped <= 0 ||
12288c2ecf20Sopenharmony_ci	    (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
12298c2ecf20Sopenharmony_ci		pipe_crc->skipped++;
12308c2ecf20Sopenharmony_ci		spin_unlock(&pipe_crc->lock);
12318c2ecf20Sopenharmony_ci		return;
12328c2ecf20Sopenharmony_ci	}
12338c2ecf20Sopenharmony_ci	spin_unlock(&pipe_crc->lock);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	drm_crtc_add_crc_entry(&crtc->base, true,
12368c2ecf20Sopenharmony_ci				drm_crtc_accurate_vblank_count(&crtc->base),
12378c2ecf20Sopenharmony_ci				crcs);
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ci#else
12408c2ecf20Sopenharmony_cistatic inline void
12418c2ecf20Sopenharmony_cidisplay_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
12428c2ecf20Sopenharmony_ci			     enum pipe pipe,
12438c2ecf20Sopenharmony_ci			     u32 crc0, u32 crc1,
12448c2ecf20Sopenharmony_ci			     u32 crc2, u32 crc3,
12458c2ecf20Sopenharmony_ci			     u32 crc4) {}
12468c2ecf20Sopenharmony_ci#endif
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_cistatic void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
12508c2ecf20Sopenharmony_ci				     enum pipe pipe)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	display_pipe_crc_irq_handler(dev_priv, pipe,
12538c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
12548c2ecf20Sopenharmony_ci				     0, 0, 0, 0);
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_cistatic void ivb_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
12588c2ecf20Sopenharmony_ci				     enum pipe pipe)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci	display_pipe_crc_irq_handler(dev_priv, pipe,
12618c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
12628c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_2_IVB(pipe)),
12638c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_3_IVB(pipe)),
12648c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_4_IVB(pipe)),
12658c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_5_IVB(pipe)));
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_cistatic void i9xx_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
12698c2ecf20Sopenharmony_ci				      enum pipe pipe)
12708c2ecf20Sopenharmony_ci{
12718c2ecf20Sopenharmony_ci	u32 res1, res2;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 3)
12748c2ecf20Sopenharmony_ci		res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe));
12758c2ecf20Sopenharmony_ci	else
12768c2ecf20Sopenharmony_ci		res1 = 0;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
12798c2ecf20Sopenharmony_ci		res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe));
12808c2ecf20Sopenharmony_ci	else
12818c2ecf20Sopenharmony_ci		res2 = 0;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	display_pipe_crc_irq_handler(dev_priv, pipe,
12848c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_RED(pipe)),
12858c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_GREEN(pipe)),
12868c2ecf20Sopenharmony_ci				     I915_READ(PIPE_CRC_RES_BLUE(pipe)),
12878c2ecf20Sopenharmony_ci				     res1, res2);
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_cistatic void i9xx_pipestat_irq_reset(struct drm_i915_private *dev_priv)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	enum pipe pipe;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
12958c2ecf20Sopenharmony_ci		I915_WRITE(PIPESTAT(pipe),
12968c2ecf20Sopenharmony_ci			   PIPESTAT_INT_STATUS_MASK |
12978c2ecf20Sopenharmony_ci			   PIPE_FIFO_UNDERRUN_STATUS);
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci		dev_priv->pipestat_irq_mask[pipe] = 0;
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_cistatic void i9xx_pipestat_irq_ack(struct drm_i915_private *dev_priv,
13048c2ecf20Sopenharmony_ci				  u32 iir, u32 pipe_stats[I915_MAX_PIPES])
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	enum pipe pipe;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	spin_lock(&dev_priv->irq_lock);
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	if (!dev_priv->display_irqs_enabled) {
13118c2ecf20Sopenharmony_ci		spin_unlock(&dev_priv->irq_lock);
13128c2ecf20Sopenharmony_ci		return;
13138c2ecf20Sopenharmony_ci	}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
13168c2ecf20Sopenharmony_ci		i915_reg_t reg;
13178c2ecf20Sopenharmony_ci		u32 status_mask, enable_mask, iir_bit = 0;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci		/*
13208c2ecf20Sopenharmony_ci		 * PIPESTAT bits get signalled even when the interrupt is
13218c2ecf20Sopenharmony_ci		 * disabled with the mask bits, and some of the status bits do
13228c2ecf20Sopenharmony_ci		 * not generate interrupts at all (like the underrun bit). Hence
13238c2ecf20Sopenharmony_ci		 * we need to be careful that we only handle what we want to
13248c2ecf20Sopenharmony_ci		 * handle.
13258c2ecf20Sopenharmony_ci		 */
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci		/* fifo underruns are filterered in the underrun handler. */
13288c2ecf20Sopenharmony_ci		status_mask = PIPE_FIFO_UNDERRUN_STATUS;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci		switch (pipe) {
13318c2ecf20Sopenharmony_ci		default:
13328c2ecf20Sopenharmony_ci		case PIPE_A:
13338c2ecf20Sopenharmony_ci			iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
13348c2ecf20Sopenharmony_ci			break;
13358c2ecf20Sopenharmony_ci		case PIPE_B:
13368c2ecf20Sopenharmony_ci			iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
13378c2ecf20Sopenharmony_ci			break;
13388c2ecf20Sopenharmony_ci		case PIPE_C:
13398c2ecf20Sopenharmony_ci			iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
13408c2ecf20Sopenharmony_ci			break;
13418c2ecf20Sopenharmony_ci		}
13428c2ecf20Sopenharmony_ci		if (iir & iir_bit)
13438c2ecf20Sopenharmony_ci			status_mask |= dev_priv->pipestat_irq_mask[pipe];
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci		if (!status_mask)
13468c2ecf20Sopenharmony_ci			continue;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		reg = PIPESTAT(pipe);
13498c2ecf20Sopenharmony_ci		pipe_stats[pipe] = I915_READ(reg) & status_mask;
13508c2ecf20Sopenharmony_ci		enable_mask = i915_pipestat_enable_mask(dev_priv, pipe);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci		/*
13538c2ecf20Sopenharmony_ci		 * Clear the PIPE*STAT regs before the IIR
13548c2ecf20Sopenharmony_ci		 *
13558c2ecf20Sopenharmony_ci		 * Toggle the enable bits to make sure we get an
13568c2ecf20Sopenharmony_ci		 * edge in the ISR pipe event bit if we don't clear
13578c2ecf20Sopenharmony_ci		 * all the enabled status bits. Otherwise the edge
13588c2ecf20Sopenharmony_ci		 * triggered IIR on i965/g4x wouldn't notice that
13598c2ecf20Sopenharmony_ci		 * an interrupt is still pending.
13608c2ecf20Sopenharmony_ci		 */
13618c2ecf20Sopenharmony_ci		if (pipe_stats[pipe]) {
13628c2ecf20Sopenharmony_ci			I915_WRITE(reg, pipe_stats[pipe]);
13638c2ecf20Sopenharmony_ci			I915_WRITE(reg, enable_mask);
13648c2ecf20Sopenharmony_ci		}
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci	spin_unlock(&dev_priv->irq_lock);
13678c2ecf20Sopenharmony_ci}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cistatic void i8xx_pipestat_irq_handler(struct drm_i915_private *dev_priv,
13708c2ecf20Sopenharmony_ci				      u16 iir, u32 pipe_stats[I915_MAX_PIPES])
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	enum pipe pipe;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
13758c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
13768c2ecf20Sopenharmony_ci			intel_handle_vblank(dev_priv, pipe);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
13798c2ecf20Sopenharmony_ci			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
13828c2ecf20Sopenharmony_ci			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
13838c2ecf20Sopenharmony_ci	}
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_cistatic void i915_pipestat_irq_handler(struct drm_i915_private *dev_priv,
13878c2ecf20Sopenharmony_ci				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	bool blc_event = false;
13908c2ecf20Sopenharmony_ci	enum pipe pipe;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
13938c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
13948c2ecf20Sopenharmony_ci			intel_handle_vblank(dev_priv, pipe);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
13978c2ecf20Sopenharmony_ci			blc_event = true;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
14008c2ecf20Sopenharmony_ci			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
14038c2ecf20Sopenharmony_ci			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
14048c2ecf20Sopenharmony_ci	}
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	if (blc_event || (iir & I915_ASLE_INTERRUPT))
14078c2ecf20Sopenharmony_ci		intel_opregion_asle_intr(dev_priv);
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_cistatic void i965_pipestat_irq_handler(struct drm_i915_private *dev_priv,
14118c2ecf20Sopenharmony_ci				      u32 iir, u32 pipe_stats[I915_MAX_PIPES])
14128c2ecf20Sopenharmony_ci{
14138c2ecf20Sopenharmony_ci	bool blc_event = false;
14148c2ecf20Sopenharmony_ci	enum pipe pipe;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
14178c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
14188c2ecf20Sopenharmony_ci			intel_handle_vblank(dev_priv, pipe);
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
14218c2ecf20Sopenharmony_ci			blc_event = true;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
14248c2ecf20Sopenharmony_ci			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
14278c2ecf20Sopenharmony_ci			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
14288c2ecf20Sopenharmony_ci	}
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (blc_event || (iir & I915_ASLE_INTERRUPT))
14318c2ecf20Sopenharmony_ci		intel_opregion_asle_intr(dev_priv);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
14348c2ecf20Sopenharmony_ci		gmbus_irq_handler(dev_priv);
14358c2ecf20Sopenharmony_ci}
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_cistatic void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
14388c2ecf20Sopenharmony_ci					    u32 pipe_stats[I915_MAX_PIPES])
14398c2ecf20Sopenharmony_ci{
14408c2ecf20Sopenharmony_ci	enum pipe pipe;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
14438c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
14448c2ecf20Sopenharmony_ci			intel_handle_vblank(dev_priv, pipe);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
14478c2ecf20Sopenharmony_ci			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci		if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
14508c2ecf20Sopenharmony_ci			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
14518c2ecf20Sopenharmony_ci	}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
14548c2ecf20Sopenharmony_ci		gmbus_irq_handler(dev_priv);
14558c2ecf20Sopenharmony_ci}
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_cistatic u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv)
14588c2ecf20Sopenharmony_ci{
14598c2ecf20Sopenharmony_ci	u32 hotplug_status = 0, hotplug_status_mask;
14608c2ecf20Sopenharmony_ci	int i;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	if (IS_G4X(dev_priv) ||
14638c2ecf20Sopenharmony_ci	    IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
14648c2ecf20Sopenharmony_ci		hotplug_status_mask = HOTPLUG_INT_STATUS_G4X |
14658c2ecf20Sopenharmony_ci			DP_AUX_CHANNEL_MASK_INT_STATUS_G4X;
14668c2ecf20Sopenharmony_ci	else
14678c2ecf20Sopenharmony_ci		hotplug_status_mask = HOTPLUG_INT_STATUS_I915;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	/*
14708c2ecf20Sopenharmony_ci	 * We absolutely have to clear all the pending interrupt
14718c2ecf20Sopenharmony_ci	 * bits in PORT_HOTPLUG_STAT. Otherwise the ISR port
14728c2ecf20Sopenharmony_ci	 * interrupt bit won't have an edge, and the i965/g4x
14738c2ecf20Sopenharmony_ci	 * edge triggered IIR will not notice that an interrupt
14748c2ecf20Sopenharmony_ci	 * is still pending. We can't use PORT_HOTPLUG_EN to
14758c2ecf20Sopenharmony_ci	 * guarantee the edge as the act of toggling the enable
14768c2ecf20Sopenharmony_ci	 * bits can itself generate a new hotplug interrupt :(
14778c2ecf20Sopenharmony_ci	 */
14788c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
14798c2ecf20Sopenharmony_ci		u32 tmp = I915_READ(PORT_HOTPLUG_STAT) & hotplug_status_mask;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci		if (tmp == 0)
14828c2ecf20Sopenharmony_ci			return hotplug_status;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci		hotplug_status |= tmp;
14858c2ecf20Sopenharmony_ci		I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
14868c2ecf20Sopenharmony_ci	}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	drm_WARN_ONCE(&dev_priv->drm, 1,
14898c2ecf20Sopenharmony_ci		      "PORT_HOTPLUG_STAT did not clear (0x%08x)\n",
14908c2ecf20Sopenharmony_ci		      I915_READ(PORT_HOTPLUG_STAT));
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	return hotplug_status;
14938c2ecf20Sopenharmony_ci}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_cistatic void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
14968c2ecf20Sopenharmony_ci				 u32 hotplug_status)
14978c2ecf20Sopenharmony_ci{
14988c2ecf20Sopenharmony_ci	u32 pin_mask = 0, long_mask = 0;
14998c2ecf20Sopenharmony_ci	u32 hotplug_trigger;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	if (IS_G4X(dev_priv) ||
15028c2ecf20Sopenharmony_ci	    IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
15038c2ecf20Sopenharmony_ci		hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
15048c2ecf20Sopenharmony_ci	else
15058c2ecf20Sopenharmony_ci		hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	if (hotplug_trigger) {
15088c2ecf20Sopenharmony_ci		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
15098c2ecf20Sopenharmony_ci				   hotplug_trigger, hotplug_trigger,
15108c2ecf20Sopenharmony_ci				   dev_priv->hotplug.hpd,
15118c2ecf20Sopenharmony_ci				   i9xx_port_hotplug_long_detect);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if ((IS_G4X(dev_priv) ||
15178c2ecf20Sopenharmony_ci	     IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
15188c2ecf20Sopenharmony_ci	    hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
15198c2ecf20Sopenharmony_ci		dp_aux_irq_handler(dev_priv);
15208c2ecf20Sopenharmony_ci}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_cistatic irqreturn_t valleyview_irq_handler(int irq, void *arg)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = arg;
15258c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv))
15288c2ecf20Sopenharmony_ci		return IRQ_NONE;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
15318c2ecf20Sopenharmony_ci	disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	do {
15348c2ecf20Sopenharmony_ci		u32 iir, gt_iir, pm_iir;
15358c2ecf20Sopenharmony_ci		u32 pipe_stats[I915_MAX_PIPES] = {};
15368c2ecf20Sopenharmony_ci		u32 hotplug_status = 0;
15378c2ecf20Sopenharmony_ci		u32 ier = 0;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci		gt_iir = I915_READ(GTIIR);
15408c2ecf20Sopenharmony_ci		pm_iir = I915_READ(GEN6_PMIIR);
15418c2ecf20Sopenharmony_ci		iir = I915_READ(VLV_IIR);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		if (gt_iir == 0 && pm_iir == 0 && iir == 0)
15448c2ecf20Sopenharmony_ci			break;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci		/*
15498c2ecf20Sopenharmony_ci		 * Theory on interrupt generation, based on empirical evidence:
15508c2ecf20Sopenharmony_ci		 *
15518c2ecf20Sopenharmony_ci		 * x = ((VLV_IIR & VLV_IER) ||
15528c2ecf20Sopenharmony_ci		 *      (((GT_IIR & GT_IER) || (GEN6_PMIIR & GEN6_PMIER)) &&
15538c2ecf20Sopenharmony_ci		 *       (VLV_MASTER_IER & MASTER_INTERRUPT_ENABLE)));
15548c2ecf20Sopenharmony_ci		 *
15558c2ecf20Sopenharmony_ci		 * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
15568c2ecf20Sopenharmony_ci		 * Hence we clear MASTER_INTERRUPT_ENABLE and VLV_IER to
15578c2ecf20Sopenharmony_ci		 * guarantee the CPU interrupt will be raised again even if we
15588c2ecf20Sopenharmony_ci		 * don't end up clearing all the VLV_IIR, GT_IIR, GEN6_PMIIR
15598c2ecf20Sopenharmony_ci		 * bits this time around.
15608c2ecf20Sopenharmony_ci		 */
15618c2ecf20Sopenharmony_ci		I915_WRITE(VLV_MASTER_IER, 0);
15628c2ecf20Sopenharmony_ci		ier = I915_READ(VLV_IER);
15638c2ecf20Sopenharmony_ci		I915_WRITE(VLV_IER, 0);
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci		if (gt_iir)
15668c2ecf20Sopenharmony_ci			I915_WRITE(GTIIR, gt_iir);
15678c2ecf20Sopenharmony_ci		if (pm_iir)
15688c2ecf20Sopenharmony_ci			I915_WRITE(GEN6_PMIIR, pm_iir);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci		if (iir & I915_DISPLAY_PORT_INTERRUPT)
15718c2ecf20Sopenharmony_ci			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci		/* Call regardless, as some status bits might not be
15748c2ecf20Sopenharmony_ci		 * signalled in iir */
15758c2ecf20Sopenharmony_ci		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
15788c2ecf20Sopenharmony_ci			   I915_LPE_PIPE_B_INTERRUPT))
15798c2ecf20Sopenharmony_ci			intel_lpe_audio_irq_handler(dev_priv);
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci		/*
15828c2ecf20Sopenharmony_ci		 * VLV_IIR is single buffered, and reflects the level
15838c2ecf20Sopenharmony_ci		 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
15848c2ecf20Sopenharmony_ci		 */
15858c2ecf20Sopenharmony_ci		if (iir)
15868c2ecf20Sopenharmony_ci			I915_WRITE(VLV_IIR, iir);
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci		I915_WRITE(VLV_IER, ier);
15898c2ecf20Sopenharmony_ci		I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci		if (gt_iir)
15928c2ecf20Sopenharmony_ci			gen6_gt_irq_handler(&dev_priv->gt, gt_iir);
15938c2ecf20Sopenharmony_ci		if (pm_iir)
15948c2ecf20Sopenharmony_ci			gen6_rps_irq_handler(&dev_priv->gt.rps, pm_iir);
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci		if (hotplug_status)
15978c2ecf20Sopenharmony_ci			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
16008c2ecf20Sopenharmony_ci	} while (0);
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	return ret;
16058c2ecf20Sopenharmony_ci}
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_cistatic irqreturn_t cherryview_irq_handler(int irq, void *arg)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = arg;
16108c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv))
16138c2ecf20Sopenharmony_ci		return IRQ_NONE;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
16168c2ecf20Sopenharmony_ci	disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	do {
16198c2ecf20Sopenharmony_ci		u32 master_ctl, iir;
16208c2ecf20Sopenharmony_ci		u32 pipe_stats[I915_MAX_PIPES] = {};
16218c2ecf20Sopenharmony_ci		u32 hotplug_status = 0;
16228c2ecf20Sopenharmony_ci		u32 ier = 0;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci		master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
16258c2ecf20Sopenharmony_ci		iir = I915_READ(VLV_IIR);
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci		if (master_ctl == 0 && iir == 0)
16288c2ecf20Sopenharmony_ci			break;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci		/*
16338c2ecf20Sopenharmony_ci		 * Theory on interrupt generation, based on empirical evidence:
16348c2ecf20Sopenharmony_ci		 *
16358c2ecf20Sopenharmony_ci		 * x = ((VLV_IIR & VLV_IER) ||
16368c2ecf20Sopenharmony_ci		 *      ((GEN8_MASTER_IRQ & ~GEN8_MASTER_IRQ_CONTROL) &&
16378c2ecf20Sopenharmony_ci		 *       (GEN8_MASTER_IRQ & GEN8_MASTER_IRQ_CONTROL)));
16388c2ecf20Sopenharmony_ci		 *
16398c2ecf20Sopenharmony_ci		 * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
16408c2ecf20Sopenharmony_ci		 * Hence we clear GEN8_MASTER_IRQ_CONTROL and VLV_IER to
16418c2ecf20Sopenharmony_ci		 * guarantee the CPU interrupt will be raised again even if we
16428c2ecf20Sopenharmony_ci		 * don't end up clearing all the VLV_IIR and GEN8_MASTER_IRQ_CONTROL
16438c2ecf20Sopenharmony_ci		 * bits this time around.
16448c2ecf20Sopenharmony_ci		 */
16458c2ecf20Sopenharmony_ci		I915_WRITE(GEN8_MASTER_IRQ, 0);
16468c2ecf20Sopenharmony_ci		ier = I915_READ(VLV_IER);
16478c2ecf20Sopenharmony_ci		I915_WRITE(VLV_IER, 0);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		gen8_gt_irq_handler(&dev_priv->gt, master_ctl);
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci		if (iir & I915_DISPLAY_PORT_INTERRUPT)
16528c2ecf20Sopenharmony_ci			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci		/* Call regardless, as some status bits might not be
16558c2ecf20Sopenharmony_ci		 * signalled in iir */
16568c2ecf20Sopenharmony_ci		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci		if (iir & (I915_LPE_PIPE_A_INTERRUPT |
16598c2ecf20Sopenharmony_ci			   I915_LPE_PIPE_B_INTERRUPT |
16608c2ecf20Sopenharmony_ci			   I915_LPE_PIPE_C_INTERRUPT))
16618c2ecf20Sopenharmony_ci			intel_lpe_audio_irq_handler(dev_priv);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci		/*
16648c2ecf20Sopenharmony_ci		 * VLV_IIR is single buffered, and reflects the level
16658c2ecf20Sopenharmony_ci		 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
16668c2ecf20Sopenharmony_ci		 */
16678c2ecf20Sopenharmony_ci		if (iir)
16688c2ecf20Sopenharmony_ci			I915_WRITE(VLV_IIR, iir);
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci		I915_WRITE(VLV_IER, ier);
16718c2ecf20Sopenharmony_ci		I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci		if (hotplug_status)
16748c2ecf20Sopenharmony_ci			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci		valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
16778c2ecf20Sopenharmony_ci	} while (0);
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	return ret;
16828c2ecf20Sopenharmony_ci}
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_cistatic void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv,
16858c2ecf20Sopenharmony_ci				u32 hotplug_trigger)
16868c2ecf20Sopenharmony_ci{
16878c2ecf20Sopenharmony_ci	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	/*
16908c2ecf20Sopenharmony_ci	 * Somehow the PCH doesn't seem to really ack the interrupt to the CPU
16918c2ecf20Sopenharmony_ci	 * unless we touch the hotplug register, even if hotplug_trigger is
16928c2ecf20Sopenharmony_ci	 * zero. Not acking leads to "The master control interrupt lied (SDE)!"
16938c2ecf20Sopenharmony_ci	 * errors.
16948c2ecf20Sopenharmony_ci	 */
16958c2ecf20Sopenharmony_ci	dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
16968c2ecf20Sopenharmony_ci	if (!hotplug_trigger) {
16978c2ecf20Sopenharmony_ci		u32 mask = PORTA_HOTPLUG_STATUS_MASK |
16988c2ecf20Sopenharmony_ci			PORTD_HOTPLUG_STATUS_MASK |
16998c2ecf20Sopenharmony_ci			PORTC_HOTPLUG_STATUS_MASK |
17008c2ecf20Sopenharmony_ci			PORTB_HOTPLUG_STATUS_MASK;
17018c2ecf20Sopenharmony_ci		dig_hotplug_reg &= ~mask;
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
17058c2ecf20Sopenharmony_ci	if (!hotplug_trigger)
17068c2ecf20Sopenharmony_ci		return;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
17098c2ecf20Sopenharmony_ci			   hotplug_trigger, dig_hotplug_reg,
17108c2ecf20Sopenharmony_ci			   dev_priv->hotplug.pch_hpd,
17118c2ecf20Sopenharmony_ci			   pch_port_hotplug_long_detect);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
17148c2ecf20Sopenharmony_ci}
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_cistatic void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
17178c2ecf20Sopenharmony_ci{
17188c2ecf20Sopenharmony_ci	enum pipe pipe;
17198c2ecf20Sopenharmony_ci	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	ibx_hpd_irq_handler(dev_priv, hotplug_trigger);
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUDIO_POWER_MASK) {
17248c2ecf20Sopenharmony_ci		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
17258c2ecf20Sopenharmony_ci			       SDE_AUDIO_POWER_SHIFT);
17268c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "PCH audio power change on port %d\n",
17278c2ecf20Sopenharmony_ci			port_name(port));
17288c2ecf20Sopenharmony_ci	}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUX_MASK)
17318c2ecf20Sopenharmony_ci		dp_aux_irq_handler(dev_priv);
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	if (pch_iir & SDE_GMBUS)
17348c2ecf20Sopenharmony_ci		gmbus_irq_handler(dev_priv);
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUDIO_HDCP_MASK)
17378c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "PCH HDCP audio interrupt\n");
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUDIO_TRANS_MASK)
17408c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "PCH transcoder audio interrupt\n");
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	if (pch_iir & SDE_POISON)
17438c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm, "PCH poison interrupt\n");
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	if (pch_iir & SDE_FDI_MASK) {
17468c2ecf20Sopenharmony_ci		for_each_pipe(dev_priv, pipe)
17478c2ecf20Sopenharmony_ci			drm_dbg(&dev_priv->drm, "  pipe %c FDI IIR: 0x%08x\n",
17488c2ecf20Sopenharmony_ci				pipe_name(pipe),
17498c2ecf20Sopenharmony_ci				I915_READ(FDI_RX_IIR(pipe)));
17508c2ecf20Sopenharmony_ci	}
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
17538c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "PCH transcoder CRC done interrupt\n");
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
17568c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm,
17578c2ecf20Sopenharmony_ci			"PCH transcoder CRC error interrupt\n");
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	if (pch_iir & SDE_TRANSA_FIFO_UNDER)
17608c2ecf20Sopenharmony_ci		intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_A);
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	if (pch_iir & SDE_TRANSB_FIFO_UNDER)
17638c2ecf20Sopenharmony_ci		intel_pch_fifo_underrun_irq_handler(dev_priv, PIPE_B);
17648c2ecf20Sopenharmony_ci}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_cistatic void ivb_err_int_handler(struct drm_i915_private *dev_priv)
17678c2ecf20Sopenharmony_ci{
17688c2ecf20Sopenharmony_ci	u32 err_int = I915_READ(GEN7_ERR_INT);
17698c2ecf20Sopenharmony_ci	enum pipe pipe;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	if (err_int & ERR_INT_POISON)
17728c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm, "Poison interrupt\n");
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
17758c2ecf20Sopenharmony_ci		if (err_int & ERR_INT_FIFO_UNDERRUN(pipe))
17768c2ecf20Sopenharmony_ci			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci		if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
17798c2ecf20Sopenharmony_ci			if (IS_IVYBRIDGE(dev_priv))
17808c2ecf20Sopenharmony_ci				ivb_pipe_crc_irq_handler(dev_priv, pipe);
17818c2ecf20Sopenharmony_ci			else
17828c2ecf20Sopenharmony_ci				hsw_pipe_crc_irq_handler(dev_priv, pipe);
17838c2ecf20Sopenharmony_ci		}
17848c2ecf20Sopenharmony_ci	}
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	I915_WRITE(GEN7_ERR_INT, err_int);
17878c2ecf20Sopenharmony_ci}
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_cistatic void cpt_serr_int_handler(struct drm_i915_private *dev_priv)
17908c2ecf20Sopenharmony_ci{
17918c2ecf20Sopenharmony_ci	u32 serr_int = I915_READ(SERR_INT);
17928c2ecf20Sopenharmony_ci	enum pipe pipe;
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	if (serr_int & SERR_INT_POISON)
17958c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm, "PCH poison interrupt\n");
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe)
17988c2ecf20Sopenharmony_ci		if (serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pipe))
17998c2ecf20Sopenharmony_ci			intel_pch_fifo_underrun_irq_handler(dev_priv, pipe);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	I915_WRITE(SERR_INT, serr_int);
18028c2ecf20Sopenharmony_ci}
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_cistatic void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
18058c2ecf20Sopenharmony_ci{
18068c2ecf20Sopenharmony_ci	enum pipe pipe;
18078c2ecf20Sopenharmony_ci	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	ibx_hpd_irq_handler(dev_priv, hotplug_trigger);
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
18128c2ecf20Sopenharmony_ci		int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
18138c2ecf20Sopenharmony_ci			       SDE_AUDIO_POWER_SHIFT_CPT);
18148c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "PCH audio power change on port %c\n",
18158c2ecf20Sopenharmony_ci			port_name(port));
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUX_MASK_CPT)
18198c2ecf20Sopenharmony_ci		dp_aux_irq_handler(dev_priv);
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	if (pch_iir & SDE_GMBUS_CPT)
18228c2ecf20Sopenharmony_ci		gmbus_irq_handler(dev_priv);
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
18258c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "Audio CP request interrupt\n");
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	if (pch_iir & SDE_AUDIO_CP_CHG_CPT)
18288c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "Audio CP change interrupt\n");
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	if (pch_iir & SDE_FDI_MASK_CPT) {
18318c2ecf20Sopenharmony_ci		for_each_pipe(dev_priv, pipe)
18328c2ecf20Sopenharmony_ci			drm_dbg(&dev_priv->drm, "  pipe %c FDI IIR: 0x%08x\n",
18338c2ecf20Sopenharmony_ci				pipe_name(pipe),
18348c2ecf20Sopenharmony_ci				I915_READ(FDI_RX_IIR(pipe)));
18358c2ecf20Sopenharmony_ci	}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	if (pch_iir & SDE_ERROR_CPT)
18388c2ecf20Sopenharmony_ci		cpt_serr_int_handler(dev_priv);
18398c2ecf20Sopenharmony_ci}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_cistatic void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
18428c2ecf20Sopenharmony_ci{
18438c2ecf20Sopenharmony_ci	u32 ddi_hotplug_trigger, tc_hotplug_trigger;
18448c2ecf20Sopenharmony_ci	u32 pin_mask = 0, long_mask = 0;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	if (HAS_PCH_TGP(dev_priv)) {
18478c2ecf20Sopenharmony_ci		ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
18488c2ecf20Sopenharmony_ci		tc_hotplug_trigger = pch_iir & SDE_TC_MASK_TGP;
18498c2ecf20Sopenharmony_ci	} else if (HAS_PCH_JSP(dev_priv)) {
18508c2ecf20Sopenharmony_ci		ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_TGP;
18518c2ecf20Sopenharmony_ci		tc_hotplug_trigger = 0;
18528c2ecf20Sopenharmony_ci	} else if (HAS_PCH_MCC(dev_priv)) {
18538c2ecf20Sopenharmony_ci		ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
18548c2ecf20Sopenharmony_ci		tc_hotplug_trigger = pch_iir & SDE_TC_HOTPLUG_ICP(PORT_TC1);
18558c2ecf20Sopenharmony_ci	} else {
18568c2ecf20Sopenharmony_ci		drm_WARN(&dev_priv->drm, !HAS_PCH_ICP(dev_priv),
18578c2ecf20Sopenharmony_ci			 "Unrecognized PCH type 0x%x\n",
18588c2ecf20Sopenharmony_ci			 INTEL_PCH_TYPE(dev_priv));
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci		ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
18618c2ecf20Sopenharmony_ci		tc_hotplug_trigger = pch_iir & SDE_TC_MASK_ICP;
18628c2ecf20Sopenharmony_ci	}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	if (ddi_hotplug_trigger) {
18658c2ecf20Sopenharmony_ci		u32 dig_hotplug_reg;
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci		dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_DDI);
18688c2ecf20Sopenharmony_ci		I915_WRITE(SHOTPLUG_CTL_DDI, dig_hotplug_reg);
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
18718c2ecf20Sopenharmony_ci				   ddi_hotplug_trigger, dig_hotplug_reg,
18728c2ecf20Sopenharmony_ci				   dev_priv->hotplug.pch_hpd,
18738c2ecf20Sopenharmony_ci				   icp_ddi_port_hotplug_long_detect);
18748c2ecf20Sopenharmony_ci	}
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	if (tc_hotplug_trigger) {
18778c2ecf20Sopenharmony_ci		u32 dig_hotplug_reg;
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci		dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_TC);
18808c2ecf20Sopenharmony_ci		I915_WRITE(SHOTPLUG_CTL_TC, dig_hotplug_reg);
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
18838c2ecf20Sopenharmony_ci				   tc_hotplug_trigger, dig_hotplug_reg,
18848c2ecf20Sopenharmony_ci				   dev_priv->hotplug.pch_hpd,
18858c2ecf20Sopenharmony_ci				   icp_tc_port_hotplug_long_detect);
18868c2ecf20Sopenharmony_ci	}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	if (pin_mask)
18898c2ecf20Sopenharmony_ci		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	if (pch_iir & SDE_GMBUS_ICP)
18928c2ecf20Sopenharmony_ci		gmbus_irq_handler(dev_priv);
18938c2ecf20Sopenharmony_ci}
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_cistatic void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
18968c2ecf20Sopenharmony_ci{
18978c2ecf20Sopenharmony_ci	u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
18988c2ecf20Sopenharmony_ci		~SDE_PORTE_HOTPLUG_SPT;
18998c2ecf20Sopenharmony_ci	u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT;
19008c2ecf20Sopenharmony_ci	u32 pin_mask = 0, long_mask = 0;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	if (hotplug_trigger) {
19038c2ecf20Sopenharmony_ci		u32 dig_hotplug_reg;
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
19068c2ecf20Sopenharmony_ci		I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
19098c2ecf20Sopenharmony_ci				   hotplug_trigger, dig_hotplug_reg,
19108c2ecf20Sopenharmony_ci				   dev_priv->hotplug.pch_hpd,
19118c2ecf20Sopenharmony_ci				   spt_port_hotplug_long_detect);
19128c2ecf20Sopenharmony_ci	}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	if (hotplug2_trigger) {
19158c2ecf20Sopenharmony_ci		u32 dig_hotplug_reg;
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci		dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
19188c2ecf20Sopenharmony_ci		I915_WRITE(PCH_PORT_HOTPLUG2, dig_hotplug_reg);
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
19218c2ecf20Sopenharmony_ci				   hotplug2_trigger, dig_hotplug_reg,
19228c2ecf20Sopenharmony_ci				   dev_priv->hotplug.pch_hpd,
19238c2ecf20Sopenharmony_ci				   spt_port_hotplug2_long_detect);
19248c2ecf20Sopenharmony_ci	}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	if (pin_mask)
19278c2ecf20Sopenharmony_ci		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	if (pch_iir & SDE_GMBUS_CPT)
19308c2ecf20Sopenharmony_ci		gmbus_irq_handler(dev_priv);
19318c2ecf20Sopenharmony_ci}
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_cistatic void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv,
19348c2ecf20Sopenharmony_ci				u32 hotplug_trigger)
19358c2ecf20Sopenharmony_ci{
19368c2ecf20Sopenharmony_ci	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
19398c2ecf20Sopenharmony_ci	I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg);
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
19428c2ecf20Sopenharmony_ci			   hotplug_trigger, dig_hotplug_reg,
19438c2ecf20Sopenharmony_ci			   dev_priv->hotplug.hpd,
19448c2ecf20Sopenharmony_ci			   ilk_port_hotplug_long_detect);
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
19478c2ecf20Sopenharmony_ci}
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_cistatic void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
19508c2ecf20Sopenharmony_ci				    u32 de_iir)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	enum pipe pipe;
19538c2ecf20Sopenharmony_ci	u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	if (hotplug_trigger)
19568c2ecf20Sopenharmony_ci		ilk_hpd_irq_handler(dev_priv, hotplug_trigger);
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_ci	if (de_iir & DE_AUX_CHANNEL_A)
19598c2ecf20Sopenharmony_ci		dp_aux_irq_handler(dev_priv);
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	if (de_iir & DE_GSE)
19628c2ecf20Sopenharmony_ci		intel_opregion_asle_intr(dev_priv);
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci	if (de_iir & DE_POISON)
19658c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm, "Poison interrupt\n");
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
19688c2ecf20Sopenharmony_ci		if (de_iir & DE_PIPE_VBLANK(pipe))
19698c2ecf20Sopenharmony_ci			intel_handle_vblank(dev_priv, pipe);
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci		if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
19728c2ecf20Sopenharmony_ci			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci		if (de_iir & DE_PIPE_CRC_DONE(pipe))
19758c2ecf20Sopenharmony_ci			i9xx_pipe_crc_irq_handler(dev_priv, pipe);
19768c2ecf20Sopenharmony_ci	}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	/* check event from PCH */
19798c2ecf20Sopenharmony_ci	if (de_iir & DE_PCH_EVENT) {
19808c2ecf20Sopenharmony_ci		u32 pch_iir = I915_READ(SDEIIR);
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci		if (HAS_PCH_CPT(dev_priv))
19838c2ecf20Sopenharmony_ci			cpt_irq_handler(dev_priv, pch_iir);
19848c2ecf20Sopenharmony_ci		else
19858c2ecf20Sopenharmony_ci			ibx_irq_handler(dev_priv, pch_iir);
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci		/* should clear PCH hotplug event before clear CPU irq */
19888c2ecf20Sopenharmony_ci		I915_WRITE(SDEIIR, pch_iir);
19898c2ecf20Sopenharmony_ci	}
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 5) && de_iir & DE_PCU_EVENT)
19928c2ecf20Sopenharmony_ci		gen5_rps_irq_handler(&dev_priv->gt.rps);
19938c2ecf20Sopenharmony_ci}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_cistatic void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
19968c2ecf20Sopenharmony_ci				    u32 de_iir)
19978c2ecf20Sopenharmony_ci{
19988c2ecf20Sopenharmony_ci	enum pipe pipe;
19998c2ecf20Sopenharmony_ci	u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB;
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci	if (hotplug_trigger)
20028c2ecf20Sopenharmony_ci		ilk_hpd_irq_handler(dev_priv, hotplug_trigger);
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	if (de_iir & DE_ERR_INT_IVB)
20058c2ecf20Sopenharmony_ci		ivb_err_int_handler(dev_priv);
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	if (de_iir & DE_EDP_PSR_INT_HSW) {
20088c2ecf20Sopenharmony_ci		u32 psr_iir = I915_READ(EDP_PSR_IIR);
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci		intel_psr_irq_handler(dev_priv, psr_iir);
20118c2ecf20Sopenharmony_ci		I915_WRITE(EDP_PSR_IIR, psr_iir);
20128c2ecf20Sopenharmony_ci	}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci	if (de_iir & DE_AUX_CHANNEL_A_IVB)
20158c2ecf20Sopenharmony_ci		dp_aux_irq_handler(dev_priv);
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	if (de_iir & DE_GSE_IVB)
20188c2ecf20Sopenharmony_ci		intel_opregion_asle_intr(dev_priv);
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
20218c2ecf20Sopenharmony_ci		if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
20228c2ecf20Sopenharmony_ci			intel_handle_vblank(dev_priv, pipe);
20238c2ecf20Sopenharmony_ci	}
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	/* check event from PCH */
20268c2ecf20Sopenharmony_ci	if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) {
20278c2ecf20Sopenharmony_ci		u32 pch_iir = I915_READ(SDEIIR);
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci		cpt_irq_handler(dev_priv, pch_iir);
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci		/* clear PCH hotplug event before clear CPU irq */
20328c2ecf20Sopenharmony_ci		I915_WRITE(SDEIIR, pch_iir);
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci/*
20378c2ecf20Sopenharmony_ci * To handle irqs with the minimum potential races with fresh interrupts, we:
20388c2ecf20Sopenharmony_ci * 1 - Disable Master Interrupt Control.
20398c2ecf20Sopenharmony_ci * 2 - Find the source(s) of the interrupt.
20408c2ecf20Sopenharmony_ci * 3 - Clear the Interrupt Identity bits (IIR).
20418c2ecf20Sopenharmony_ci * 4 - Process the interrupt(s) that had bits set in the IIRs.
20428c2ecf20Sopenharmony_ci * 5 - Re-enable Master Interrupt Control.
20438c2ecf20Sopenharmony_ci */
20448c2ecf20Sopenharmony_cistatic irqreturn_t ilk_irq_handler(int irq, void *arg)
20458c2ecf20Sopenharmony_ci{
20468c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = arg;
20478c2ecf20Sopenharmony_ci	void __iomem * const regs = i915->uncore.regs;
20488c2ecf20Sopenharmony_ci	u32 de_iir, gt_iir, de_ier, sde_ier = 0;
20498c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	if (unlikely(!intel_irqs_enabled(i915)))
20528c2ecf20Sopenharmony_ci		return IRQ_NONE;
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
20558c2ecf20Sopenharmony_ci	disable_rpm_wakeref_asserts(&i915->runtime_pm);
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	/* disable master interrupt before clearing iir  */
20588c2ecf20Sopenharmony_ci	de_ier = raw_reg_read(regs, DEIER);
20598c2ecf20Sopenharmony_ci	raw_reg_write(regs, DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	/* Disable south interrupts. We'll only write to SDEIIR once, so further
20628c2ecf20Sopenharmony_ci	 * interrupts will will be stored on its back queue, and then we'll be
20638c2ecf20Sopenharmony_ci	 * able to process them after we restore SDEIER (as soon as we restore
20648c2ecf20Sopenharmony_ci	 * it, we'll get an interrupt if SDEIIR still has something to process
20658c2ecf20Sopenharmony_ci	 * due to its back queue). */
20668c2ecf20Sopenharmony_ci	if (!HAS_PCH_NOP(i915)) {
20678c2ecf20Sopenharmony_ci		sde_ier = raw_reg_read(regs, SDEIER);
20688c2ecf20Sopenharmony_ci		raw_reg_write(regs, SDEIER, 0);
20698c2ecf20Sopenharmony_ci	}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	/* Find, clear, then process each source of interrupt */
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	gt_iir = raw_reg_read(regs, GTIIR);
20748c2ecf20Sopenharmony_ci	if (gt_iir) {
20758c2ecf20Sopenharmony_ci		raw_reg_write(regs, GTIIR, gt_iir);
20768c2ecf20Sopenharmony_ci		if (INTEL_GEN(i915) >= 6)
20778c2ecf20Sopenharmony_ci			gen6_gt_irq_handler(&i915->gt, gt_iir);
20788c2ecf20Sopenharmony_ci		else
20798c2ecf20Sopenharmony_ci			gen5_gt_irq_handler(&i915->gt, gt_iir);
20808c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	de_iir = raw_reg_read(regs, DEIIR);
20848c2ecf20Sopenharmony_ci	if (de_iir) {
20858c2ecf20Sopenharmony_ci		raw_reg_write(regs, DEIIR, de_iir);
20868c2ecf20Sopenharmony_ci		if (INTEL_GEN(i915) >= 7)
20878c2ecf20Sopenharmony_ci			ivb_display_irq_handler(i915, de_iir);
20888c2ecf20Sopenharmony_ci		else
20898c2ecf20Sopenharmony_ci			ilk_display_irq_handler(i915, de_iir);
20908c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
20918c2ecf20Sopenharmony_ci	}
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	if (INTEL_GEN(i915) >= 6) {
20948c2ecf20Sopenharmony_ci		u32 pm_iir = raw_reg_read(regs, GEN6_PMIIR);
20958c2ecf20Sopenharmony_ci		if (pm_iir) {
20968c2ecf20Sopenharmony_ci			raw_reg_write(regs, GEN6_PMIIR, pm_iir);
20978c2ecf20Sopenharmony_ci			gen6_rps_irq_handler(&i915->gt.rps, pm_iir);
20988c2ecf20Sopenharmony_ci			ret = IRQ_HANDLED;
20998c2ecf20Sopenharmony_ci		}
21008c2ecf20Sopenharmony_ci	}
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	raw_reg_write(regs, DEIER, de_ier);
21038c2ecf20Sopenharmony_ci	if (sde_ier)
21048c2ecf20Sopenharmony_ci		raw_reg_write(regs, SDEIER, sde_ier);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
21078c2ecf20Sopenharmony_ci	enable_rpm_wakeref_asserts(&i915->runtime_pm);
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	return ret;
21108c2ecf20Sopenharmony_ci}
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_cistatic void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
21138c2ecf20Sopenharmony_ci				u32 hotplug_trigger)
21148c2ecf20Sopenharmony_ci{
21158c2ecf20Sopenharmony_ci	u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
21188c2ecf20Sopenharmony_ci	I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
21218c2ecf20Sopenharmony_ci			   hotplug_trigger, dig_hotplug_reg,
21228c2ecf20Sopenharmony_ci			   dev_priv->hotplug.hpd,
21238c2ecf20Sopenharmony_ci			   bxt_port_hotplug_long_detect);
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
21268c2ecf20Sopenharmony_ci}
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_cistatic void gen11_hpd_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
21298c2ecf20Sopenharmony_ci{
21308c2ecf20Sopenharmony_ci	u32 pin_mask = 0, long_mask = 0;
21318c2ecf20Sopenharmony_ci	u32 trigger_tc = iir & GEN11_DE_TC_HOTPLUG_MASK;
21328c2ecf20Sopenharmony_ci	u32 trigger_tbt = iir & GEN11_DE_TBT_HOTPLUG_MASK;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	if (trigger_tc) {
21358c2ecf20Sopenharmony_ci		u32 dig_hotplug_reg;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci		dig_hotplug_reg = I915_READ(GEN11_TC_HOTPLUG_CTL);
21388c2ecf20Sopenharmony_ci		I915_WRITE(GEN11_TC_HOTPLUG_CTL, dig_hotplug_reg);
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
21418c2ecf20Sopenharmony_ci				   trigger_tc, dig_hotplug_reg,
21428c2ecf20Sopenharmony_ci				   dev_priv->hotplug.hpd,
21438c2ecf20Sopenharmony_ci				   gen11_port_hotplug_long_detect);
21448c2ecf20Sopenharmony_ci	}
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	if (trigger_tbt) {
21478c2ecf20Sopenharmony_ci		u32 dig_hotplug_reg;
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci		dig_hotplug_reg = I915_READ(GEN11_TBT_HOTPLUG_CTL);
21508c2ecf20Sopenharmony_ci		I915_WRITE(GEN11_TBT_HOTPLUG_CTL, dig_hotplug_reg);
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci		intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
21538c2ecf20Sopenharmony_ci				   trigger_tbt, dig_hotplug_reg,
21548c2ecf20Sopenharmony_ci				   dev_priv->hotplug.hpd,
21558c2ecf20Sopenharmony_ci				   gen11_port_hotplug_long_detect);
21568c2ecf20Sopenharmony_ci	}
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	if (pin_mask)
21598c2ecf20Sopenharmony_ci		intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
21608c2ecf20Sopenharmony_ci	else
21618c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm,
21628c2ecf20Sopenharmony_ci			"Unexpected DE HPD interrupt 0x%08x\n", iir);
21638c2ecf20Sopenharmony_ci}
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_cistatic u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv)
21668c2ecf20Sopenharmony_ci{
21678c2ecf20Sopenharmony_ci	u32 mask;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 12)
21708c2ecf20Sopenharmony_ci		return TGL_DE_PORT_AUX_DDIA |
21718c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_DDIB |
21728c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_DDIC |
21738c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_USBC1 |
21748c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_USBC2 |
21758c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_USBC3 |
21768c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_USBC4 |
21778c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_USBC5 |
21788c2ecf20Sopenharmony_ci			TGL_DE_PORT_AUX_USBC6;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	mask = GEN8_AUX_CHANNEL_A;
21828c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 9)
21838c2ecf20Sopenharmony_ci		mask |= GEN9_AUX_CHANNEL_B |
21848c2ecf20Sopenharmony_ci			GEN9_AUX_CHANNEL_C |
21858c2ecf20Sopenharmony_ci			GEN9_AUX_CHANNEL_D;
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ci	if (IS_CNL_WITH_PORT_F(dev_priv) || IS_GEN(dev_priv, 11))
21888c2ecf20Sopenharmony_ci		mask |= CNL_AUX_CHANNEL_F;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 11))
21918c2ecf20Sopenharmony_ci		mask |= ICL_AUX_CHANNEL_E;
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	return mask;
21948c2ecf20Sopenharmony_ci}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_cistatic u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv)
21978c2ecf20Sopenharmony_ci{
21988c2ecf20Sopenharmony_ci	if (IS_ROCKETLAKE(dev_priv))
21998c2ecf20Sopenharmony_ci		return RKL_DE_PIPE_IRQ_FAULT_ERRORS;
22008c2ecf20Sopenharmony_ci	else if (INTEL_GEN(dev_priv) >= 11)
22018c2ecf20Sopenharmony_ci		return GEN11_DE_PIPE_IRQ_FAULT_ERRORS;
22028c2ecf20Sopenharmony_ci	else if (INTEL_GEN(dev_priv) >= 9)
22038c2ecf20Sopenharmony_ci		return GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
22048c2ecf20Sopenharmony_ci	else
22058c2ecf20Sopenharmony_ci		return GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
22068c2ecf20Sopenharmony_ci}
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_cistatic void
22098c2ecf20Sopenharmony_cigen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir)
22108c2ecf20Sopenharmony_ci{
22118c2ecf20Sopenharmony_ci	bool found = false;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	if (iir & GEN8_DE_MISC_GSE) {
22148c2ecf20Sopenharmony_ci		intel_opregion_asle_intr(dev_priv);
22158c2ecf20Sopenharmony_ci		found = true;
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	if (iir & GEN8_DE_EDP_PSR) {
22198c2ecf20Sopenharmony_ci		u32 psr_iir;
22208c2ecf20Sopenharmony_ci		i915_reg_t iir_reg;
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 12)
22238c2ecf20Sopenharmony_ci			iir_reg = TRANS_PSR_IIR(dev_priv->psr.transcoder);
22248c2ecf20Sopenharmony_ci		else
22258c2ecf20Sopenharmony_ci			iir_reg = EDP_PSR_IIR;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci		psr_iir = I915_READ(iir_reg);
22288c2ecf20Sopenharmony_ci		I915_WRITE(iir_reg, psr_iir);
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci		if (psr_iir)
22318c2ecf20Sopenharmony_ci			found = true;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci		intel_psr_irq_handler(dev_priv, psr_iir);
22348c2ecf20Sopenharmony_ci	}
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	if (!found)
22378c2ecf20Sopenharmony_ci		drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n");
22388c2ecf20Sopenharmony_ci}
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_cistatic irqreturn_t
22418c2ecf20Sopenharmony_cigen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
22428c2ecf20Sopenharmony_ci{
22438c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
22448c2ecf20Sopenharmony_ci	u32 iir;
22458c2ecf20Sopenharmony_ci	enum pipe pipe;
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	if (master_ctl & GEN8_DE_MISC_IRQ) {
22488c2ecf20Sopenharmony_ci		iir = I915_READ(GEN8_DE_MISC_IIR);
22498c2ecf20Sopenharmony_ci		if (iir) {
22508c2ecf20Sopenharmony_ci			I915_WRITE(GEN8_DE_MISC_IIR, iir);
22518c2ecf20Sopenharmony_ci			ret = IRQ_HANDLED;
22528c2ecf20Sopenharmony_ci			gen8_de_misc_irq_handler(dev_priv, iir);
22538c2ecf20Sopenharmony_ci		} else {
22548c2ecf20Sopenharmony_ci			drm_err(&dev_priv->drm,
22558c2ecf20Sopenharmony_ci				"The master control interrupt lied (DE MISC)!\n");
22568c2ecf20Sopenharmony_ci		}
22578c2ecf20Sopenharmony_ci	}
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11 && (master_ctl & GEN11_DE_HPD_IRQ)) {
22608c2ecf20Sopenharmony_ci		iir = I915_READ(GEN11_DE_HPD_IIR);
22618c2ecf20Sopenharmony_ci		if (iir) {
22628c2ecf20Sopenharmony_ci			I915_WRITE(GEN11_DE_HPD_IIR, iir);
22638c2ecf20Sopenharmony_ci			ret = IRQ_HANDLED;
22648c2ecf20Sopenharmony_ci			gen11_hpd_irq_handler(dev_priv, iir);
22658c2ecf20Sopenharmony_ci		} else {
22668c2ecf20Sopenharmony_ci			drm_err(&dev_priv->drm,
22678c2ecf20Sopenharmony_ci				"The master control interrupt lied, (DE HPD)!\n");
22688c2ecf20Sopenharmony_ci		}
22698c2ecf20Sopenharmony_ci	}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	if (master_ctl & GEN8_DE_PORT_IRQ) {
22728c2ecf20Sopenharmony_ci		iir = I915_READ(GEN8_DE_PORT_IIR);
22738c2ecf20Sopenharmony_ci		if (iir) {
22748c2ecf20Sopenharmony_ci			u32 tmp_mask;
22758c2ecf20Sopenharmony_ci			bool found = false;
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci			I915_WRITE(GEN8_DE_PORT_IIR, iir);
22788c2ecf20Sopenharmony_ci			ret = IRQ_HANDLED;
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci			if (iir & gen8_de_port_aux_mask(dev_priv)) {
22818c2ecf20Sopenharmony_ci				dp_aux_irq_handler(dev_priv);
22828c2ecf20Sopenharmony_ci				found = true;
22838c2ecf20Sopenharmony_ci			}
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci			if (IS_GEN9_LP(dev_priv)) {
22868c2ecf20Sopenharmony_ci				tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK;
22878c2ecf20Sopenharmony_ci				if (tmp_mask) {
22888c2ecf20Sopenharmony_ci					bxt_hpd_irq_handler(dev_priv, tmp_mask);
22898c2ecf20Sopenharmony_ci					found = true;
22908c2ecf20Sopenharmony_ci				}
22918c2ecf20Sopenharmony_ci			} else if (IS_BROADWELL(dev_priv)) {
22928c2ecf20Sopenharmony_ci				tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG;
22938c2ecf20Sopenharmony_ci				if (tmp_mask) {
22948c2ecf20Sopenharmony_ci					ilk_hpd_irq_handler(dev_priv, tmp_mask);
22958c2ecf20Sopenharmony_ci					found = true;
22968c2ecf20Sopenharmony_ci				}
22978c2ecf20Sopenharmony_ci			}
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci			if (IS_GEN9_LP(dev_priv) && (iir & BXT_DE_PORT_GMBUS)) {
23008c2ecf20Sopenharmony_ci				gmbus_irq_handler(dev_priv);
23018c2ecf20Sopenharmony_ci				found = true;
23028c2ecf20Sopenharmony_ci			}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci			if (!found)
23058c2ecf20Sopenharmony_ci				drm_err(&dev_priv->drm,
23068c2ecf20Sopenharmony_ci					"Unexpected DE Port interrupt\n");
23078c2ecf20Sopenharmony_ci		}
23088c2ecf20Sopenharmony_ci		else
23098c2ecf20Sopenharmony_ci			drm_err(&dev_priv->drm,
23108c2ecf20Sopenharmony_ci				"The master control interrupt lied (DE PORT)!\n");
23118c2ecf20Sopenharmony_ci	}
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
23148c2ecf20Sopenharmony_ci		u32 fault_errors;
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci		if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
23178c2ecf20Sopenharmony_ci			continue;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci		iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
23208c2ecf20Sopenharmony_ci		if (!iir) {
23218c2ecf20Sopenharmony_ci			drm_err(&dev_priv->drm,
23228c2ecf20Sopenharmony_ci				"The master control interrupt lied (DE PIPE)!\n");
23238c2ecf20Sopenharmony_ci			continue;
23248c2ecf20Sopenharmony_ci		}
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
23278c2ecf20Sopenharmony_ci		I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci		if (iir & GEN8_PIPE_VBLANK)
23308c2ecf20Sopenharmony_ci			intel_handle_vblank(dev_priv, pipe);
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci		if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
23338c2ecf20Sopenharmony_ci			hsw_pipe_crc_irq_handler(dev_priv, pipe);
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci		if (iir & GEN8_PIPE_FIFO_UNDERRUN)
23368c2ecf20Sopenharmony_ci			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci		fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv);
23398c2ecf20Sopenharmony_ci		if (fault_errors)
23408c2ecf20Sopenharmony_ci			drm_err(&dev_priv->drm,
23418c2ecf20Sopenharmony_ci				"Fault errors on pipe %c: 0x%08x\n",
23428c2ecf20Sopenharmony_ci				pipe_name(pipe),
23438c2ecf20Sopenharmony_ci				fault_errors);
23448c2ecf20Sopenharmony_ci	}
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
23478c2ecf20Sopenharmony_ci	    master_ctl & GEN8_DE_PCH_IRQ) {
23488c2ecf20Sopenharmony_ci		/*
23498c2ecf20Sopenharmony_ci		 * FIXME(BDW): Assume for now that the new interrupt handling
23508c2ecf20Sopenharmony_ci		 * scheme also closed the SDE interrupt handling race we've seen
23518c2ecf20Sopenharmony_ci		 * on older pch-split platforms. But this needs testing.
23528c2ecf20Sopenharmony_ci		 */
23538c2ecf20Sopenharmony_ci		iir = I915_READ(SDEIIR);
23548c2ecf20Sopenharmony_ci		if (iir) {
23558c2ecf20Sopenharmony_ci			I915_WRITE(SDEIIR, iir);
23568c2ecf20Sopenharmony_ci			ret = IRQ_HANDLED;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci			if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
23598c2ecf20Sopenharmony_ci				icp_irq_handler(dev_priv, iir);
23608c2ecf20Sopenharmony_ci			else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT)
23618c2ecf20Sopenharmony_ci				spt_irq_handler(dev_priv, iir);
23628c2ecf20Sopenharmony_ci			else
23638c2ecf20Sopenharmony_ci				cpt_irq_handler(dev_priv, iir);
23648c2ecf20Sopenharmony_ci		} else {
23658c2ecf20Sopenharmony_ci			/*
23668c2ecf20Sopenharmony_ci			 * Like on previous PCH there seems to be something
23678c2ecf20Sopenharmony_ci			 * fishy going on with forwarding PCH interrupts.
23688c2ecf20Sopenharmony_ci			 */
23698c2ecf20Sopenharmony_ci			drm_dbg(&dev_priv->drm,
23708c2ecf20Sopenharmony_ci				"The master control interrupt lied (SDE)!\n");
23718c2ecf20Sopenharmony_ci		}
23728c2ecf20Sopenharmony_ci	}
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	return ret;
23758c2ecf20Sopenharmony_ci}
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_cistatic inline u32 gen8_master_intr_disable(void __iomem * const regs)
23788c2ecf20Sopenharmony_ci{
23798c2ecf20Sopenharmony_ci	raw_reg_write(regs, GEN8_MASTER_IRQ, 0);
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	/*
23828c2ecf20Sopenharmony_ci	 * Now with master disabled, get a sample of level indications
23838c2ecf20Sopenharmony_ci	 * for this interrupt. Indications will be cleared on related acks.
23848c2ecf20Sopenharmony_ci	 * New indications can and will light up during processing,
23858c2ecf20Sopenharmony_ci	 * and will generate new interrupt after enabling master.
23868c2ecf20Sopenharmony_ci	 */
23878c2ecf20Sopenharmony_ci	return raw_reg_read(regs, GEN8_MASTER_IRQ);
23888c2ecf20Sopenharmony_ci}
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_cistatic inline void gen8_master_intr_enable(void __iomem * const regs)
23918c2ecf20Sopenharmony_ci{
23928c2ecf20Sopenharmony_ci	raw_reg_write(regs, GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
23938c2ecf20Sopenharmony_ci}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_cistatic irqreturn_t gen8_irq_handler(int irq, void *arg)
23968c2ecf20Sopenharmony_ci{
23978c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = arg;
23988c2ecf20Sopenharmony_ci	void __iomem * const regs = dev_priv->uncore.regs;
23998c2ecf20Sopenharmony_ci	u32 master_ctl;
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv))
24028c2ecf20Sopenharmony_ci		return IRQ_NONE;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	master_ctl = gen8_master_intr_disable(regs);
24058c2ecf20Sopenharmony_ci	if (!master_ctl) {
24068c2ecf20Sopenharmony_ci		gen8_master_intr_enable(regs);
24078c2ecf20Sopenharmony_ci		return IRQ_NONE;
24088c2ecf20Sopenharmony_ci	}
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci	/* Find, queue (onto bottom-halves), then clear each source */
24118c2ecf20Sopenharmony_ci	gen8_gt_irq_handler(&dev_priv->gt, master_ctl);
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
24148c2ecf20Sopenharmony_ci	if (master_ctl & ~GEN8_GT_IRQS) {
24158c2ecf20Sopenharmony_ci		disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
24168c2ecf20Sopenharmony_ci		gen8_de_irq_handler(dev_priv, master_ctl);
24178c2ecf20Sopenharmony_ci		enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
24188c2ecf20Sopenharmony_ci	}
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci	gen8_master_intr_enable(regs);
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
24238c2ecf20Sopenharmony_ci}
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_cistatic u32
24268c2ecf20Sopenharmony_cigen11_gu_misc_irq_ack(struct intel_gt *gt, const u32 master_ctl)
24278c2ecf20Sopenharmony_ci{
24288c2ecf20Sopenharmony_ci	void __iomem * const regs = gt->uncore->regs;
24298c2ecf20Sopenharmony_ci	u32 iir;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	if (!(master_ctl & GEN11_GU_MISC_IRQ))
24328c2ecf20Sopenharmony_ci		return 0;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	iir = raw_reg_read(regs, GEN11_GU_MISC_IIR);
24358c2ecf20Sopenharmony_ci	if (likely(iir))
24368c2ecf20Sopenharmony_ci		raw_reg_write(regs, GEN11_GU_MISC_IIR, iir);
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	return iir;
24398c2ecf20Sopenharmony_ci}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_cistatic void
24428c2ecf20Sopenharmony_cigen11_gu_misc_irq_handler(struct intel_gt *gt, const u32 iir)
24438c2ecf20Sopenharmony_ci{
24448c2ecf20Sopenharmony_ci	if (iir & GEN11_GU_MISC_GSE)
24458c2ecf20Sopenharmony_ci		intel_opregion_asle_intr(gt->i915);
24468c2ecf20Sopenharmony_ci}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_cistatic inline u32 gen11_master_intr_disable(void __iomem * const regs)
24498c2ecf20Sopenharmony_ci{
24508c2ecf20Sopenharmony_ci	raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0);
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	/*
24538c2ecf20Sopenharmony_ci	 * Now with master disabled, get a sample of level indications
24548c2ecf20Sopenharmony_ci	 * for this interrupt. Indications will be cleared on related acks.
24558c2ecf20Sopenharmony_ci	 * New indications can and will light up during processing,
24568c2ecf20Sopenharmony_ci	 * and will generate new interrupt after enabling master.
24578c2ecf20Sopenharmony_ci	 */
24588c2ecf20Sopenharmony_ci	return raw_reg_read(regs, GEN11_GFX_MSTR_IRQ);
24598c2ecf20Sopenharmony_ci}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_cistatic inline void gen11_master_intr_enable(void __iomem * const regs)
24628c2ecf20Sopenharmony_ci{
24638c2ecf20Sopenharmony_ci	raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, GEN11_MASTER_IRQ);
24648c2ecf20Sopenharmony_ci}
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_cistatic void
24678c2ecf20Sopenharmony_cigen11_display_irq_handler(struct drm_i915_private *i915)
24688c2ecf20Sopenharmony_ci{
24698c2ecf20Sopenharmony_ci	void __iomem * const regs = i915->uncore.regs;
24708c2ecf20Sopenharmony_ci	const u32 disp_ctl = raw_reg_read(regs, GEN11_DISPLAY_INT_CTL);
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	disable_rpm_wakeref_asserts(&i915->runtime_pm);
24738c2ecf20Sopenharmony_ci	/*
24748c2ecf20Sopenharmony_ci	 * GEN11_DISPLAY_INT_CTL has same format as GEN8_MASTER_IRQ
24758c2ecf20Sopenharmony_ci	 * for the display related bits.
24768c2ecf20Sopenharmony_ci	 */
24778c2ecf20Sopenharmony_ci	raw_reg_write(regs, GEN11_DISPLAY_INT_CTL, 0x0);
24788c2ecf20Sopenharmony_ci	gen8_de_irq_handler(i915, disp_ctl);
24798c2ecf20Sopenharmony_ci	raw_reg_write(regs, GEN11_DISPLAY_INT_CTL,
24808c2ecf20Sopenharmony_ci		      GEN11_DISPLAY_IRQ_ENABLE);
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	enable_rpm_wakeref_asserts(&i915->runtime_pm);
24838c2ecf20Sopenharmony_ci}
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_cistatic __always_inline irqreturn_t
24868c2ecf20Sopenharmony_ci__gen11_irq_handler(struct drm_i915_private * const i915,
24878c2ecf20Sopenharmony_ci		    u32 (*intr_disable)(void __iomem * const regs),
24888c2ecf20Sopenharmony_ci		    void (*intr_enable)(void __iomem * const regs))
24898c2ecf20Sopenharmony_ci{
24908c2ecf20Sopenharmony_ci	void __iomem * const regs = i915->uncore.regs;
24918c2ecf20Sopenharmony_ci	struct intel_gt *gt = &i915->gt;
24928c2ecf20Sopenharmony_ci	u32 master_ctl;
24938c2ecf20Sopenharmony_ci	u32 gu_misc_iir;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(i915))
24968c2ecf20Sopenharmony_ci		return IRQ_NONE;
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	master_ctl = intr_disable(regs);
24998c2ecf20Sopenharmony_ci	if (!master_ctl) {
25008c2ecf20Sopenharmony_ci		intr_enable(regs);
25018c2ecf20Sopenharmony_ci		return IRQ_NONE;
25028c2ecf20Sopenharmony_ci	}
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	/* Find, queue (onto bottom-halves), then clear each source */
25058c2ecf20Sopenharmony_ci	gen11_gt_irq_handler(gt, master_ctl);
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
25088c2ecf20Sopenharmony_ci	if (master_ctl & GEN11_DISPLAY_IRQ)
25098c2ecf20Sopenharmony_ci		gen11_display_irq_handler(i915);
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci	gu_misc_iir = gen11_gu_misc_irq_ack(gt, master_ctl);
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci	intr_enable(regs);
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	gen11_gu_misc_irq_handler(gt, gu_misc_iir);
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
25188c2ecf20Sopenharmony_ci}
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_cistatic irqreturn_t gen11_irq_handler(int irq, void *arg)
25218c2ecf20Sopenharmony_ci{
25228c2ecf20Sopenharmony_ci	return __gen11_irq_handler(arg,
25238c2ecf20Sopenharmony_ci				   gen11_master_intr_disable,
25248c2ecf20Sopenharmony_ci				   gen11_master_intr_enable);
25258c2ecf20Sopenharmony_ci}
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_cistatic u32 dg1_master_intr_disable_and_ack(void __iomem * const regs)
25288c2ecf20Sopenharmony_ci{
25298c2ecf20Sopenharmony_ci	u32 val;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	/* First disable interrupts */
25328c2ecf20Sopenharmony_ci	raw_reg_write(regs, DG1_MSTR_UNIT_INTR, 0);
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	/* Get the indication levels and ack the master unit */
25358c2ecf20Sopenharmony_ci	val = raw_reg_read(regs, DG1_MSTR_UNIT_INTR);
25368c2ecf20Sopenharmony_ci	if (unlikely(!val))
25378c2ecf20Sopenharmony_ci		return 0;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci	raw_reg_write(regs, DG1_MSTR_UNIT_INTR, val);
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	/*
25428c2ecf20Sopenharmony_ci	 * Now with master disabled, get a sample of level indications
25438c2ecf20Sopenharmony_ci	 * for this interrupt and ack them right away - we keep GEN11_MASTER_IRQ
25448c2ecf20Sopenharmony_ci	 * out as this bit doesn't exist anymore for DG1
25458c2ecf20Sopenharmony_ci	 */
25468c2ecf20Sopenharmony_ci	val = raw_reg_read(regs, GEN11_GFX_MSTR_IRQ) & ~GEN11_MASTER_IRQ;
25478c2ecf20Sopenharmony_ci	if (unlikely(!val))
25488c2ecf20Sopenharmony_ci		return 0;
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, val);
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci	return val;
25538c2ecf20Sopenharmony_ci}
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_cistatic inline void dg1_master_intr_enable(void __iomem * const regs)
25568c2ecf20Sopenharmony_ci{
25578c2ecf20Sopenharmony_ci	raw_reg_write(regs, DG1_MSTR_UNIT_INTR, DG1_MSTR_IRQ);
25588c2ecf20Sopenharmony_ci}
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_cistatic irqreturn_t dg1_irq_handler(int irq, void *arg)
25618c2ecf20Sopenharmony_ci{
25628c2ecf20Sopenharmony_ci	return __gen11_irq_handler(arg,
25638c2ecf20Sopenharmony_ci				   dg1_master_intr_disable_and_ack,
25648c2ecf20Sopenharmony_ci				   dg1_master_intr_enable);
25658c2ecf20Sopenharmony_ci}
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci/* Called from drm generic code, passed 'crtc' which
25688c2ecf20Sopenharmony_ci * we use as a pipe index
25698c2ecf20Sopenharmony_ci */
25708c2ecf20Sopenharmony_ciint i8xx_enable_vblank(struct drm_crtc *crtc)
25718c2ecf20Sopenharmony_ci{
25728c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
25738c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
25748c2ecf20Sopenharmony_ci	unsigned long irqflags;
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
25778c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS);
25788c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	return 0;
25818c2ecf20Sopenharmony_ci}
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ciint i915gm_enable_vblank(struct drm_crtc *crtc)
25848c2ecf20Sopenharmony_ci{
25858c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci	/*
25888c2ecf20Sopenharmony_ci	 * Vblank interrupts fail to wake the device up from C2+.
25898c2ecf20Sopenharmony_ci	 * Disabling render clock gating during C-states avoids
25908c2ecf20Sopenharmony_ci	 * the problem. There is a small power cost so we do this
25918c2ecf20Sopenharmony_ci	 * only when vblank interrupts are actually enabled.
25928c2ecf20Sopenharmony_ci	 */
25938c2ecf20Sopenharmony_ci	if (dev_priv->vblank_enabled++ == 0)
25948c2ecf20Sopenharmony_ci		I915_WRITE(SCPD0, _MASKED_BIT_ENABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE));
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	return i8xx_enable_vblank(crtc);
25978c2ecf20Sopenharmony_ci}
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ciint i965_enable_vblank(struct drm_crtc *crtc)
26008c2ecf20Sopenharmony_ci{
26018c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
26028c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
26038c2ecf20Sopenharmony_ci	unsigned long irqflags;
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
26068c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, pipe,
26078c2ecf20Sopenharmony_ci			     PIPE_START_VBLANK_INTERRUPT_STATUS);
26088c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	return 0;
26118c2ecf20Sopenharmony_ci}
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ciint ilk_enable_vblank(struct drm_crtc *crtc)
26148c2ecf20Sopenharmony_ci{
26158c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
26168c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
26178c2ecf20Sopenharmony_ci	unsigned long irqflags;
26188c2ecf20Sopenharmony_ci	u32 bit = INTEL_GEN(dev_priv) >= 7 ?
26198c2ecf20Sopenharmony_ci		DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe);
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
26228c2ecf20Sopenharmony_ci	ilk_enable_display_irq(dev_priv, bit);
26238c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	/* Even though there is no DMC, frame counter can get stuck when
26268c2ecf20Sopenharmony_ci	 * PSR is active as no frames are generated.
26278c2ecf20Sopenharmony_ci	 */
26288c2ecf20Sopenharmony_ci	if (HAS_PSR(dev_priv))
26298c2ecf20Sopenharmony_ci		drm_crtc_vblank_restore(crtc);
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	return 0;
26328c2ecf20Sopenharmony_ci}
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ciint bdw_enable_vblank(struct drm_crtc *crtc)
26358c2ecf20Sopenharmony_ci{
26368c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
26378c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
26388c2ecf20Sopenharmony_ci	unsigned long irqflags;
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
26418c2ecf20Sopenharmony_ci	bdw_enable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
26428c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	/* Even if there is no DMC, frame counter can get stuck when
26458c2ecf20Sopenharmony_ci	 * PSR is active as no frames are generated, so check only for PSR.
26468c2ecf20Sopenharmony_ci	 */
26478c2ecf20Sopenharmony_ci	if (HAS_PSR(dev_priv))
26488c2ecf20Sopenharmony_ci		drm_crtc_vblank_restore(crtc);
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	return 0;
26518c2ecf20Sopenharmony_ci}
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci/* Called from drm generic code, passed 'crtc' which
26548c2ecf20Sopenharmony_ci * we use as a pipe index
26558c2ecf20Sopenharmony_ci */
26568c2ecf20Sopenharmony_civoid i8xx_disable_vblank(struct drm_crtc *crtc)
26578c2ecf20Sopenharmony_ci{
26588c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
26598c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
26608c2ecf20Sopenharmony_ci	unsigned long irqflags;
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
26638c2ecf20Sopenharmony_ci	i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_STATUS);
26648c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
26658c2ecf20Sopenharmony_ci}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_civoid i915gm_disable_vblank(struct drm_crtc *crtc)
26688c2ecf20Sopenharmony_ci{
26698c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	i8xx_disable_vblank(crtc);
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	if (--dev_priv->vblank_enabled == 0)
26748c2ecf20Sopenharmony_ci		I915_WRITE(SCPD0, _MASKED_BIT_DISABLE(CSTATE_RENDER_CLOCK_GATE_DISABLE));
26758c2ecf20Sopenharmony_ci}
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_civoid i965_disable_vblank(struct drm_crtc *crtc)
26788c2ecf20Sopenharmony_ci{
26798c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
26808c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
26818c2ecf20Sopenharmony_ci	unsigned long irqflags;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
26848c2ecf20Sopenharmony_ci	i915_disable_pipestat(dev_priv, pipe,
26858c2ecf20Sopenharmony_ci			      PIPE_START_VBLANK_INTERRUPT_STATUS);
26868c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
26878c2ecf20Sopenharmony_ci}
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_civoid ilk_disable_vblank(struct drm_crtc *crtc)
26908c2ecf20Sopenharmony_ci{
26918c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
26928c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
26938c2ecf20Sopenharmony_ci	unsigned long irqflags;
26948c2ecf20Sopenharmony_ci	u32 bit = INTEL_GEN(dev_priv) >= 7 ?
26958c2ecf20Sopenharmony_ci		DE_PIPE_VBLANK_IVB(pipe) : DE_PIPE_VBLANK(pipe);
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
26988c2ecf20Sopenharmony_ci	ilk_disable_display_irq(dev_priv, bit);
26998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
27008c2ecf20Sopenharmony_ci}
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_civoid bdw_disable_vblank(struct drm_crtc *crtc)
27038c2ecf20Sopenharmony_ci{
27048c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
27058c2ecf20Sopenharmony_ci	enum pipe pipe = to_intel_crtc(crtc)->pipe;
27068c2ecf20Sopenharmony_ci	unsigned long irqflags;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
27098c2ecf20Sopenharmony_ci	bdw_disable_pipe_irq(dev_priv, pipe, GEN8_PIPE_VBLANK);
27108c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
27118c2ecf20Sopenharmony_ci}
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_cistatic void ibx_irq_reset(struct drm_i915_private *dev_priv)
27148c2ecf20Sopenharmony_ci{
27158c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci	if (HAS_PCH_NOP(dev_priv))
27188c2ecf20Sopenharmony_ci		return;
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, SDE);
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
27238c2ecf20Sopenharmony_ci		I915_WRITE(SERR_INT, 0xffffffff);
27248c2ecf20Sopenharmony_ci}
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci/*
27278c2ecf20Sopenharmony_ci * SDEIER is also touched by the interrupt handler to work around missed PCH
27288c2ecf20Sopenharmony_ci * interrupts. Hence we can't update it after the interrupt handler is enabled -
27298c2ecf20Sopenharmony_ci * instead we unconditionally enable all PCH interrupt sources here, but then
27308c2ecf20Sopenharmony_ci * only unmask them as needed with SDEIMR.
27318c2ecf20Sopenharmony_ci *
27328c2ecf20Sopenharmony_ci * This function needs to be called before interrupts are enabled.
27338c2ecf20Sopenharmony_ci */
27348c2ecf20Sopenharmony_cistatic void ibx_irq_pre_postinstall(struct drm_i915_private *dev_priv)
27358c2ecf20Sopenharmony_ci{
27368c2ecf20Sopenharmony_ci	if (HAS_PCH_NOP(dev_priv))
27378c2ecf20Sopenharmony_ci		return;
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0);
27408c2ecf20Sopenharmony_ci	I915_WRITE(SDEIER, 0xffffffff);
27418c2ecf20Sopenharmony_ci	POSTING_READ(SDEIER);
27428c2ecf20Sopenharmony_ci}
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_cistatic void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
27458c2ecf20Sopenharmony_ci{
27468c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci	if (IS_CHERRYVIEW(dev_priv))
27498c2ecf20Sopenharmony_ci		intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
27508c2ecf20Sopenharmony_ci	else
27518c2ecf20Sopenharmony_ci		intel_uncore_write(uncore, DPINVGTT, DPINVGTT_STATUS_MASK);
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0);
27548c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci	i9xx_pipestat_irq_reset(dev_priv);
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, VLV_);
27598c2ecf20Sopenharmony_ci	dev_priv->irq_mask = ~0u;
27608c2ecf20Sopenharmony_ci}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_cistatic void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
27638c2ecf20Sopenharmony_ci{
27648c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
27658c2ecf20Sopenharmony_ci
27668c2ecf20Sopenharmony_ci	u32 pipestat_mask;
27678c2ecf20Sopenharmony_ci	u32 enable_mask;
27688c2ecf20Sopenharmony_ci	enum pipe pipe;
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	pipestat_mask = PIPE_CRC_DONE_INTERRUPT_STATUS;
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
27738c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe)
27748c2ecf20Sopenharmony_ci		i915_enable_pipestat(dev_priv, pipe, pipestat_mask);
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	enable_mask = I915_DISPLAY_PORT_INTERRUPT |
27778c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
27788c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
27798c2ecf20Sopenharmony_ci		I915_LPE_PIPE_A_INTERRUPT |
27808c2ecf20Sopenharmony_ci		I915_LPE_PIPE_B_INTERRUPT;
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	if (IS_CHERRYVIEW(dev_priv))
27838c2ecf20Sopenharmony_ci		enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT |
27848c2ecf20Sopenharmony_ci			I915_LPE_PIPE_C_INTERRUPT;
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, dev_priv->irq_mask != ~0u);
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	dev_priv->irq_mask = ~enable_mask;
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci	GEN3_IRQ_INIT(uncore, VLV_, dev_priv->irq_mask, enable_mask);
27918c2ecf20Sopenharmony_ci}
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ci/* drm_dma.h hooks
27948c2ecf20Sopenharmony_ci*/
27958c2ecf20Sopenharmony_cistatic void ilk_irq_reset(struct drm_i915_private *dev_priv)
27968c2ecf20Sopenharmony_ci{
27978c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, DE);
28008c2ecf20Sopenharmony_ci	if (IS_GEN(dev_priv, 7))
28018c2ecf20Sopenharmony_ci		intel_uncore_write(uncore, GEN7_ERR_INT, 0xffffffff);
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	if (IS_HASWELL(dev_priv)) {
28048c2ecf20Sopenharmony_ci		intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff);
28058c2ecf20Sopenharmony_ci		intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff);
28068c2ecf20Sopenharmony_ci	}
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci	gen5_gt_irq_reset(&dev_priv->gt);
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	ibx_irq_reset(dev_priv);
28118c2ecf20Sopenharmony_ci}
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_cistatic void valleyview_irq_reset(struct drm_i915_private *dev_priv)
28148c2ecf20Sopenharmony_ci{
28158c2ecf20Sopenharmony_ci	I915_WRITE(VLV_MASTER_IER, 0);
28168c2ecf20Sopenharmony_ci	POSTING_READ(VLV_MASTER_IER);
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	gen5_gt_irq_reset(&dev_priv->gt);
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
28218c2ecf20Sopenharmony_ci	if (dev_priv->display_irqs_enabled)
28228c2ecf20Sopenharmony_ci		vlv_display_irq_reset(dev_priv);
28238c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
28248c2ecf20Sopenharmony_ci}
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_cistatic void gen8_irq_reset(struct drm_i915_private *dev_priv)
28278c2ecf20Sopenharmony_ci{
28288c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
28298c2ecf20Sopenharmony_ci	enum pipe pipe;
28308c2ecf20Sopenharmony_ci
28318c2ecf20Sopenharmony_ci	gen8_master_intr_disable(dev_priv->uncore.regs);
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	gen8_gt_irq_reset(&dev_priv->gt);
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff);
28368c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff);
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe)
28398c2ecf20Sopenharmony_ci		if (intel_display_power_is_enabled(dev_priv,
28408c2ecf20Sopenharmony_ci						   POWER_DOMAIN_PIPE(pipe)))
28418c2ecf20Sopenharmony_ci			GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe);
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_);
28448c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_);
28458c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN8_PCU_);
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci	if (HAS_PCH_SPLIT(dev_priv))
28488c2ecf20Sopenharmony_ci		ibx_irq_reset(dev_priv);
28498c2ecf20Sopenharmony_ci}
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_cistatic void gen11_display_irq_reset(struct drm_i915_private *dev_priv)
28528c2ecf20Sopenharmony_ci{
28538c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
28548c2ecf20Sopenharmony_ci	enum pipe pipe;
28558c2ecf20Sopenharmony_ci	u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) |
28568c2ecf20Sopenharmony_ci		BIT(TRANSCODER_C) | BIT(TRANSCODER_D);
28578c2ecf20Sopenharmony_ci
28588c2ecf20Sopenharmony_ci	intel_uncore_write(uncore, GEN11_DISPLAY_INT_CTL, 0);
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 12) {
28618c2ecf20Sopenharmony_ci		enum transcoder trans;
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci		for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) {
28648c2ecf20Sopenharmony_ci			enum intel_display_power_domain domain;
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci			domain = POWER_DOMAIN_TRANSCODER(trans);
28678c2ecf20Sopenharmony_ci			if (!intel_display_power_is_enabled(dev_priv, domain))
28688c2ecf20Sopenharmony_ci				continue;
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_ci			intel_uncore_write(uncore, TRANS_PSR_IMR(trans), 0xffffffff);
28718c2ecf20Sopenharmony_ci			intel_uncore_write(uncore, TRANS_PSR_IIR(trans), 0xffffffff);
28728c2ecf20Sopenharmony_ci		}
28738c2ecf20Sopenharmony_ci	} else {
28748c2ecf20Sopenharmony_ci		intel_uncore_write(uncore, EDP_PSR_IMR, 0xffffffff);
28758c2ecf20Sopenharmony_ci		intel_uncore_write(uncore, EDP_PSR_IIR, 0xffffffff);
28768c2ecf20Sopenharmony_ci	}
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe)
28798c2ecf20Sopenharmony_ci		if (intel_display_power_is_enabled(dev_priv,
28808c2ecf20Sopenharmony_ci						   POWER_DOMAIN_PIPE(pipe)))
28818c2ecf20Sopenharmony_ci			GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe);
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN8_DE_PORT_);
28848c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN8_DE_MISC_);
28858c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN11_DE_HPD_);
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_ci	if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
28888c2ecf20Sopenharmony_ci		GEN3_IRQ_RESET(uncore, SDE);
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci	/* Wa_14010685332:icl,jsl,ehl,tgl,rkl */
28918c2ecf20Sopenharmony_ci	if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) {
28928c2ecf20Sopenharmony_ci		intel_uncore_rmw(uncore, SOUTH_CHICKEN1,
28938c2ecf20Sopenharmony_ci				 SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS);
28948c2ecf20Sopenharmony_ci		intel_uncore_rmw(uncore, SOUTH_CHICKEN1,
28958c2ecf20Sopenharmony_ci				 SBCLK_RUN_REFCLK_DIS, 0);
28968c2ecf20Sopenharmony_ci	}
28978c2ecf20Sopenharmony_ci}
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_cistatic void gen11_irq_reset(struct drm_i915_private *dev_priv)
29008c2ecf20Sopenharmony_ci{
29018c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	if (HAS_MASTER_UNIT_IRQ(dev_priv))
29048c2ecf20Sopenharmony_ci		dg1_master_intr_disable_and_ack(dev_priv->uncore.regs);
29058c2ecf20Sopenharmony_ci	else
29068c2ecf20Sopenharmony_ci		gen11_master_intr_disable(dev_priv->uncore.regs);
29078c2ecf20Sopenharmony_ci
29088c2ecf20Sopenharmony_ci	gen11_gt_irq_reset(&dev_priv->gt);
29098c2ecf20Sopenharmony_ci	gen11_display_irq_reset(dev_priv);
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN11_GU_MISC_);
29128c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN8_PCU_);
29138c2ecf20Sopenharmony_ci}
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_civoid gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
29168c2ecf20Sopenharmony_ci				     u8 pipe_mask)
29178c2ecf20Sopenharmony_ci{
29188c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci	u32 extra_ier = GEN8_PIPE_VBLANK | GEN8_PIPE_FIFO_UNDERRUN;
29218c2ecf20Sopenharmony_ci	enum pipe pipe;
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv)) {
29268c2ecf20Sopenharmony_ci		spin_unlock_irq(&dev_priv->irq_lock);
29278c2ecf20Sopenharmony_ci		return;
29288c2ecf20Sopenharmony_ci	}
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci	for_each_pipe_masked(dev_priv, pipe, pipe_mask)
29318c2ecf20Sopenharmony_ci		GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe,
29328c2ecf20Sopenharmony_ci				  dev_priv->de_irq_mask[pipe],
29338c2ecf20Sopenharmony_ci				  ~dev_priv->de_irq_mask[pipe] | extra_ier);
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
29368c2ecf20Sopenharmony_ci}
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_civoid gen8_irq_power_well_pre_disable(struct drm_i915_private *dev_priv,
29398c2ecf20Sopenharmony_ci				     u8 pipe_mask)
29408c2ecf20Sopenharmony_ci{
29418c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
29428c2ecf20Sopenharmony_ci	enum pipe pipe;
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv)) {
29478c2ecf20Sopenharmony_ci		spin_unlock_irq(&dev_priv->irq_lock);
29488c2ecf20Sopenharmony_ci		return;
29498c2ecf20Sopenharmony_ci	}
29508c2ecf20Sopenharmony_ci
29518c2ecf20Sopenharmony_ci	for_each_pipe_masked(dev_priv, pipe, pipe_mask)
29528c2ecf20Sopenharmony_ci		GEN8_IRQ_RESET_NDX(uncore, DE_PIPE, pipe);
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci	/* make sure we're done processing display irqs */
29578c2ecf20Sopenharmony_ci	intel_synchronize_irq(dev_priv);
29588c2ecf20Sopenharmony_ci}
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_cistatic void cherryview_irq_reset(struct drm_i915_private *dev_priv)
29618c2ecf20Sopenharmony_ci{
29628c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_MASTER_IRQ, 0);
29658c2ecf20Sopenharmony_ci	POSTING_READ(GEN8_MASTER_IRQ);
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	gen8_gt_irq_reset(&dev_priv->gt);
29688c2ecf20Sopenharmony_ci
29698c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN8_PCU_);
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
29728c2ecf20Sopenharmony_ci	if (dev_priv->display_irqs_enabled)
29738c2ecf20Sopenharmony_ci		vlv_display_irq_reset(dev_priv);
29748c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
29758c2ecf20Sopenharmony_ci}
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_cistatic u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
29788c2ecf20Sopenharmony_ci				  const u32 hpd[HPD_NUM_PINS])
29798c2ecf20Sopenharmony_ci{
29808c2ecf20Sopenharmony_ci	struct intel_encoder *encoder;
29818c2ecf20Sopenharmony_ci	u32 enabled_irqs = 0;
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_ci	for_each_intel_encoder(&dev_priv->drm, encoder)
29848c2ecf20Sopenharmony_ci		if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
29858c2ecf20Sopenharmony_ci			enabled_irqs |= hpd[encoder->hpd_pin];
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci	return enabled_irqs;
29888c2ecf20Sopenharmony_ci}
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_cistatic u32 intel_hpd_hotplug_irqs(struct drm_i915_private *dev_priv,
29918c2ecf20Sopenharmony_ci				  const u32 hpd[HPD_NUM_PINS])
29928c2ecf20Sopenharmony_ci{
29938c2ecf20Sopenharmony_ci	struct intel_encoder *encoder;
29948c2ecf20Sopenharmony_ci	u32 hotplug_irqs = 0;
29958c2ecf20Sopenharmony_ci
29968c2ecf20Sopenharmony_ci	for_each_intel_encoder(&dev_priv->drm, encoder)
29978c2ecf20Sopenharmony_ci		hotplug_irqs |= hpd[encoder->hpd_pin];
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	return hotplug_irqs;
30008c2ecf20Sopenharmony_ci}
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_cistatic void ibx_hpd_detection_setup(struct drm_i915_private *dev_priv)
30038c2ecf20Sopenharmony_ci{
30048c2ecf20Sopenharmony_ci	u32 hotplug;
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci	/*
30078c2ecf20Sopenharmony_ci	 * Enable digital hotplug on the PCH, and configure the DP short pulse
30088c2ecf20Sopenharmony_ci	 * duration to 2ms (which is the minimum in the Display Port spec).
30098c2ecf20Sopenharmony_ci	 * The pulse duration bits are reserved on LPT+.
30108c2ecf20Sopenharmony_ci	 */
30118c2ecf20Sopenharmony_ci	hotplug = I915_READ(PCH_PORT_HOTPLUG);
30128c2ecf20Sopenharmony_ci	hotplug &= ~(PORTB_PULSE_DURATION_MASK |
30138c2ecf20Sopenharmony_ci		     PORTC_PULSE_DURATION_MASK |
30148c2ecf20Sopenharmony_ci		     PORTD_PULSE_DURATION_MASK);
30158c2ecf20Sopenharmony_ci	hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
30168c2ecf20Sopenharmony_ci	hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
30178c2ecf20Sopenharmony_ci	hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
30188c2ecf20Sopenharmony_ci	/*
30198c2ecf20Sopenharmony_ci	 * When CPU and PCH are on the same package, port A
30208c2ecf20Sopenharmony_ci	 * HPD must be enabled in both north and south.
30218c2ecf20Sopenharmony_ci	 */
30228c2ecf20Sopenharmony_ci	if (HAS_PCH_LPT_LP(dev_priv))
30238c2ecf20Sopenharmony_ci		hotplug |= PORTA_HOTPLUG_ENABLE;
30248c2ecf20Sopenharmony_ci	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
30258c2ecf20Sopenharmony_ci}
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_cistatic void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
30288c2ecf20Sopenharmony_ci{
30298c2ecf20Sopenharmony_ci	u32 hotplug_irqs, enabled_irqs;
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
30328c2ecf20Sopenharmony_ci	hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
30358c2ecf20Sopenharmony_ci
30368c2ecf20Sopenharmony_ci	ibx_hpd_detection_setup(dev_priv);
30378c2ecf20Sopenharmony_ci}
30388c2ecf20Sopenharmony_ci
30398c2ecf20Sopenharmony_cistatic void icp_ddi_hpd_detection_setup(struct drm_i915_private *dev_priv,
30408c2ecf20Sopenharmony_ci					u32 enable_mask)
30418c2ecf20Sopenharmony_ci{
30428c2ecf20Sopenharmony_ci	u32 hotplug;
30438c2ecf20Sopenharmony_ci
30448c2ecf20Sopenharmony_ci	hotplug = I915_READ(SHOTPLUG_CTL_DDI);
30458c2ecf20Sopenharmony_ci	hotplug |= enable_mask;
30468c2ecf20Sopenharmony_ci	I915_WRITE(SHOTPLUG_CTL_DDI, hotplug);
30478c2ecf20Sopenharmony_ci}
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_cistatic void icp_tc_hpd_detection_setup(struct drm_i915_private *dev_priv,
30508c2ecf20Sopenharmony_ci				       u32 enable_mask)
30518c2ecf20Sopenharmony_ci{
30528c2ecf20Sopenharmony_ci	u32 hotplug;
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	hotplug = I915_READ(SHOTPLUG_CTL_TC);
30558c2ecf20Sopenharmony_ci	hotplug |= enable_mask;
30568c2ecf20Sopenharmony_ci	I915_WRITE(SHOTPLUG_CTL_TC, hotplug);
30578c2ecf20Sopenharmony_ci}
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_cistatic void icp_hpd_irq_setup(struct drm_i915_private *dev_priv,
30608c2ecf20Sopenharmony_ci			      u32 ddi_enable_mask, u32 tc_enable_mask)
30618c2ecf20Sopenharmony_ci{
30628c2ecf20Sopenharmony_ci	u32 hotplug_irqs, enabled_irqs;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
30658c2ecf20Sopenharmony_ci	hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	if (INTEL_PCH_TYPE(dev_priv) <= PCH_TGP)
30688c2ecf20Sopenharmony_ci		I915_WRITE(SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ);
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
30718c2ecf20Sopenharmony_ci
30728c2ecf20Sopenharmony_ci	icp_ddi_hpd_detection_setup(dev_priv, ddi_enable_mask);
30738c2ecf20Sopenharmony_ci	if (tc_enable_mask)
30748c2ecf20Sopenharmony_ci		icp_tc_hpd_detection_setup(dev_priv, tc_enable_mask);
30758c2ecf20Sopenharmony_ci}
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci/*
30788c2ecf20Sopenharmony_ci * EHL doesn't need most of gen11_hpd_irq_setup, it's handling only the
30798c2ecf20Sopenharmony_ci * equivalent of SDE.
30808c2ecf20Sopenharmony_ci */
30818c2ecf20Sopenharmony_cistatic void mcc_hpd_irq_setup(struct drm_i915_private *dev_priv)
30828c2ecf20Sopenharmony_ci{
30838c2ecf20Sopenharmony_ci	icp_hpd_irq_setup(dev_priv,
30848c2ecf20Sopenharmony_ci			  ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE(PORT_TC1));
30858c2ecf20Sopenharmony_ci}
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci/*
30888c2ecf20Sopenharmony_ci * JSP behaves exactly the same as MCC above except that port C is mapped to
30898c2ecf20Sopenharmony_ci * the DDI-C pins instead of the TC1 pins.  This means we should follow TGP's
30908c2ecf20Sopenharmony_ci * masks & tables rather than ICP's masks & tables.
30918c2ecf20Sopenharmony_ci */
30928c2ecf20Sopenharmony_cistatic void jsp_hpd_irq_setup(struct drm_i915_private *dev_priv)
30938c2ecf20Sopenharmony_ci{
30948c2ecf20Sopenharmony_ci	icp_hpd_irq_setup(dev_priv,
30958c2ecf20Sopenharmony_ci			  TGP_DDI_HPD_ENABLE_MASK, 0);
30968c2ecf20Sopenharmony_ci}
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_cistatic void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv)
30998c2ecf20Sopenharmony_ci{
31008c2ecf20Sopenharmony_ci	u32 hotplug;
31018c2ecf20Sopenharmony_ci
31028c2ecf20Sopenharmony_ci	hotplug = I915_READ(GEN11_TC_HOTPLUG_CTL);
31038c2ecf20Sopenharmony_ci	hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
31048c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
31058c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
31068c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
31078c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
31088c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
31098c2ecf20Sopenharmony_ci	I915_WRITE(GEN11_TC_HOTPLUG_CTL, hotplug);
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ci	hotplug = I915_READ(GEN11_TBT_HOTPLUG_CTL);
31128c2ecf20Sopenharmony_ci	hotplug |= GEN11_HOTPLUG_CTL_ENABLE(PORT_TC1) |
31138c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC2) |
31148c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC3) |
31158c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC4) |
31168c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC5) |
31178c2ecf20Sopenharmony_ci		   GEN11_HOTPLUG_CTL_ENABLE(PORT_TC6);
31188c2ecf20Sopenharmony_ci	I915_WRITE(GEN11_TBT_HOTPLUG_CTL, hotplug);
31198c2ecf20Sopenharmony_ci}
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_cistatic void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
31228c2ecf20Sopenharmony_ci{
31238c2ecf20Sopenharmony_ci	u32 hotplug_irqs, enabled_irqs;
31248c2ecf20Sopenharmony_ci	u32 val;
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
31278c2ecf20Sopenharmony_ci	hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.hpd);
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	val = I915_READ(GEN11_DE_HPD_IMR);
31308c2ecf20Sopenharmony_ci	val &= ~hotplug_irqs;
31318c2ecf20Sopenharmony_ci	val |= ~enabled_irqs & hotplug_irqs;
31328c2ecf20Sopenharmony_ci	I915_WRITE(GEN11_DE_HPD_IMR, val);
31338c2ecf20Sopenharmony_ci	POSTING_READ(GEN11_DE_HPD_IMR);
31348c2ecf20Sopenharmony_ci
31358c2ecf20Sopenharmony_ci	gen11_hpd_detection_setup(dev_priv);
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_ci	if (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP)
31388c2ecf20Sopenharmony_ci		icp_hpd_irq_setup(dev_priv,
31398c2ecf20Sopenharmony_ci				  TGP_DDI_HPD_ENABLE_MASK, TGP_TC_HPD_ENABLE_MASK);
31408c2ecf20Sopenharmony_ci	else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
31418c2ecf20Sopenharmony_ci		icp_hpd_irq_setup(dev_priv,
31428c2ecf20Sopenharmony_ci				  ICP_DDI_HPD_ENABLE_MASK, ICP_TC_HPD_ENABLE_MASK);
31438c2ecf20Sopenharmony_ci}
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_cistatic void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
31468c2ecf20Sopenharmony_ci{
31478c2ecf20Sopenharmony_ci	u32 val, hotplug;
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	/* Display WA #1179 WaHardHangonHotPlug: cnp */
31508c2ecf20Sopenharmony_ci	if (HAS_PCH_CNP(dev_priv)) {
31518c2ecf20Sopenharmony_ci		val = I915_READ(SOUTH_CHICKEN1);
31528c2ecf20Sopenharmony_ci		val &= ~CHASSIS_CLK_REQ_DURATION_MASK;
31538c2ecf20Sopenharmony_ci		val |= CHASSIS_CLK_REQ_DURATION(0xf);
31548c2ecf20Sopenharmony_ci		I915_WRITE(SOUTH_CHICKEN1, val);
31558c2ecf20Sopenharmony_ci	}
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	/* Enable digital hotplug on the PCH */
31588c2ecf20Sopenharmony_ci	hotplug = I915_READ(PCH_PORT_HOTPLUG);
31598c2ecf20Sopenharmony_ci	hotplug |= PORTA_HOTPLUG_ENABLE |
31608c2ecf20Sopenharmony_ci		   PORTB_HOTPLUG_ENABLE |
31618c2ecf20Sopenharmony_ci		   PORTC_HOTPLUG_ENABLE |
31628c2ecf20Sopenharmony_ci		   PORTD_HOTPLUG_ENABLE;
31638c2ecf20Sopenharmony_ci	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	hotplug = I915_READ(PCH_PORT_HOTPLUG2);
31668c2ecf20Sopenharmony_ci	hotplug |= PORTE_HOTPLUG_ENABLE;
31678c2ecf20Sopenharmony_ci	I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
31688c2ecf20Sopenharmony_ci}
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_cistatic void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
31718c2ecf20Sopenharmony_ci{
31728c2ecf20Sopenharmony_ci	u32 hotplug_irqs, enabled_irqs;
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP)
31758c2ecf20Sopenharmony_ci		I915_WRITE(SHPD_FILTER_CNT, SHPD_FILTER_CNT_500_ADJ);
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
31788c2ecf20Sopenharmony_ci	hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.pch_hpd);
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_ci	spt_hpd_detection_setup(dev_priv);
31838c2ecf20Sopenharmony_ci}
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_cistatic void ilk_hpd_detection_setup(struct drm_i915_private *dev_priv)
31868c2ecf20Sopenharmony_ci{
31878c2ecf20Sopenharmony_ci	u32 hotplug;
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci	/*
31908c2ecf20Sopenharmony_ci	 * Enable digital hotplug on the CPU, and configure the DP short pulse
31918c2ecf20Sopenharmony_ci	 * duration to 2ms (which is the minimum in the Display Port spec)
31928c2ecf20Sopenharmony_ci	 * The pulse duration bits are reserved on HSW+.
31938c2ecf20Sopenharmony_ci	 */
31948c2ecf20Sopenharmony_ci	hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
31958c2ecf20Sopenharmony_ci	hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK;
31968c2ecf20Sopenharmony_ci	hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE |
31978c2ecf20Sopenharmony_ci		   DIGITAL_PORTA_PULSE_DURATION_2ms;
31988c2ecf20Sopenharmony_ci	I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
31998c2ecf20Sopenharmony_ci}
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_cistatic void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
32028c2ecf20Sopenharmony_ci{
32038c2ecf20Sopenharmony_ci	u32 hotplug_irqs, enabled_irqs;
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_ci	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
32068c2ecf20Sopenharmony_ci	hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.hpd);
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 8)
32098c2ecf20Sopenharmony_ci		bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
32108c2ecf20Sopenharmony_ci	else
32118c2ecf20Sopenharmony_ci		ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
32128c2ecf20Sopenharmony_ci
32138c2ecf20Sopenharmony_ci	ilk_hpd_detection_setup(dev_priv);
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	ibx_hpd_irq_setup(dev_priv);
32168c2ecf20Sopenharmony_ci}
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_cistatic void __bxt_hpd_detection_setup(struct drm_i915_private *dev_priv,
32198c2ecf20Sopenharmony_ci				      u32 enabled_irqs)
32208c2ecf20Sopenharmony_ci{
32218c2ecf20Sopenharmony_ci	u32 hotplug;
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci	hotplug = I915_READ(PCH_PORT_HOTPLUG);
32248c2ecf20Sopenharmony_ci	hotplug |= PORTA_HOTPLUG_ENABLE |
32258c2ecf20Sopenharmony_ci		   PORTB_HOTPLUG_ENABLE |
32268c2ecf20Sopenharmony_ci		   PORTC_HOTPLUG_ENABLE;
32278c2ecf20Sopenharmony_ci
32288c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm,
32298c2ecf20Sopenharmony_ci		    "Invert bit setting: hp_ctl:%x hp_port:%x\n",
32308c2ecf20Sopenharmony_ci		    hotplug, enabled_irqs);
32318c2ecf20Sopenharmony_ci	hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	/*
32348c2ecf20Sopenharmony_ci	 * For BXT invert bit has to be set based on AOB design
32358c2ecf20Sopenharmony_ci	 * for HPD detection logic, update it based on VBT fields.
32368c2ecf20Sopenharmony_ci	 */
32378c2ecf20Sopenharmony_ci	if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
32388c2ecf20Sopenharmony_ci	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_A))
32398c2ecf20Sopenharmony_ci		hotplug |= BXT_DDIA_HPD_INVERT;
32408c2ecf20Sopenharmony_ci	if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
32418c2ecf20Sopenharmony_ci	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_B))
32428c2ecf20Sopenharmony_ci		hotplug |= BXT_DDIB_HPD_INVERT;
32438c2ecf20Sopenharmony_ci	if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
32448c2ecf20Sopenharmony_ci	    intel_bios_is_port_hpd_inverted(dev_priv, PORT_C))
32458c2ecf20Sopenharmony_ci		hotplug |= BXT_DDIC_HPD_INVERT;
32468c2ecf20Sopenharmony_ci
32478c2ecf20Sopenharmony_ci	I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
32488c2ecf20Sopenharmony_ci}
32498c2ecf20Sopenharmony_ci
32508c2ecf20Sopenharmony_cistatic void bxt_hpd_detection_setup(struct drm_i915_private *dev_priv)
32518c2ecf20Sopenharmony_ci{
32528c2ecf20Sopenharmony_ci	__bxt_hpd_detection_setup(dev_priv, BXT_DE_PORT_HOTPLUG_MASK);
32538c2ecf20Sopenharmony_ci}
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_cistatic void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
32568c2ecf20Sopenharmony_ci{
32578c2ecf20Sopenharmony_ci	u32 hotplug_irqs, enabled_irqs;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	enabled_irqs = intel_hpd_enabled_irqs(dev_priv, dev_priv->hotplug.hpd);
32608c2ecf20Sopenharmony_ci	hotplug_irqs = intel_hpd_hotplug_irqs(dev_priv, dev_priv->hotplug.hpd);
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_ci	bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_ci	__bxt_hpd_detection_setup(dev_priv, enabled_irqs);
32658c2ecf20Sopenharmony_ci}
32668c2ecf20Sopenharmony_ci
32678c2ecf20Sopenharmony_cistatic void ibx_irq_postinstall(struct drm_i915_private *dev_priv)
32688c2ecf20Sopenharmony_ci{
32698c2ecf20Sopenharmony_ci	u32 mask;
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	if (HAS_PCH_NOP(dev_priv))
32728c2ecf20Sopenharmony_ci		return;
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci	if (HAS_PCH_IBX(dev_priv))
32758c2ecf20Sopenharmony_ci		mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
32768c2ecf20Sopenharmony_ci	else if (HAS_PCH_CPT(dev_priv) || HAS_PCH_LPT(dev_priv))
32778c2ecf20Sopenharmony_ci		mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
32788c2ecf20Sopenharmony_ci	else
32798c2ecf20Sopenharmony_ci		mask = SDE_GMBUS_CPT;
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci	gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
32828c2ecf20Sopenharmony_ci	I915_WRITE(SDEIMR, ~mask);
32838c2ecf20Sopenharmony_ci
32848c2ecf20Sopenharmony_ci	if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv) ||
32858c2ecf20Sopenharmony_ci	    HAS_PCH_LPT(dev_priv))
32868c2ecf20Sopenharmony_ci		ibx_hpd_detection_setup(dev_priv);
32878c2ecf20Sopenharmony_ci	else
32888c2ecf20Sopenharmony_ci		spt_hpd_detection_setup(dev_priv);
32898c2ecf20Sopenharmony_ci}
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_cistatic void ilk_irq_postinstall(struct drm_i915_private *dev_priv)
32928c2ecf20Sopenharmony_ci{
32938c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
32948c2ecf20Sopenharmony_ci	u32 display_mask, extra_mask;
32958c2ecf20Sopenharmony_ci
32968c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 7) {
32978c2ecf20Sopenharmony_ci		display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
32988c2ecf20Sopenharmony_ci				DE_PCH_EVENT_IVB | DE_AUX_CHANNEL_A_IVB);
32998c2ecf20Sopenharmony_ci		extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
33008c2ecf20Sopenharmony_ci			      DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB |
33018c2ecf20Sopenharmony_ci			      DE_DP_A_HOTPLUG_IVB);
33028c2ecf20Sopenharmony_ci	} else {
33038c2ecf20Sopenharmony_ci		display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
33048c2ecf20Sopenharmony_ci				DE_AUX_CHANNEL_A | DE_PIPEB_CRC_DONE |
33058c2ecf20Sopenharmony_ci				DE_PIPEA_CRC_DONE | DE_POISON);
33068c2ecf20Sopenharmony_ci		extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
33078c2ecf20Sopenharmony_ci			      DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
33088c2ecf20Sopenharmony_ci			      DE_DP_A_HOTPLUG);
33098c2ecf20Sopenharmony_ci	}
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci	if (IS_HASWELL(dev_priv)) {
33128c2ecf20Sopenharmony_ci		gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR);
33138c2ecf20Sopenharmony_ci		display_mask |= DE_EDP_PSR_INT_HSW;
33148c2ecf20Sopenharmony_ci	}
33158c2ecf20Sopenharmony_ci
33168c2ecf20Sopenharmony_ci	dev_priv->irq_mask = ~display_mask;
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci	ibx_irq_pre_postinstall(dev_priv);
33198c2ecf20Sopenharmony_ci
33208c2ecf20Sopenharmony_ci	GEN3_IRQ_INIT(uncore, DE, dev_priv->irq_mask,
33218c2ecf20Sopenharmony_ci		      display_mask | extra_mask);
33228c2ecf20Sopenharmony_ci
33238c2ecf20Sopenharmony_ci	gen5_gt_irq_postinstall(&dev_priv->gt);
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci	ilk_hpd_detection_setup(dev_priv);
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci	ibx_irq_postinstall(dev_priv);
33288c2ecf20Sopenharmony_ci
33298c2ecf20Sopenharmony_ci	if (IS_IRONLAKE_M(dev_priv)) {
33308c2ecf20Sopenharmony_ci		/* Enable PCU event interrupts
33318c2ecf20Sopenharmony_ci		 *
33328c2ecf20Sopenharmony_ci		 * spinlocking not required here for correctness since interrupt
33338c2ecf20Sopenharmony_ci		 * setup is guaranteed to run in single-threaded context. But we
33348c2ecf20Sopenharmony_ci		 * need it to make the assert_spin_locked happy. */
33358c2ecf20Sopenharmony_ci		spin_lock_irq(&dev_priv->irq_lock);
33368c2ecf20Sopenharmony_ci		ilk_enable_display_irq(dev_priv, DE_PCU_EVENT);
33378c2ecf20Sopenharmony_ci		spin_unlock_irq(&dev_priv->irq_lock);
33388c2ecf20Sopenharmony_ci	}
33398c2ecf20Sopenharmony_ci}
33408c2ecf20Sopenharmony_ci
33418c2ecf20Sopenharmony_civoid valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
33428c2ecf20Sopenharmony_ci{
33438c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci	if (dev_priv->display_irqs_enabled)
33468c2ecf20Sopenharmony_ci		return;
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_ci	dev_priv->display_irqs_enabled = true;
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_ci	if (intel_irqs_enabled(dev_priv)) {
33518c2ecf20Sopenharmony_ci		vlv_display_irq_reset(dev_priv);
33528c2ecf20Sopenharmony_ci		vlv_display_irq_postinstall(dev_priv);
33538c2ecf20Sopenharmony_ci	}
33548c2ecf20Sopenharmony_ci}
33558c2ecf20Sopenharmony_ci
33568c2ecf20Sopenharmony_civoid valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
33578c2ecf20Sopenharmony_ci{
33588c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci	if (!dev_priv->display_irqs_enabled)
33618c2ecf20Sopenharmony_ci		return;
33628c2ecf20Sopenharmony_ci
33638c2ecf20Sopenharmony_ci	dev_priv->display_irqs_enabled = false;
33648c2ecf20Sopenharmony_ci
33658c2ecf20Sopenharmony_ci	if (intel_irqs_enabled(dev_priv))
33668c2ecf20Sopenharmony_ci		vlv_display_irq_reset(dev_priv);
33678c2ecf20Sopenharmony_ci}
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_cistatic void valleyview_irq_postinstall(struct drm_i915_private *dev_priv)
33718c2ecf20Sopenharmony_ci{
33728c2ecf20Sopenharmony_ci	gen5_gt_irq_postinstall(&dev_priv->gt);
33738c2ecf20Sopenharmony_ci
33748c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
33758c2ecf20Sopenharmony_ci	if (dev_priv->display_irqs_enabled)
33768c2ecf20Sopenharmony_ci		vlv_display_irq_postinstall(dev_priv);
33778c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
33788c2ecf20Sopenharmony_ci
33798c2ecf20Sopenharmony_ci	I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
33808c2ecf20Sopenharmony_ci	POSTING_READ(VLV_MASTER_IER);
33818c2ecf20Sopenharmony_ci}
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_cistatic void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
33848c2ecf20Sopenharmony_ci{
33858c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
33868c2ecf20Sopenharmony_ci
33878c2ecf20Sopenharmony_ci	u32 de_pipe_masked = gen8_de_pipe_fault_mask(dev_priv) |
33888c2ecf20Sopenharmony_ci		GEN8_PIPE_CDCLK_CRC_DONE;
33898c2ecf20Sopenharmony_ci	u32 de_pipe_enables;
33908c2ecf20Sopenharmony_ci	u32 de_port_masked = gen8_de_port_aux_mask(dev_priv);
33918c2ecf20Sopenharmony_ci	u32 de_port_enables;
33928c2ecf20Sopenharmony_ci	u32 de_misc_masked = GEN8_DE_EDP_PSR;
33938c2ecf20Sopenharmony_ci	u32 trans_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) |
33948c2ecf20Sopenharmony_ci		BIT(TRANSCODER_C) | BIT(TRANSCODER_D);
33958c2ecf20Sopenharmony_ci	enum pipe pipe;
33968c2ecf20Sopenharmony_ci
33978c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) <= 10)
33988c2ecf20Sopenharmony_ci		de_misc_masked |= GEN8_DE_MISC_GSE;
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	if (IS_GEN9_LP(dev_priv))
34018c2ecf20Sopenharmony_ci		de_port_masked |= BXT_DE_PORT_GMBUS;
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_ci	de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
34048c2ecf20Sopenharmony_ci					   GEN8_PIPE_FIFO_UNDERRUN;
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ci	de_port_enables = de_port_masked;
34078c2ecf20Sopenharmony_ci	if (IS_GEN9_LP(dev_priv))
34088c2ecf20Sopenharmony_ci		de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK;
34098c2ecf20Sopenharmony_ci	else if (IS_BROADWELL(dev_priv))
34108c2ecf20Sopenharmony_ci		de_port_enables |= GEN8_PORT_DP_A_HOTPLUG;
34118c2ecf20Sopenharmony_ci
34128c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 12) {
34138c2ecf20Sopenharmony_ci		enum transcoder trans;
34148c2ecf20Sopenharmony_ci
34158c2ecf20Sopenharmony_ci		for_each_cpu_transcoder_masked(dev_priv, trans, trans_mask) {
34168c2ecf20Sopenharmony_ci			enum intel_display_power_domain domain;
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci			domain = POWER_DOMAIN_TRANSCODER(trans);
34198c2ecf20Sopenharmony_ci			if (!intel_display_power_is_enabled(dev_priv, domain))
34208c2ecf20Sopenharmony_ci				continue;
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci			gen3_assert_iir_is_zero(uncore, TRANS_PSR_IIR(trans));
34238c2ecf20Sopenharmony_ci		}
34248c2ecf20Sopenharmony_ci	} else {
34258c2ecf20Sopenharmony_ci		gen3_assert_iir_is_zero(uncore, EDP_PSR_IIR);
34268c2ecf20Sopenharmony_ci	}
34278c2ecf20Sopenharmony_ci
34288c2ecf20Sopenharmony_ci	for_each_pipe(dev_priv, pipe) {
34298c2ecf20Sopenharmony_ci		dev_priv->de_irq_mask[pipe] = ~de_pipe_masked;
34308c2ecf20Sopenharmony_ci
34318c2ecf20Sopenharmony_ci		if (intel_display_power_is_enabled(dev_priv,
34328c2ecf20Sopenharmony_ci				POWER_DOMAIN_PIPE(pipe)))
34338c2ecf20Sopenharmony_ci			GEN8_IRQ_INIT_NDX(uncore, DE_PIPE, pipe,
34348c2ecf20Sopenharmony_ci					  dev_priv->de_irq_mask[pipe],
34358c2ecf20Sopenharmony_ci					  de_pipe_enables);
34368c2ecf20Sopenharmony_ci	}
34378c2ecf20Sopenharmony_ci
34388c2ecf20Sopenharmony_ci	GEN3_IRQ_INIT(uncore, GEN8_DE_PORT_, ~de_port_masked, de_port_enables);
34398c2ecf20Sopenharmony_ci	GEN3_IRQ_INIT(uncore, GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked);
34408c2ecf20Sopenharmony_ci
34418c2ecf20Sopenharmony_ci	if (INTEL_GEN(dev_priv) >= 11) {
34428c2ecf20Sopenharmony_ci		u32 de_hpd_masked = 0;
34438c2ecf20Sopenharmony_ci		u32 de_hpd_enables = GEN11_DE_TC_HOTPLUG_MASK |
34448c2ecf20Sopenharmony_ci				     GEN11_DE_TBT_HOTPLUG_MASK;
34458c2ecf20Sopenharmony_ci
34468c2ecf20Sopenharmony_ci		GEN3_IRQ_INIT(uncore, GEN11_DE_HPD_, ~de_hpd_masked,
34478c2ecf20Sopenharmony_ci			      de_hpd_enables);
34488c2ecf20Sopenharmony_ci		gen11_hpd_detection_setup(dev_priv);
34498c2ecf20Sopenharmony_ci	} else if (IS_GEN9_LP(dev_priv)) {
34508c2ecf20Sopenharmony_ci		bxt_hpd_detection_setup(dev_priv);
34518c2ecf20Sopenharmony_ci	} else if (IS_BROADWELL(dev_priv)) {
34528c2ecf20Sopenharmony_ci		ilk_hpd_detection_setup(dev_priv);
34538c2ecf20Sopenharmony_ci	}
34548c2ecf20Sopenharmony_ci}
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_cistatic void gen8_irq_postinstall(struct drm_i915_private *dev_priv)
34578c2ecf20Sopenharmony_ci{
34588c2ecf20Sopenharmony_ci	if (HAS_PCH_SPLIT(dev_priv))
34598c2ecf20Sopenharmony_ci		ibx_irq_pre_postinstall(dev_priv);
34608c2ecf20Sopenharmony_ci
34618c2ecf20Sopenharmony_ci	gen8_gt_irq_postinstall(&dev_priv->gt);
34628c2ecf20Sopenharmony_ci	gen8_de_irq_postinstall(dev_priv);
34638c2ecf20Sopenharmony_ci
34648c2ecf20Sopenharmony_ci	if (HAS_PCH_SPLIT(dev_priv))
34658c2ecf20Sopenharmony_ci		ibx_irq_postinstall(dev_priv);
34668c2ecf20Sopenharmony_ci
34678c2ecf20Sopenharmony_ci	gen8_master_intr_enable(dev_priv->uncore.regs);
34688c2ecf20Sopenharmony_ci}
34698c2ecf20Sopenharmony_ci
34708c2ecf20Sopenharmony_cistatic void icp_irq_postinstall(struct drm_i915_private *dev_priv)
34718c2ecf20Sopenharmony_ci{
34728c2ecf20Sopenharmony_ci	u32 mask = SDE_GMBUS_ICP;
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	drm_WARN_ON(&dev_priv->drm, I915_READ(SDEIER) != 0);
34758c2ecf20Sopenharmony_ci	I915_WRITE(SDEIER, 0xffffffff);
34768c2ecf20Sopenharmony_ci	POSTING_READ(SDEIER);
34778c2ecf20Sopenharmony_ci
34788c2ecf20Sopenharmony_ci	gen3_assert_iir_is_zero(&dev_priv->uncore, SDEIIR);
34798c2ecf20Sopenharmony_ci	I915_WRITE(SDEIMR, ~mask);
34808c2ecf20Sopenharmony_ci
34818c2ecf20Sopenharmony_ci	if (HAS_PCH_TGP(dev_priv)) {
34828c2ecf20Sopenharmony_ci		icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
34838c2ecf20Sopenharmony_ci		icp_tc_hpd_detection_setup(dev_priv, TGP_TC_HPD_ENABLE_MASK);
34848c2ecf20Sopenharmony_ci	} else if (HAS_PCH_JSP(dev_priv)) {
34858c2ecf20Sopenharmony_ci		icp_ddi_hpd_detection_setup(dev_priv, TGP_DDI_HPD_ENABLE_MASK);
34868c2ecf20Sopenharmony_ci	} else if (HAS_PCH_MCC(dev_priv)) {
34878c2ecf20Sopenharmony_ci		icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
34888c2ecf20Sopenharmony_ci		icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE(PORT_TC1));
34898c2ecf20Sopenharmony_ci	} else {
34908c2ecf20Sopenharmony_ci		icp_ddi_hpd_detection_setup(dev_priv, ICP_DDI_HPD_ENABLE_MASK);
34918c2ecf20Sopenharmony_ci		icp_tc_hpd_detection_setup(dev_priv, ICP_TC_HPD_ENABLE_MASK);
34928c2ecf20Sopenharmony_ci	}
34938c2ecf20Sopenharmony_ci}
34948c2ecf20Sopenharmony_ci
34958c2ecf20Sopenharmony_cistatic void gen11_irq_postinstall(struct drm_i915_private *dev_priv)
34968c2ecf20Sopenharmony_ci{
34978c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
34988c2ecf20Sopenharmony_ci	u32 gu_misc_masked = GEN11_GU_MISC_GSE;
34998c2ecf20Sopenharmony_ci
35008c2ecf20Sopenharmony_ci	if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP)
35018c2ecf20Sopenharmony_ci		icp_irq_postinstall(dev_priv);
35028c2ecf20Sopenharmony_ci
35038c2ecf20Sopenharmony_ci	gen11_gt_irq_postinstall(&dev_priv->gt);
35048c2ecf20Sopenharmony_ci	gen8_de_irq_postinstall(dev_priv);
35058c2ecf20Sopenharmony_ci
35068c2ecf20Sopenharmony_ci	GEN3_IRQ_INIT(uncore, GEN11_GU_MISC_, ~gu_misc_masked, gu_misc_masked);
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci	I915_WRITE(GEN11_DISPLAY_INT_CTL, GEN11_DISPLAY_IRQ_ENABLE);
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci	if (HAS_MASTER_UNIT_IRQ(dev_priv)) {
35118c2ecf20Sopenharmony_ci		dg1_master_intr_enable(uncore->regs);
35128c2ecf20Sopenharmony_ci		POSTING_READ(DG1_MSTR_UNIT_INTR);
35138c2ecf20Sopenharmony_ci	} else {
35148c2ecf20Sopenharmony_ci		gen11_master_intr_enable(uncore->regs);
35158c2ecf20Sopenharmony_ci		POSTING_READ(GEN11_GFX_MSTR_IRQ);
35168c2ecf20Sopenharmony_ci	}
35178c2ecf20Sopenharmony_ci}
35188c2ecf20Sopenharmony_ci
35198c2ecf20Sopenharmony_cistatic void cherryview_irq_postinstall(struct drm_i915_private *dev_priv)
35208c2ecf20Sopenharmony_ci{
35218c2ecf20Sopenharmony_ci	gen8_gt_irq_postinstall(&dev_priv->gt);
35228c2ecf20Sopenharmony_ci
35238c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
35248c2ecf20Sopenharmony_ci	if (dev_priv->display_irqs_enabled)
35258c2ecf20Sopenharmony_ci		vlv_display_irq_postinstall(dev_priv);
35268c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
35278c2ecf20Sopenharmony_ci
35288c2ecf20Sopenharmony_ci	I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
35298c2ecf20Sopenharmony_ci	POSTING_READ(GEN8_MASTER_IRQ);
35308c2ecf20Sopenharmony_ci}
35318c2ecf20Sopenharmony_ci
35328c2ecf20Sopenharmony_cistatic void i8xx_irq_reset(struct drm_i915_private *dev_priv)
35338c2ecf20Sopenharmony_ci{
35348c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	i9xx_pipestat_irq_reset(dev_priv);
35378c2ecf20Sopenharmony_ci
35388c2ecf20Sopenharmony_ci	GEN2_IRQ_RESET(uncore);
35398c2ecf20Sopenharmony_ci}
35408c2ecf20Sopenharmony_ci
35418c2ecf20Sopenharmony_cistatic void i8xx_irq_postinstall(struct drm_i915_private *dev_priv)
35428c2ecf20Sopenharmony_ci{
35438c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
35448c2ecf20Sopenharmony_ci	u16 enable_mask;
35458c2ecf20Sopenharmony_ci
35468c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore,
35478c2ecf20Sopenharmony_ci			     EMR,
35488c2ecf20Sopenharmony_ci			     ~(I915_ERROR_PAGE_TABLE |
35498c2ecf20Sopenharmony_ci			       I915_ERROR_MEMORY_REFRESH));
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ci	/* Unmask the interrupts that we always want on. */
35528c2ecf20Sopenharmony_ci	dev_priv->irq_mask =
35538c2ecf20Sopenharmony_ci		~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
35548c2ecf20Sopenharmony_ci		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
35558c2ecf20Sopenharmony_ci		  I915_MASTER_ERROR_INTERRUPT);
35568c2ecf20Sopenharmony_ci
35578c2ecf20Sopenharmony_ci	enable_mask =
35588c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
35598c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
35608c2ecf20Sopenharmony_ci		I915_MASTER_ERROR_INTERRUPT |
35618c2ecf20Sopenharmony_ci		I915_USER_INTERRUPT;
35628c2ecf20Sopenharmony_ci
35638c2ecf20Sopenharmony_ci	GEN2_IRQ_INIT(uncore, dev_priv->irq_mask, enable_mask);
35648c2ecf20Sopenharmony_ci
35658c2ecf20Sopenharmony_ci	/* Interrupt setup is already guaranteed to be single-threaded, this is
35668c2ecf20Sopenharmony_ci	 * just to make the assert_spin_locked check happy. */
35678c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
35688c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
35698c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
35708c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
35718c2ecf20Sopenharmony_ci}
35728c2ecf20Sopenharmony_ci
35738c2ecf20Sopenharmony_cistatic void i8xx_error_irq_ack(struct drm_i915_private *i915,
35748c2ecf20Sopenharmony_ci			       u16 *eir, u16 *eir_stuck)
35758c2ecf20Sopenharmony_ci{
35768c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &i915->uncore;
35778c2ecf20Sopenharmony_ci	u16 emr;
35788c2ecf20Sopenharmony_ci
35798c2ecf20Sopenharmony_ci	*eir = intel_uncore_read16(uncore, EIR);
35808c2ecf20Sopenharmony_ci
35818c2ecf20Sopenharmony_ci	if (*eir)
35828c2ecf20Sopenharmony_ci		intel_uncore_write16(uncore, EIR, *eir);
35838c2ecf20Sopenharmony_ci
35848c2ecf20Sopenharmony_ci	*eir_stuck = intel_uncore_read16(uncore, EIR);
35858c2ecf20Sopenharmony_ci	if (*eir_stuck == 0)
35868c2ecf20Sopenharmony_ci		return;
35878c2ecf20Sopenharmony_ci
35888c2ecf20Sopenharmony_ci	/*
35898c2ecf20Sopenharmony_ci	 * Toggle all EMR bits to make sure we get an edge
35908c2ecf20Sopenharmony_ci	 * in the ISR master error bit if we don't clear
35918c2ecf20Sopenharmony_ci	 * all the EIR bits. Otherwise the edge triggered
35928c2ecf20Sopenharmony_ci	 * IIR on i965/g4x wouldn't notice that an interrupt
35938c2ecf20Sopenharmony_ci	 * is still pending. Also some EIR bits can't be
35948c2ecf20Sopenharmony_ci	 * cleared except by handling the underlying error
35958c2ecf20Sopenharmony_ci	 * (or by a GPU reset) so we mask any bit that
35968c2ecf20Sopenharmony_ci	 * remains set.
35978c2ecf20Sopenharmony_ci	 */
35988c2ecf20Sopenharmony_ci	emr = intel_uncore_read16(uncore, EMR);
35998c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, EMR, 0xffff);
36008c2ecf20Sopenharmony_ci	intel_uncore_write16(uncore, EMR, emr | *eir_stuck);
36018c2ecf20Sopenharmony_ci}
36028c2ecf20Sopenharmony_ci
36038c2ecf20Sopenharmony_cistatic void i8xx_error_irq_handler(struct drm_i915_private *dev_priv,
36048c2ecf20Sopenharmony_ci				   u16 eir, u16 eir_stuck)
36058c2ecf20Sopenharmony_ci{
36068c2ecf20Sopenharmony_ci	DRM_DEBUG("Master Error: EIR 0x%04x\n", eir);
36078c2ecf20Sopenharmony_ci
36088c2ecf20Sopenharmony_ci	if (eir_stuck)
36098c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "EIR stuck: 0x%04x, masked\n",
36108c2ecf20Sopenharmony_ci			eir_stuck);
36118c2ecf20Sopenharmony_ci}
36128c2ecf20Sopenharmony_ci
36138c2ecf20Sopenharmony_cistatic void i9xx_error_irq_ack(struct drm_i915_private *dev_priv,
36148c2ecf20Sopenharmony_ci			       u32 *eir, u32 *eir_stuck)
36158c2ecf20Sopenharmony_ci{
36168c2ecf20Sopenharmony_ci	u32 emr;
36178c2ecf20Sopenharmony_ci
36188c2ecf20Sopenharmony_ci	*eir = I915_READ(EIR);
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci	I915_WRITE(EIR, *eir);
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_ci	*eir_stuck = I915_READ(EIR);
36238c2ecf20Sopenharmony_ci	if (*eir_stuck == 0)
36248c2ecf20Sopenharmony_ci		return;
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci	/*
36278c2ecf20Sopenharmony_ci	 * Toggle all EMR bits to make sure we get an edge
36288c2ecf20Sopenharmony_ci	 * in the ISR master error bit if we don't clear
36298c2ecf20Sopenharmony_ci	 * all the EIR bits. Otherwise the edge triggered
36308c2ecf20Sopenharmony_ci	 * IIR on i965/g4x wouldn't notice that an interrupt
36318c2ecf20Sopenharmony_ci	 * is still pending. Also some EIR bits can't be
36328c2ecf20Sopenharmony_ci	 * cleared except by handling the underlying error
36338c2ecf20Sopenharmony_ci	 * (or by a GPU reset) so we mask any bit that
36348c2ecf20Sopenharmony_ci	 * remains set.
36358c2ecf20Sopenharmony_ci	 */
36368c2ecf20Sopenharmony_ci	emr = I915_READ(EMR);
36378c2ecf20Sopenharmony_ci	I915_WRITE(EMR, 0xffffffff);
36388c2ecf20Sopenharmony_ci	I915_WRITE(EMR, emr | *eir_stuck);
36398c2ecf20Sopenharmony_ci}
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_cistatic void i9xx_error_irq_handler(struct drm_i915_private *dev_priv,
36428c2ecf20Sopenharmony_ci				   u32 eir, u32 eir_stuck)
36438c2ecf20Sopenharmony_ci{
36448c2ecf20Sopenharmony_ci	DRM_DEBUG("Master Error, EIR 0x%08x\n", eir);
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	if (eir_stuck)
36478c2ecf20Sopenharmony_ci		drm_dbg(&dev_priv->drm, "EIR stuck: 0x%08x, masked\n",
36488c2ecf20Sopenharmony_ci			eir_stuck);
36498c2ecf20Sopenharmony_ci}
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_cistatic irqreturn_t i8xx_irq_handler(int irq, void *arg)
36528c2ecf20Sopenharmony_ci{
36538c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = arg;
36548c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
36558c2ecf20Sopenharmony_ci
36568c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv))
36578c2ecf20Sopenharmony_ci		return IRQ_NONE;
36588c2ecf20Sopenharmony_ci
36598c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
36608c2ecf20Sopenharmony_ci	disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_ci	do {
36638c2ecf20Sopenharmony_ci		u32 pipe_stats[I915_MAX_PIPES] = {};
36648c2ecf20Sopenharmony_ci		u16 eir = 0, eir_stuck = 0;
36658c2ecf20Sopenharmony_ci		u16 iir;
36668c2ecf20Sopenharmony_ci
36678c2ecf20Sopenharmony_ci		iir = intel_uncore_read16(&dev_priv->uncore, GEN2_IIR);
36688c2ecf20Sopenharmony_ci		if (iir == 0)
36698c2ecf20Sopenharmony_ci			break;
36708c2ecf20Sopenharmony_ci
36718c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
36728c2ecf20Sopenharmony_ci
36738c2ecf20Sopenharmony_ci		/* Call regardless, as some status bits might not be
36748c2ecf20Sopenharmony_ci		 * signalled in iir */
36758c2ecf20Sopenharmony_ci		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
36768c2ecf20Sopenharmony_ci
36778c2ecf20Sopenharmony_ci		if (iir & I915_MASTER_ERROR_INTERRUPT)
36788c2ecf20Sopenharmony_ci			i8xx_error_irq_ack(dev_priv, &eir, &eir_stuck);
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci		intel_uncore_write16(&dev_priv->uncore, GEN2_IIR, iir);
36818c2ecf20Sopenharmony_ci
36828c2ecf20Sopenharmony_ci		if (iir & I915_USER_INTERRUPT)
36838c2ecf20Sopenharmony_ci			intel_engine_signal_breadcrumbs(dev_priv->gt.engine[RCS0]);
36848c2ecf20Sopenharmony_ci
36858c2ecf20Sopenharmony_ci		if (iir & I915_MASTER_ERROR_INTERRUPT)
36868c2ecf20Sopenharmony_ci			i8xx_error_irq_handler(dev_priv, eir, eir_stuck);
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_ci		i8xx_pipestat_irq_handler(dev_priv, iir, pipe_stats);
36898c2ecf20Sopenharmony_ci	} while (0);
36908c2ecf20Sopenharmony_ci
36918c2ecf20Sopenharmony_ci	enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
36928c2ecf20Sopenharmony_ci
36938c2ecf20Sopenharmony_ci	return ret;
36948c2ecf20Sopenharmony_ci}
36958c2ecf20Sopenharmony_ci
36968c2ecf20Sopenharmony_cistatic void i915_irq_reset(struct drm_i915_private *dev_priv)
36978c2ecf20Sopenharmony_ci{
36988c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
36998c2ecf20Sopenharmony_ci
37008c2ecf20Sopenharmony_ci	if (I915_HAS_HOTPLUG(dev_priv)) {
37018c2ecf20Sopenharmony_ci		i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
37028c2ecf20Sopenharmony_ci		I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
37038c2ecf20Sopenharmony_ci	}
37048c2ecf20Sopenharmony_ci
37058c2ecf20Sopenharmony_ci	i9xx_pipestat_irq_reset(dev_priv);
37068c2ecf20Sopenharmony_ci
37078c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN2_);
37088c2ecf20Sopenharmony_ci}
37098c2ecf20Sopenharmony_ci
37108c2ecf20Sopenharmony_cistatic void i915_irq_postinstall(struct drm_i915_private *dev_priv)
37118c2ecf20Sopenharmony_ci{
37128c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
37138c2ecf20Sopenharmony_ci	u32 enable_mask;
37148c2ecf20Sopenharmony_ci
37158c2ecf20Sopenharmony_ci	I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE |
37168c2ecf20Sopenharmony_ci			  I915_ERROR_MEMORY_REFRESH));
37178c2ecf20Sopenharmony_ci
37188c2ecf20Sopenharmony_ci	/* Unmask the interrupts that we always want on. */
37198c2ecf20Sopenharmony_ci	dev_priv->irq_mask =
37208c2ecf20Sopenharmony_ci		~(I915_ASLE_INTERRUPT |
37218c2ecf20Sopenharmony_ci		  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
37228c2ecf20Sopenharmony_ci		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
37238c2ecf20Sopenharmony_ci		  I915_MASTER_ERROR_INTERRUPT);
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci	enable_mask =
37268c2ecf20Sopenharmony_ci		I915_ASLE_INTERRUPT |
37278c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
37288c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
37298c2ecf20Sopenharmony_ci		I915_MASTER_ERROR_INTERRUPT |
37308c2ecf20Sopenharmony_ci		I915_USER_INTERRUPT;
37318c2ecf20Sopenharmony_ci
37328c2ecf20Sopenharmony_ci	if (I915_HAS_HOTPLUG(dev_priv)) {
37338c2ecf20Sopenharmony_ci		/* Enable in IER... */
37348c2ecf20Sopenharmony_ci		enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
37358c2ecf20Sopenharmony_ci		/* and unmask in IMR */
37368c2ecf20Sopenharmony_ci		dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
37378c2ecf20Sopenharmony_ci	}
37388c2ecf20Sopenharmony_ci
37398c2ecf20Sopenharmony_ci	GEN3_IRQ_INIT(uncore, GEN2_, dev_priv->irq_mask, enable_mask);
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci	/* Interrupt setup is already guaranteed to be single-threaded, this is
37428c2ecf20Sopenharmony_ci	 * just to make the assert_spin_locked check happy. */
37438c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
37448c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
37458c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
37468c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_ci	i915_enable_asle_pipestat(dev_priv);
37498c2ecf20Sopenharmony_ci}
37508c2ecf20Sopenharmony_ci
37518c2ecf20Sopenharmony_cistatic irqreturn_t i915_irq_handler(int irq, void *arg)
37528c2ecf20Sopenharmony_ci{
37538c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = arg;
37548c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
37558c2ecf20Sopenharmony_ci
37568c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv))
37578c2ecf20Sopenharmony_ci		return IRQ_NONE;
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
37608c2ecf20Sopenharmony_ci	disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
37618c2ecf20Sopenharmony_ci
37628c2ecf20Sopenharmony_ci	do {
37638c2ecf20Sopenharmony_ci		u32 pipe_stats[I915_MAX_PIPES] = {};
37648c2ecf20Sopenharmony_ci		u32 eir = 0, eir_stuck = 0;
37658c2ecf20Sopenharmony_ci		u32 hotplug_status = 0;
37668c2ecf20Sopenharmony_ci		u32 iir;
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci		iir = I915_READ(GEN2_IIR);
37698c2ecf20Sopenharmony_ci		if (iir == 0)
37708c2ecf20Sopenharmony_ci			break;
37718c2ecf20Sopenharmony_ci
37728c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
37738c2ecf20Sopenharmony_ci
37748c2ecf20Sopenharmony_ci		if (I915_HAS_HOTPLUG(dev_priv) &&
37758c2ecf20Sopenharmony_ci		    iir & I915_DISPLAY_PORT_INTERRUPT)
37768c2ecf20Sopenharmony_ci			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
37778c2ecf20Sopenharmony_ci
37788c2ecf20Sopenharmony_ci		/* Call regardless, as some status bits might not be
37798c2ecf20Sopenharmony_ci		 * signalled in iir */
37808c2ecf20Sopenharmony_ci		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
37818c2ecf20Sopenharmony_ci
37828c2ecf20Sopenharmony_ci		if (iir & I915_MASTER_ERROR_INTERRUPT)
37838c2ecf20Sopenharmony_ci			i9xx_error_irq_ack(dev_priv, &eir, &eir_stuck);
37848c2ecf20Sopenharmony_ci
37858c2ecf20Sopenharmony_ci		I915_WRITE(GEN2_IIR, iir);
37868c2ecf20Sopenharmony_ci
37878c2ecf20Sopenharmony_ci		if (iir & I915_USER_INTERRUPT)
37888c2ecf20Sopenharmony_ci			intel_engine_signal_breadcrumbs(dev_priv->gt.engine[RCS0]);
37898c2ecf20Sopenharmony_ci
37908c2ecf20Sopenharmony_ci		if (iir & I915_MASTER_ERROR_INTERRUPT)
37918c2ecf20Sopenharmony_ci			i9xx_error_irq_handler(dev_priv, eir, eir_stuck);
37928c2ecf20Sopenharmony_ci
37938c2ecf20Sopenharmony_ci		if (hotplug_status)
37948c2ecf20Sopenharmony_ci			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
37958c2ecf20Sopenharmony_ci
37968c2ecf20Sopenharmony_ci		i915_pipestat_irq_handler(dev_priv, iir, pipe_stats);
37978c2ecf20Sopenharmony_ci	} while (0);
37988c2ecf20Sopenharmony_ci
37998c2ecf20Sopenharmony_ci	enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
38008c2ecf20Sopenharmony_ci
38018c2ecf20Sopenharmony_ci	return ret;
38028c2ecf20Sopenharmony_ci}
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_cistatic void i965_irq_reset(struct drm_i915_private *dev_priv)
38058c2ecf20Sopenharmony_ci{
38068c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
38078c2ecf20Sopenharmony_ci
38088c2ecf20Sopenharmony_ci	i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
38098c2ecf20Sopenharmony_ci	I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
38108c2ecf20Sopenharmony_ci
38118c2ecf20Sopenharmony_ci	i9xx_pipestat_irq_reset(dev_priv);
38128c2ecf20Sopenharmony_ci
38138c2ecf20Sopenharmony_ci	GEN3_IRQ_RESET(uncore, GEN2_);
38148c2ecf20Sopenharmony_ci}
38158c2ecf20Sopenharmony_ci
38168c2ecf20Sopenharmony_cistatic void i965_irq_postinstall(struct drm_i915_private *dev_priv)
38178c2ecf20Sopenharmony_ci{
38188c2ecf20Sopenharmony_ci	struct intel_uncore *uncore = &dev_priv->uncore;
38198c2ecf20Sopenharmony_ci	u32 enable_mask;
38208c2ecf20Sopenharmony_ci	u32 error_mask;
38218c2ecf20Sopenharmony_ci
38228c2ecf20Sopenharmony_ci	/*
38238c2ecf20Sopenharmony_ci	 * Enable some error detection, note the instruction error mask
38248c2ecf20Sopenharmony_ci	 * bit is reserved, so we leave it masked.
38258c2ecf20Sopenharmony_ci	 */
38268c2ecf20Sopenharmony_ci	if (IS_G4X(dev_priv)) {
38278c2ecf20Sopenharmony_ci		error_mask = ~(GM45_ERROR_PAGE_TABLE |
38288c2ecf20Sopenharmony_ci			       GM45_ERROR_MEM_PRIV |
38298c2ecf20Sopenharmony_ci			       GM45_ERROR_CP_PRIV |
38308c2ecf20Sopenharmony_ci			       I915_ERROR_MEMORY_REFRESH);
38318c2ecf20Sopenharmony_ci	} else {
38328c2ecf20Sopenharmony_ci		error_mask = ~(I915_ERROR_PAGE_TABLE |
38338c2ecf20Sopenharmony_ci			       I915_ERROR_MEMORY_REFRESH);
38348c2ecf20Sopenharmony_ci	}
38358c2ecf20Sopenharmony_ci	I915_WRITE(EMR, error_mask);
38368c2ecf20Sopenharmony_ci
38378c2ecf20Sopenharmony_ci	/* Unmask the interrupts that we always want on. */
38388c2ecf20Sopenharmony_ci	dev_priv->irq_mask =
38398c2ecf20Sopenharmony_ci		~(I915_ASLE_INTERRUPT |
38408c2ecf20Sopenharmony_ci		  I915_DISPLAY_PORT_INTERRUPT |
38418c2ecf20Sopenharmony_ci		  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
38428c2ecf20Sopenharmony_ci		  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
38438c2ecf20Sopenharmony_ci		  I915_MASTER_ERROR_INTERRUPT);
38448c2ecf20Sopenharmony_ci
38458c2ecf20Sopenharmony_ci	enable_mask =
38468c2ecf20Sopenharmony_ci		I915_ASLE_INTERRUPT |
38478c2ecf20Sopenharmony_ci		I915_DISPLAY_PORT_INTERRUPT |
38488c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
38498c2ecf20Sopenharmony_ci		I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
38508c2ecf20Sopenharmony_ci		I915_MASTER_ERROR_INTERRUPT |
38518c2ecf20Sopenharmony_ci		I915_USER_INTERRUPT;
38528c2ecf20Sopenharmony_ci
38538c2ecf20Sopenharmony_ci	if (IS_G4X(dev_priv))
38548c2ecf20Sopenharmony_ci		enable_mask |= I915_BSD_USER_INTERRUPT;
38558c2ecf20Sopenharmony_ci
38568c2ecf20Sopenharmony_ci	GEN3_IRQ_INIT(uncore, GEN2_, dev_priv->irq_mask, enable_mask);
38578c2ecf20Sopenharmony_ci
38588c2ecf20Sopenharmony_ci	/* Interrupt setup is already guaranteed to be single-threaded, this is
38598c2ecf20Sopenharmony_ci	 * just to make the assert_spin_locked check happy. */
38608c2ecf20Sopenharmony_ci	spin_lock_irq(&dev_priv->irq_lock);
38618c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
38628c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
38638c2ecf20Sopenharmony_ci	i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
38648c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev_priv->irq_lock);
38658c2ecf20Sopenharmony_ci
38668c2ecf20Sopenharmony_ci	i915_enable_asle_pipestat(dev_priv);
38678c2ecf20Sopenharmony_ci}
38688c2ecf20Sopenharmony_ci
38698c2ecf20Sopenharmony_cistatic void i915_hpd_irq_setup(struct drm_i915_private *dev_priv)
38708c2ecf20Sopenharmony_ci{
38718c2ecf20Sopenharmony_ci	u32 hotplug_en;
38728c2ecf20Sopenharmony_ci
38738c2ecf20Sopenharmony_ci	lockdep_assert_held(&dev_priv->irq_lock);
38748c2ecf20Sopenharmony_ci
38758c2ecf20Sopenharmony_ci	/* Note HDMI and DP share hotplug bits */
38768c2ecf20Sopenharmony_ci	/* enable bits are the same for all generations */
38778c2ecf20Sopenharmony_ci	hotplug_en = intel_hpd_enabled_irqs(dev_priv, hpd_mask_i915);
38788c2ecf20Sopenharmony_ci	/* Programming the CRT detection parameters tends
38798c2ecf20Sopenharmony_ci	   to generate a spurious hotplug event about three
38808c2ecf20Sopenharmony_ci	   seconds later.  So just do it once.
38818c2ecf20Sopenharmony_ci	*/
38828c2ecf20Sopenharmony_ci	if (IS_G4X(dev_priv))
38838c2ecf20Sopenharmony_ci		hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
38848c2ecf20Sopenharmony_ci	hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
38858c2ecf20Sopenharmony_ci
38868c2ecf20Sopenharmony_ci	/* Ignore TV since it's buggy */
38878c2ecf20Sopenharmony_ci	i915_hotplug_interrupt_update_locked(dev_priv,
38888c2ecf20Sopenharmony_ci					     HOTPLUG_INT_EN_MASK |
38898c2ecf20Sopenharmony_ci					     CRT_HOTPLUG_VOLTAGE_COMPARE_MASK |
38908c2ecf20Sopenharmony_ci					     CRT_HOTPLUG_ACTIVATION_PERIOD_64,
38918c2ecf20Sopenharmony_ci					     hotplug_en);
38928c2ecf20Sopenharmony_ci}
38938c2ecf20Sopenharmony_ci
38948c2ecf20Sopenharmony_cistatic irqreturn_t i965_irq_handler(int irq, void *arg)
38958c2ecf20Sopenharmony_ci{
38968c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = arg;
38978c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_ci	if (!intel_irqs_enabled(dev_priv))
39008c2ecf20Sopenharmony_ci		return IRQ_NONE;
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_ci	/* IRQs are synced during runtime_suspend, we don't require a wakeref */
39038c2ecf20Sopenharmony_ci	disable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ci	do {
39068c2ecf20Sopenharmony_ci		u32 pipe_stats[I915_MAX_PIPES] = {};
39078c2ecf20Sopenharmony_ci		u32 eir = 0, eir_stuck = 0;
39088c2ecf20Sopenharmony_ci		u32 hotplug_status = 0;
39098c2ecf20Sopenharmony_ci		u32 iir;
39108c2ecf20Sopenharmony_ci
39118c2ecf20Sopenharmony_ci		iir = I915_READ(GEN2_IIR);
39128c2ecf20Sopenharmony_ci		if (iir == 0)
39138c2ecf20Sopenharmony_ci			break;
39148c2ecf20Sopenharmony_ci
39158c2ecf20Sopenharmony_ci		ret = IRQ_HANDLED;
39168c2ecf20Sopenharmony_ci
39178c2ecf20Sopenharmony_ci		if (iir & I915_DISPLAY_PORT_INTERRUPT)
39188c2ecf20Sopenharmony_ci			hotplug_status = i9xx_hpd_irq_ack(dev_priv);
39198c2ecf20Sopenharmony_ci
39208c2ecf20Sopenharmony_ci		/* Call regardless, as some status bits might not be
39218c2ecf20Sopenharmony_ci		 * signalled in iir */
39228c2ecf20Sopenharmony_ci		i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
39238c2ecf20Sopenharmony_ci
39248c2ecf20Sopenharmony_ci		if (iir & I915_MASTER_ERROR_INTERRUPT)
39258c2ecf20Sopenharmony_ci			i9xx_error_irq_ack(dev_priv, &eir, &eir_stuck);
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_ci		I915_WRITE(GEN2_IIR, iir);
39288c2ecf20Sopenharmony_ci
39298c2ecf20Sopenharmony_ci		if (iir & I915_USER_INTERRUPT)
39308c2ecf20Sopenharmony_ci			intel_engine_signal_breadcrumbs(dev_priv->gt.engine[RCS0]);
39318c2ecf20Sopenharmony_ci
39328c2ecf20Sopenharmony_ci		if (iir & I915_BSD_USER_INTERRUPT)
39338c2ecf20Sopenharmony_ci			intel_engine_signal_breadcrumbs(dev_priv->gt.engine[VCS0]);
39348c2ecf20Sopenharmony_ci
39358c2ecf20Sopenharmony_ci		if (iir & I915_MASTER_ERROR_INTERRUPT)
39368c2ecf20Sopenharmony_ci			i9xx_error_irq_handler(dev_priv, eir, eir_stuck);
39378c2ecf20Sopenharmony_ci
39388c2ecf20Sopenharmony_ci		if (hotplug_status)
39398c2ecf20Sopenharmony_ci			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
39408c2ecf20Sopenharmony_ci
39418c2ecf20Sopenharmony_ci		i965_pipestat_irq_handler(dev_priv, iir, pipe_stats);
39428c2ecf20Sopenharmony_ci	} while (0);
39438c2ecf20Sopenharmony_ci
39448c2ecf20Sopenharmony_ci	enable_rpm_wakeref_asserts(&dev_priv->runtime_pm);
39458c2ecf20Sopenharmony_ci
39468c2ecf20Sopenharmony_ci	return ret;
39478c2ecf20Sopenharmony_ci}
39488c2ecf20Sopenharmony_ci
39498c2ecf20Sopenharmony_ci/**
39508c2ecf20Sopenharmony_ci * intel_irq_init - initializes irq support
39518c2ecf20Sopenharmony_ci * @dev_priv: i915 device instance
39528c2ecf20Sopenharmony_ci *
39538c2ecf20Sopenharmony_ci * This function initializes all the irq support including work items, timers
39548c2ecf20Sopenharmony_ci * and all the vtables. It does not setup the interrupt itself though.
39558c2ecf20Sopenharmony_ci */
39568c2ecf20Sopenharmony_civoid intel_irq_init(struct drm_i915_private *dev_priv)
39578c2ecf20Sopenharmony_ci{
39588c2ecf20Sopenharmony_ci	struct drm_device *dev = &dev_priv->drm;
39598c2ecf20Sopenharmony_ci	int i;
39608c2ecf20Sopenharmony_ci
39618c2ecf20Sopenharmony_ci	intel_hpd_init_pins(dev_priv);
39628c2ecf20Sopenharmony_ci
39638c2ecf20Sopenharmony_ci	intel_hpd_init_work(dev_priv);
39648c2ecf20Sopenharmony_ci
39658c2ecf20Sopenharmony_ci	INIT_WORK(&dev_priv->l3_parity.error_work, ivb_parity_work);
39668c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_L3_SLICES; ++i)
39678c2ecf20Sopenharmony_ci		dev_priv->l3_parity.remap_info[i] = NULL;
39688c2ecf20Sopenharmony_ci
39698c2ecf20Sopenharmony_ci	/* pre-gen11 the guc irqs bits are in the upper 16 bits of the pm reg */
39708c2ecf20Sopenharmony_ci	if (HAS_GT_UC(dev_priv) && INTEL_GEN(dev_priv) < 11)
39718c2ecf20Sopenharmony_ci		dev_priv->gt.pm_guc_events = GUC_INTR_GUC2HOST << 16;
39728c2ecf20Sopenharmony_ci
39738c2ecf20Sopenharmony_ci	dev->vblank_disable_immediate = true;
39748c2ecf20Sopenharmony_ci
39758c2ecf20Sopenharmony_ci	/* Most platforms treat the display irq block as an always-on
39768c2ecf20Sopenharmony_ci	 * power domain. vlv/chv can disable it at runtime and need
39778c2ecf20Sopenharmony_ci	 * special care to avoid writing any of the display block registers
39788c2ecf20Sopenharmony_ci	 * outside of the power domain. We defer setting up the display irqs
39798c2ecf20Sopenharmony_ci	 * in this case to the runtime pm.
39808c2ecf20Sopenharmony_ci	 */
39818c2ecf20Sopenharmony_ci	dev_priv->display_irqs_enabled = true;
39828c2ecf20Sopenharmony_ci	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
39838c2ecf20Sopenharmony_ci		dev_priv->display_irqs_enabled = false;
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci	dev_priv->hotplug.hpd_storm_threshold = HPD_STORM_DEFAULT_THRESHOLD;
39868c2ecf20Sopenharmony_ci	/* If we have MST support, we want to avoid doing short HPD IRQ storm
39878c2ecf20Sopenharmony_ci	 * detection, as short HPD storms will occur as a natural part of
39888c2ecf20Sopenharmony_ci	 * sideband messaging with MST.
39898c2ecf20Sopenharmony_ci	 * On older platforms however, IRQ storms can occur with both long and
39908c2ecf20Sopenharmony_ci	 * short pulses, as seen on some G4x systems.
39918c2ecf20Sopenharmony_ci	 */
39928c2ecf20Sopenharmony_ci	dev_priv->hotplug.hpd_short_storm_enabled = !HAS_DP_MST(dev_priv);
39938c2ecf20Sopenharmony_ci
39948c2ecf20Sopenharmony_ci	if (HAS_GMCH(dev_priv)) {
39958c2ecf20Sopenharmony_ci		if (I915_HAS_HOTPLUG(dev_priv))
39968c2ecf20Sopenharmony_ci			dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
39978c2ecf20Sopenharmony_ci	} else {
39988c2ecf20Sopenharmony_ci		if (HAS_PCH_JSP(dev_priv))
39998c2ecf20Sopenharmony_ci			dev_priv->display.hpd_irq_setup = jsp_hpd_irq_setup;
40008c2ecf20Sopenharmony_ci		else if (HAS_PCH_MCC(dev_priv))
40018c2ecf20Sopenharmony_ci			dev_priv->display.hpd_irq_setup = mcc_hpd_irq_setup;
40028c2ecf20Sopenharmony_ci		else if (INTEL_GEN(dev_priv) >= 11)
40038c2ecf20Sopenharmony_ci			dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup;
40048c2ecf20Sopenharmony_ci		else if (IS_GEN9_LP(dev_priv))
40058c2ecf20Sopenharmony_ci			dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup;
40068c2ecf20Sopenharmony_ci		else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT)
40078c2ecf20Sopenharmony_ci			dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup;
40088c2ecf20Sopenharmony_ci		else
40098c2ecf20Sopenharmony_ci			dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
40108c2ecf20Sopenharmony_ci	}
40118c2ecf20Sopenharmony_ci}
40128c2ecf20Sopenharmony_ci
40138c2ecf20Sopenharmony_ci/**
40148c2ecf20Sopenharmony_ci * intel_irq_fini - deinitializes IRQ support
40158c2ecf20Sopenharmony_ci * @i915: i915 device instance
40168c2ecf20Sopenharmony_ci *
40178c2ecf20Sopenharmony_ci * This function deinitializes all the IRQ support.
40188c2ecf20Sopenharmony_ci */
40198c2ecf20Sopenharmony_civoid intel_irq_fini(struct drm_i915_private *i915)
40208c2ecf20Sopenharmony_ci{
40218c2ecf20Sopenharmony_ci	int i;
40228c2ecf20Sopenharmony_ci
40238c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_L3_SLICES; ++i)
40248c2ecf20Sopenharmony_ci		kfree(i915->l3_parity.remap_info[i]);
40258c2ecf20Sopenharmony_ci}
40268c2ecf20Sopenharmony_ci
40278c2ecf20Sopenharmony_cistatic irq_handler_t intel_irq_handler(struct drm_i915_private *dev_priv)
40288c2ecf20Sopenharmony_ci{
40298c2ecf20Sopenharmony_ci	if (HAS_GMCH(dev_priv)) {
40308c2ecf20Sopenharmony_ci		if (IS_CHERRYVIEW(dev_priv))
40318c2ecf20Sopenharmony_ci			return cherryview_irq_handler;
40328c2ecf20Sopenharmony_ci		else if (IS_VALLEYVIEW(dev_priv))
40338c2ecf20Sopenharmony_ci			return valleyview_irq_handler;
40348c2ecf20Sopenharmony_ci		else if (IS_GEN(dev_priv, 4))
40358c2ecf20Sopenharmony_ci			return i965_irq_handler;
40368c2ecf20Sopenharmony_ci		else if (IS_GEN(dev_priv, 3))
40378c2ecf20Sopenharmony_ci			return i915_irq_handler;
40388c2ecf20Sopenharmony_ci		else
40398c2ecf20Sopenharmony_ci			return i8xx_irq_handler;
40408c2ecf20Sopenharmony_ci	} else {
40418c2ecf20Sopenharmony_ci		if (HAS_MASTER_UNIT_IRQ(dev_priv))
40428c2ecf20Sopenharmony_ci			return dg1_irq_handler;
40438c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 11)
40448c2ecf20Sopenharmony_ci			return gen11_irq_handler;
40458c2ecf20Sopenharmony_ci		else if (INTEL_GEN(dev_priv) >= 8)
40468c2ecf20Sopenharmony_ci			return gen8_irq_handler;
40478c2ecf20Sopenharmony_ci		else
40488c2ecf20Sopenharmony_ci			return ilk_irq_handler;
40498c2ecf20Sopenharmony_ci	}
40508c2ecf20Sopenharmony_ci}
40518c2ecf20Sopenharmony_ci
40528c2ecf20Sopenharmony_cistatic void intel_irq_reset(struct drm_i915_private *dev_priv)
40538c2ecf20Sopenharmony_ci{
40548c2ecf20Sopenharmony_ci	if (HAS_GMCH(dev_priv)) {
40558c2ecf20Sopenharmony_ci		if (IS_CHERRYVIEW(dev_priv))
40568c2ecf20Sopenharmony_ci			cherryview_irq_reset(dev_priv);
40578c2ecf20Sopenharmony_ci		else if (IS_VALLEYVIEW(dev_priv))
40588c2ecf20Sopenharmony_ci			valleyview_irq_reset(dev_priv);
40598c2ecf20Sopenharmony_ci		else if (IS_GEN(dev_priv, 4))
40608c2ecf20Sopenharmony_ci			i965_irq_reset(dev_priv);
40618c2ecf20Sopenharmony_ci		else if (IS_GEN(dev_priv, 3))
40628c2ecf20Sopenharmony_ci			i915_irq_reset(dev_priv);
40638c2ecf20Sopenharmony_ci		else
40648c2ecf20Sopenharmony_ci			i8xx_irq_reset(dev_priv);
40658c2ecf20Sopenharmony_ci	} else {
40668c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 11)
40678c2ecf20Sopenharmony_ci			gen11_irq_reset(dev_priv);
40688c2ecf20Sopenharmony_ci		else if (INTEL_GEN(dev_priv) >= 8)
40698c2ecf20Sopenharmony_ci			gen8_irq_reset(dev_priv);
40708c2ecf20Sopenharmony_ci		else
40718c2ecf20Sopenharmony_ci			ilk_irq_reset(dev_priv);
40728c2ecf20Sopenharmony_ci	}
40738c2ecf20Sopenharmony_ci}
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_cistatic void intel_irq_postinstall(struct drm_i915_private *dev_priv)
40768c2ecf20Sopenharmony_ci{
40778c2ecf20Sopenharmony_ci	if (HAS_GMCH(dev_priv)) {
40788c2ecf20Sopenharmony_ci		if (IS_CHERRYVIEW(dev_priv))
40798c2ecf20Sopenharmony_ci			cherryview_irq_postinstall(dev_priv);
40808c2ecf20Sopenharmony_ci		else if (IS_VALLEYVIEW(dev_priv))
40818c2ecf20Sopenharmony_ci			valleyview_irq_postinstall(dev_priv);
40828c2ecf20Sopenharmony_ci		else if (IS_GEN(dev_priv, 4))
40838c2ecf20Sopenharmony_ci			i965_irq_postinstall(dev_priv);
40848c2ecf20Sopenharmony_ci		else if (IS_GEN(dev_priv, 3))
40858c2ecf20Sopenharmony_ci			i915_irq_postinstall(dev_priv);
40868c2ecf20Sopenharmony_ci		else
40878c2ecf20Sopenharmony_ci			i8xx_irq_postinstall(dev_priv);
40888c2ecf20Sopenharmony_ci	} else {
40898c2ecf20Sopenharmony_ci		if (INTEL_GEN(dev_priv) >= 11)
40908c2ecf20Sopenharmony_ci			gen11_irq_postinstall(dev_priv);
40918c2ecf20Sopenharmony_ci		else if (INTEL_GEN(dev_priv) >= 8)
40928c2ecf20Sopenharmony_ci			gen8_irq_postinstall(dev_priv);
40938c2ecf20Sopenharmony_ci		else
40948c2ecf20Sopenharmony_ci			ilk_irq_postinstall(dev_priv);
40958c2ecf20Sopenharmony_ci	}
40968c2ecf20Sopenharmony_ci}
40978c2ecf20Sopenharmony_ci
40988c2ecf20Sopenharmony_ci/**
40998c2ecf20Sopenharmony_ci * intel_irq_install - enables the hardware interrupt
41008c2ecf20Sopenharmony_ci * @dev_priv: i915 device instance
41018c2ecf20Sopenharmony_ci *
41028c2ecf20Sopenharmony_ci * This function enables the hardware interrupt handling, but leaves the hotplug
41038c2ecf20Sopenharmony_ci * handling still disabled. It is called after intel_irq_init().
41048c2ecf20Sopenharmony_ci *
41058c2ecf20Sopenharmony_ci * In the driver load and resume code we need working interrupts in a few places
41068c2ecf20Sopenharmony_ci * but don't want to deal with the hassle of concurrent probe and hotplug
41078c2ecf20Sopenharmony_ci * workers. Hence the split into this two-stage approach.
41088c2ecf20Sopenharmony_ci */
41098c2ecf20Sopenharmony_ciint intel_irq_install(struct drm_i915_private *dev_priv)
41108c2ecf20Sopenharmony_ci{
41118c2ecf20Sopenharmony_ci	int irq = dev_priv->drm.pdev->irq;
41128c2ecf20Sopenharmony_ci	int ret;
41138c2ecf20Sopenharmony_ci
41148c2ecf20Sopenharmony_ci	/*
41158c2ecf20Sopenharmony_ci	 * We enable some interrupt sources in our postinstall hooks, so mark
41168c2ecf20Sopenharmony_ci	 * interrupts as enabled _before_ actually enabling them to avoid
41178c2ecf20Sopenharmony_ci	 * special cases in our ordering checks.
41188c2ecf20Sopenharmony_ci	 */
41198c2ecf20Sopenharmony_ci	dev_priv->runtime_pm.irqs_enabled = true;
41208c2ecf20Sopenharmony_ci
41218c2ecf20Sopenharmony_ci	dev_priv->drm.irq_enabled = true;
41228c2ecf20Sopenharmony_ci
41238c2ecf20Sopenharmony_ci	intel_irq_reset(dev_priv);
41248c2ecf20Sopenharmony_ci
41258c2ecf20Sopenharmony_ci	ret = request_irq(irq, intel_irq_handler(dev_priv),
41268c2ecf20Sopenharmony_ci			  IRQF_SHARED, DRIVER_NAME, dev_priv);
41278c2ecf20Sopenharmony_ci	if (ret < 0) {
41288c2ecf20Sopenharmony_ci		dev_priv->drm.irq_enabled = false;
41298c2ecf20Sopenharmony_ci		return ret;
41308c2ecf20Sopenharmony_ci	}
41318c2ecf20Sopenharmony_ci
41328c2ecf20Sopenharmony_ci	intel_irq_postinstall(dev_priv);
41338c2ecf20Sopenharmony_ci
41348c2ecf20Sopenharmony_ci	return ret;
41358c2ecf20Sopenharmony_ci}
41368c2ecf20Sopenharmony_ci
41378c2ecf20Sopenharmony_ci/**
41388c2ecf20Sopenharmony_ci * intel_irq_uninstall - finilizes all irq handling
41398c2ecf20Sopenharmony_ci * @dev_priv: i915 device instance
41408c2ecf20Sopenharmony_ci *
41418c2ecf20Sopenharmony_ci * This stops interrupt and hotplug handling and unregisters and frees all
41428c2ecf20Sopenharmony_ci * resources acquired in the init functions.
41438c2ecf20Sopenharmony_ci */
41448c2ecf20Sopenharmony_civoid intel_irq_uninstall(struct drm_i915_private *dev_priv)
41458c2ecf20Sopenharmony_ci{
41468c2ecf20Sopenharmony_ci	int irq = dev_priv->drm.pdev->irq;
41478c2ecf20Sopenharmony_ci
41488c2ecf20Sopenharmony_ci	/*
41498c2ecf20Sopenharmony_ci	 * FIXME we can get called twice during driver probe
41508c2ecf20Sopenharmony_ci	 * error handling as well as during driver remove due to
41518c2ecf20Sopenharmony_ci	 * intel_modeset_driver_remove() calling us out of sequence.
41528c2ecf20Sopenharmony_ci	 * Would be nice if it didn't do that...
41538c2ecf20Sopenharmony_ci	 */
41548c2ecf20Sopenharmony_ci	if (!dev_priv->drm.irq_enabled)
41558c2ecf20Sopenharmony_ci		return;
41568c2ecf20Sopenharmony_ci
41578c2ecf20Sopenharmony_ci	dev_priv->drm.irq_enabled = false;
41588c2ecf20Sopenharmony_ci
41598c2ecf20Sopenharmony_ci	intel_irq_reset(dev_priv);
41608c2ecf20Sopenharmony_ci
41618c2ecf20Sopenharmony_ci	free_irq(irq, dev_priv);
41628c2ecf20Sopenharmony_ci
41638c2ecf20Sopenharmony_ci	intel_hpd_cancel_work(dev_priv);
41648c2ecf20Sopenharmony_ci	dev_priv->runtime_pm.irqs_enabled = false;
41658c2ecf20Sopenharmony_ci}
41668c2ecf20Sopenharmony_ci
41678c2ecf20Sopenharmony_ci/**
41688c2ecf20Sopenharmony_ci * intel_runtime_pm_disable_interrupts - runtime interrupt disabling
41698c2ecf20Sopenharmony_ci * @dev_priv: i915 device instance
41708c2ecf20Sopenharmony_ci *
41718c2ecf20Sopenharmony_ci * This function is used to disable interrupts at runtime, both in the runtime
41728c2ecf20Sopenharmony_ci * pm and the system suspend/resume code.
41738c2ecf20Sopenharmony_ci */
41748c2ecf20Sopenharmony_civoid intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
41758c2ecf20Sopenharmony_ci{
41768c2ecf20Sopenharmony_ci	intel_irq_reset(dev_priv);
41778c2ecf20Sopenharmony_ci	dev_priv->runtime_pm.irqs_enabled = false;
41788c2ecf20Sopenharmony_ci	intel_synchronize_irq(dev_priv);
41798c2ecf20Sopenharmony_ci}
41808c2ecf20Sopenharmony_ci
41818c2ecf20Sopenharmony_ci/**
41828c2ecf20Sopenharmony_ci * intel_runtime_pm_enable_interrupts - runtime interrupt enabling
41838c2ecf20Sopenharmony_ci * @dev_priv: i915 device instance
41848c2ecf20Sopenharmony_ci *
41858c2ecf20Sopenharmony_ci * This function is used to enable interrupts at runtime, both in the runtime
41868c2ecf20Sopenharmony_ci * pm and the system suspend/resume code.
41878c2ecf20Sopenharmony_ci */
41888c2ecf20Sopenharmony_civoid intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
41898c2ecf20Sopenharmony_ci{
41908c2ecf20Sopenharmony_ci	dev_priv->runtime_pm.irqs_enabled = true;
41918c2ecf20Sopenharmony_ci	intel_irq_reset(dev_priv);
41928c2ecf20Sopenharmony_ci	intel_irq_postinstall(dev_priv);
41938c2ecf20Sopenharmony_ci}
41948c2ecf20Sopenharmony_ci
41958c2ecf20Sopenharmony_cibool intel_irqs_enabled(struct drm_i915_private *dev_priv)
41968c2ecf20Sopenharmony_ci{
41978c2ecf20Sopenharmony_ci	/*
41988c2ecf20Sopenharmony_ci	 * We only use drm_irq_uninstall() at unload and VT switch, so
41998c2ecf20Sopenharmony_ci	 * this is the only thing we need to check.
42008c2ecf20Sopenharmony_ci	 */
42018c2ecf20Sopenharmony_ci	return dev_priv->runtime_pm.irqs_enabled;
42028c2ecf20Sopenharmony_ci}
42038c2ecf20Sopenharmony_ci
42048c2ecf20Sopenharmony_civoid intel_synchronize_irq(struct drm_i915_private *i915)
42058c2ecf20Sopenharmony_ci{
42068c2ecf20Sopenharmony_ci	synchronize_irq(i915->drm.pdev->irq);
42078c2ecf20Sopenharmony_ci}
4208