18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2019 Intel Corporation.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "i915_drv.h"
78c2ecf20Sopenharmony_ci#include "intel_pch.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci/* Map PCH device id to PCH type, or PCH_NONE if unknown. */
108c2ecf20Sopenharmony_cistatic enum intel_pch
118c2ecf20Sopenharmony_ciintel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	switch (id) {
148c2ecf20Sopenharmony_ci	case INTEL_PCH_IBX_DEVICE_ID_TYPE:
158c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Ibex Peak PCH\n");
168c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, !IS_GEN(dev_priv, 5));
178c2ecf20Sopenharmony_ci		return PCH_IBX;
188c2ecf20Sopenharmony_ci	case INTEL_PCH_CPT_DEVICE_ID_TYPE:
198c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found CougarPoint PCH\n");
208c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
218c2ecf20Sopenharmony_ci			    !IS_GEN(dev_priv, 6) && !IS_IVYBRIDGE(dev_priv));
228c2ecf20Sopenharmony_ci		return PCH_CPT;
238c2ecf20Sopenharmony_ci	case INTEL_PCH_PPT_DEVICE_ID_TYPE:
248c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found PantherPoint PCH\n");
258c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
268c2ecf20Sopenharmony_ci			    !IS_GEN(dev_priv, 6) && !IS_IVYBRIDGE(dev_priv));
278c2ecf20Sopenharmony_ci		/* PantherPoint is CPT compatible */
288c2ecf20Sopenharmony_ci		return PCH_CPT;
298c2ecf20Sopenharmony_ci	case INTEL_PCH_LPT_DEVICE_ID_TYPE:
308c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found LynxPoint PCH\n");
318c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
328c2ecf20Sopenharmony_ci			    !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
338c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
348c2ecf20Sopenharmony_ci			    IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv));
358c2ecf20Sopenharmony_ci		return PCH_LPT;
368c2ecf20Sopenharmony_ci	case INTEL_PCH_LPT_LP_DEVICE_ID_TYPE:
378c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found LynxPoint LP PCH\n");
388c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
398c2ecf20Sopenharmony_ci			    !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
408c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
418c2ecf20Sopenharmony_ci			    !IS_HSW_ULT(dev_priv) && !IS_BDW_ULT(dev_priv));
428c2ecf20Sopenharmony_ci		return PCH_LPT;
438c2ecf20Sopenharmony_ci	case INTEL_PCH_WPT_DEVICE_ID_TYPE:
448c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found WildcatPoint PCH\n");
458c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
468c2ecf20Sopenharmony_ci			    !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
478c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
488c2ecf20Sopenharmony_ci			    IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv));
498c2ecf20Sopenharmony_ci		/* WildcatPoint is LPT compatible */
508c2ecf20Sopenharmony_ci		return PCH_LPT;
518c2ecf20Sopenharmony_ci	case INTEL_PCH_WPT_LP_DEVICE_ID_TYPE:
528c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found WildcatPoint LP PCH\n");
538c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
548c2ecf20Sopenharmony_ci			    !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv));
558c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
568c2ecf20Sopenharmony_ci			    !IS_HSW_ULT(dev_priv) && !IS_BDW_ULT(dev_priv));
578c2ecf20Sopenharmony_ci		/* WildcatPoint is LPT compatible */
588c2ecf20Sopenharmony_ci		return PCH_LPT;
598c2ecf20Sopenharmony_ci	case INTEL_PCH_SPT_DEVICE_ID_TYPE:
608c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found SunrisePoint PCH\n");
618c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
628c2ecf20Sopenharmony_ci			    !IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv));
638c2ecf20Sopenharmony_ci		return PCH_SPT;
648c2ecf20Sopenharmony_ci	case INTEL_PCH_SPT_LP_DEVICE_ID_TYPE:
658c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found SunrisePoint LP PCH\n");
668c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
678c2ecf20Sopenharmony_ci			    !IS_SKYLAKE(dev_priv) &&
688c2ecf20Sopenharmony_ci			    !IS_KABYLAKE(dev_priv) &&
698c2ecf20Sopenharmony_ci			    !IS_COFFEELAKE(dev_priv) &&
708c2ecf20Sopenharmony_ci			    !IS_COMETLAKE(dev_priv));
718c2ecf20Sopenharmony_ci		return PCH_SPT;
728c2ecf20Sopenharmony_ci	case INTEL_PCH_KBP_DEVICE_ID_TYPE:
738c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Kaby Lake PCH (KBP)\n");
748c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
758c2ecf20Sopenharmony_ci			    !IS_SKYLAKE(dev_priv) &&
768c2ecf20Sopenharmony_ci			    !IS_KABYLAKE(dev_priv) &&
778c2ecf20Sopenharmony_ci			    !IS_COFFEELAKE(dev_priv) &&
788c2ecf20Sopenharmony_ci			    !IS_COMETLAKE(dev_priv));
798c2ecf20Sopenharmony_ci		/* KBP is SPT compatible */
808c2ecf20Sopenharmony_ci		return PCH_SPT;
818c2ecf20Sopenharmony_ci	case INTEL_PCH_CNP_DEVICE_ID_TYPE:
828c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Cannon Lake PCH (CNP)\n");
838c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
848c2ecf20Sopenharmony_ci			    !IS_CANNONLAKE(dev_priv) &&
858c2ecf20Sopenharmony_ci			    !IS_COFFEELAKE(dev_priv) &&
868c2ecf20Sopenharmony_ci			    !IS_COMETLAKE(dev_priv));
878c2ecf20Sopenharmony_ci		return PCH_CNP;
888c2ecf20Sopenharmony_ci	case INTEL_PCH_CNP_LP_DEVICE_ID_TYPE:
898c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
908c2ecf20Sopenharmony_ci			    "Found Cannon Lake LP PCH (CNP-LP)\n");
918c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
928c2ecf20Sopenharmony_ci			    !IS_CANNONLAKE(dev_priv) &&
938c2ecf20Sopenharmony_ci			    !IS_COFFEELAKE(dev_priv) &&
948c2ecf20Sopenharmony_ci			    !IS_COMETLAKE(dev_priv));
958c2ecf20Sopenharmony_ci		return PCH_CNP;
968c2ecf20Sopenharmony_ci	case INTEL_PCH_CMP_DEVICE_ID_TYPE:
978c2ecf20Sopenharmony_ci	case INTEL_PCH_CMP2_DEVICE_ID_TYPE:
988c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Comet Lake PCH (CMP)\n");
998c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
1008c2ecf20Sopenharmony_ci			    !IS_COFFEELAKE(dev_priv) &&
1018c2ecf20Sopenharmony_ci			    !IS_COMETLAKE(dev_priv) &&
1028c2ecf20Sopenharmony_ci			    !IS_ROCKETLAKE(dev_priv));
1038c2ecf20Sopenharmony_ci		/* CometPoint is CNP Compatible */
1048c2ecf20Sopenharmony_ci		return PCH_CNP;
1058c2ecf20Sopenharmony_ci	case INTEL_PCH_CMP_V_DEVICE_ID_TYPE:
1068c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Comet Lake V PCH (CMP-V)\n");
1078c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm,
1088c2ecf20Sopenharmony_ci			    !IS_COFFEELAKE(dev_priv) &&
1098c2ecf20Sopenharmony_ci			    !IS_COMETLAKE(dev_priv));
1108c2ecf20Sopenharmony_ci		/* Comet Lake V PCH is based on KBP, which is SPT compatible */
1118c2ecf20Sopenharmony_ci		return PCH_SPT;
1128c2ecf20Sopenharmony_ci	case INTEL_PCH_ICP_DEVICE_ID_TYPE:
1138c2ecf20Sopenharmony_ci	case INTEL_PCH_ICP2_DEVICE_ID_TYPE:
1148c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Ice Lake PCH\n");
1158c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, !IS_ICELAKE(dev_priv));
1168c2ecf20Sopenharmony_ci		return PCH_ICP;
1178c2ecf20Sopenharmony_ci	case INTEL_PCH_MCC_DEVICE_ID_TYPE:
1188c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Mule Creek Canyon PCH\n");
1198c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, !IS_ELKHARTLAKE(dev_priv));
1208c2ecf20Sopenharmony_ci		return PCH_MCC;
1218c2ecf20Sopenharmony_ci	case INTEL_PCH_TGP_DEVICE_ID_TYPE:
1228c2ecf20Sopenharmony_ci	case INTEL_PCH_TGP2_DEVICE_ID_TYPE:
1238c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Tiger Lake LP PCH\n");
1248c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, !IS_TIGERLAKE(dev_priv) &&
1258c2ecf20Sopenharmony_ci			    !IS_ROCKETLAKE(dev_priv));
1268c2ecf20Sopenharmony_ci		return PCH_TGP;
1278c2ecf20Sopenharmony_ci	case INTEL_PCH_JSP_DEVICE_ID_TYPE:
1288c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Found Jasper Lake PCH\n");
1298c2ecf20Sopenharmony_ci		drm_WARN_ON(&dev_priv->drm, !IS_ELKHARTLAKE(dev_priv));
1308c2ecf20Sopenharmony_ci		return PCH_JSP;
1318c2ecf20Sopenharmony_ci	default:
1328c2ecf20Sopenharmony_ci		return PCH_NONE;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic bool intel_is_virt_pch(unsigned short id,
1378c2ecf20Sopenharmony_ci			      unsigned short svendor, unsigned short sdevice)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	return (id == INTEL_PCH_P2X_DEVICE_ID_TYPE ||
1408c2ecf20Sopenharmony_ci		id == INTEL_PCH_P3X_DEVICE_ID_TYPE ||
1418c2ecf20Sopenharmony_ci		(id == INTEL_PCH_QEMU_DEVICE_ID_TYPE &&
1428c2ecf20Sopenharmony_ci		 svendor == PCI_SUBVENDOR_ID_REDHAT_QUMRANET &&
1438c2ecf20Sopenharmony_ci		 sdevice == PCI_SUBDEVICE_ID_QEMU));
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic unsigned short
1478c2ecf20Sopenharmony_ciintel_virt_detect_pch(const struct drm_i915_private *dev_priv)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	unsigned short id = 0;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/*
1528c2ecf20Sopenharmony_ci	 * In a virtualized passthrough environment we can be in a
1538c2ecf20Sopenharmony_ci	 * setup where the ISA bridge is not able to be passed through.
1548c2ecf20Sopenharmony_ci	 * In this case, a south bridge can be emulated and we have to
1558c2ecf20Sopenharmony_ci	 * make an educated guess as to which PCH is really there.
1568c2ecf20Sopenharmony_ci	 */
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv))
1598c2ecf20Sopenharmony_ci		id = INTEL_PCH_TGP_DEVICE_ID_TYPE;
1608c2ecf20Sopenharmony_ci	else if (IS_ELKHARTLAKE(dev_priv))
1618c2ecf20Sopenharmony_ci		id = INTEL_PCH_MCC_DEVICE_ID_TYPE;
1628c2ecf20Sopenharmony_ci	else if (IS_ICELAKE(dev_priv))
1638c2ecf20Sopenharmony_ci		id = INTEL_PCH_ICP_DEVICE_ID_TYPE;
1648c2ecf20Sopenharmony_ci	else if (IS_CANNONLAKE(dev_priv) ||
1658c2ecf20Sopenharmony_ci		 IS_COFFEELAKE(dev_priv) ||
1668c2ecf20Sopenharmony_ci		 IS_COMETLAKE(dev_priv))
1678c2ecf20Sopenharmony_ci		id = INTEL_PCH_CNP_DEVICE_ID_TYPE;
1688c2ecf20Sopenharmony_ci	else if (IS_KABYLAKE(dev_priv) || IS_SKYLAKE(dev_priv))
1698c2ecf20Sopenharmony_ci		id = INTEL_PCH_SPT_DEVICE_ID_TYPE;
1708c2ecf20Sopenharmony_ci	else if (IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv))
1718c2ecf20Sopenharmony_ci		id = INTEL_PCH_LPT_LP_DEVICE_ID_TYPE;
1728c2ecf20Sopenharmony_ci	else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
1738c2ecf20Sopenharmony_ci		id = INTEL_PCH_LPT_DEVICE_ID_TYPE;
1748c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
1758c2ecf20Sopenharmony_ci		id = INTEL_PCH_CPT_DEVICE_ID_TYPE;
1768c2ecf20Sopenharmony_ci	else if (IS_GEN(dev_priv, 5))
1778c2ecf20Sopenharmony_ci		id = INTEL_PCH_IBX_DEVICE_ID_TYPE;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (id)
1808c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Assuming PCH ID %04x\n", id);
1818c2ecf20Sopenharmony_ci	else
1828c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "Assuming no PCH\n");
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return id;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_civoid intel_detect_pch(struct drm_i915_private *dev_priv)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct pci_dev *pch = NULL;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* DG1 has south engine display on the same PCI device */
1928c2ecf20Sopenharmony_ci	if (IS_DG1(dev_priv)) {
1938c2ecf20Sopenharmony_ci		dev_priv->pch_type = PCH_DG1;
1948c2ecf20Sopenharmony_ci		return;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/*
1988c2ecf20Sopenharmony_ci	 * The reason to probe ISA bridge instead of Dev31:Fun0 is to
1998c2ecf20Sopenharmony_ci	 * make graphics device passthrough work easy for VMM, that only
2008c2ecf20Sopenharmony_ci	 * need to expose ISA bridge to let driver know the real hardware
2018c2ecf20Sopenharmony_ci	 * underneath. This is a requirement from virtualization team.
2028c2ecf20Sopenharmony_ci	 *
2038c2ecf20Sopenharmony_ci	 * In some virtualized environments (e.g. XEN), there is irrelevant
2048c2ecf20Sopenharmony_ci	 * ISA bridge in the system. To work reliably, we should scan trhough
2058c2ecf20Sopenharmony_ci	 * all the ISA bridge devices and check for the first match, instead
2068c2ecf20Sopenharmony_ci	 * of only checking the first one.
2078c2ecf20Sopenharmony_ci	 */
2088c2ecf20Sopenharmony_ci	while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
2098c2ecf20Sopenharmony_ci		unsigned short id;
2108c2ecf20Sopenharmony_ci		enum intel_pch pch_type;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci		if (pch->vendor != PCI_VENDOR_ID_INTEL)
2138c2ecf20Sopenharmony_ci			continue;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		pch_type = intel_pch_type(dev_priv, id);
2188c2ecf20Sopenharmony_ci		if (pch_type != PCH_NONE) {
2198c2ecf20Sopenharmony_ci			dev_priv->pch_type = pch_type;
2208c2ecf20Sopenharmony_ci			dev_priv->pch_id = id;
2218c2ecf20Sopenharmony_ci			break;
2228c2ecf20Sopenharmony_ci		} else if (intel_is_virt_pch(id, pch->subsystem_vendor,
2238c2ecf20Sopenharmony_ci					     pch->subsystem_device)) {
2248c2ecf20Sopenharmony_ci			id = intel_virt_detect_pch(dev_priv);
2258c2ecf20Sopenharmony_ci			pch_type = intel_pch_type(dev_priv, id);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci			/* Sanity check virtual PCH id */
2288c2ecf20Sopenharmony_ci			if (drm_WARN_ON(&dev_priv->drm,
2298c2ecf20Sopenharmony_ci					id && pch_type == PCH_NONE))
2308c2ecf20Sopenharmony_ci				id = 0;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci			dev_priv->pch_type = pch_type;
2338c2ecf20Sopenharmony_ci			dev_priv->pch_id = id;
2348c2ecf20Sopenharmony_ci			break;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/*
2398c2ecf20Sopenharmony_ci	 * Use PCH_NOP (PCH but no South Display) for PCH platforms without
2408c2ecf20Sopenharmony_ci	 * display.
2418c2ecf20Sopenharmony_ci	 */
2428c2ecf20Sopenharmony_ci	if (pch && !HAS_DISPLAY(dev_priv)) {
2438c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
2448c2ecf20Sopenharmony_ci			    "Display disabled, reverting to NOP PCH\n");
2458c2ecf20Sopenharmony_ci		dev_priv->pch_type = PCH_NOP;
2468c2ecf20Sopenharmony_ci		dev_priv->pch_id = 0;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (!pch)
2508c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm, "No PCH found.\n");
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	pci_dev_put(pch);
2538c2ecf20Sopenharmony_ci}
254