162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2019 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "i915_drv.h" 762306a36Sopenharmony_ci#include "i915_utils.h" 862306a36Sopenharmony_ci#include "intel_pch.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* Map PCH device id to PCH type, or PCH_NONE if unknown. */ 1162306a36Sopenharmony_cistatic enum intel_pch 1262306a36Sopenharmony_ciintel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci switch (id) { 1562306a36Sopenharmony_ci case INTEL_PCH_IBX_DEVICE_ID_TYPE: 1662306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Ibex Peak PCH\n"); 1762306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, GRAPHICS_VER(dev_priv) != 5); 1862306a36Sopenharmony_ci return PCH_IBX; 1962306a36Sopenharmony_ci case INTEL_PCH_CPT_DEVICE_ID_TYPE: 2062306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found CougarPoint PCH\n"); 2162306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 2262306a36Sopenharmony_ci GRAPHICS_VER(dev_priv) != 6 && !IS_IVYBRIDGE(dev_priv)); 2362306a36Sopenharmony_ci return PCH_CPT; 2462306a36Sopenharmony_ci case INTEL_PCH_PPT_DEVICE_ID_TYPE: 2562306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found PantherPoint PCH\n"); 2662306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 2762306a36Sopenharmony_ci GRAPHICS_VER(dev_priv) != 6 && !IS_IVYBRIDGE(dev_priv)); 2862306a36Sopenharmony_ci /* PPT is CPT compatible */ 2962306a36Sopenharmony_ci return PCH_CPT; 3062306a36Sopenharmony_ci case INTEL_PCH_LPT_DEVICE_ID_TYPE: 3162306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found LynxPoint PCH\n"); 3262306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 3362306a36Sopenharmony_ci !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 3462306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 3562306a36Sopenharmony_ci IS_HASWELL_ULT(dev_priv) || IS_BROADWELL_ULT(dev_priv)); 3662306a36Sopenharmony_ci return PCH_LPT; 3762306a36Sopenharmony_ci case INTEL_PCH_LPT_LP_DEVICE_ID_TYPE: 3862306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found LynxPoint LP PCH\n"); 3962306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 4062306a36Sopenharmony_ci !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 4162306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 4262306a36Sopenharmony_ci !IS_HASWELL_ULT(dev_priv) && !IS_BROADWELL_ULT(dev_priv)); 4362306a36Sopenharmony_ci return PCH_LPT; 4462306a36Sopenharmony_ci case INTEL_PCH_WPT_DEVICE_ID_TYPE: 4562306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found WildcatPoint PCH\n"); 4662306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 4762306a36Sopenharmony_ci !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 4862306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 4962306a36Sopenharmony_ci IS_HASWELL_ULT(dev_priv) || IS_BROADWELL_ULT(dev_priv)); 5062306a36Sopenharmony_ci /* WPT is LPT compatible */ 5162306a36Sopenharmony_ci return PCH_LPT; 5262306a36Sopenharmony_ci case INTEL_PCH_WPT_LP_DEVICE_ID_TYPE: 5362306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found WildcatPoint LP PCH\n"); 5462306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 5562306a36Sopenharmony_ci !IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 5662306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 5762306a36Sopenharmony_ci !IS_HASWELL_ULT(dev_priv) && !IS_BROADWELL_ULT(dev_priv)); 5862306a36Sopenharmony_ci /* WPT is LPT compatible */ 5962306a36Sopenharmony_ci return PCH_LPT; 6062306a36Sopenharmony_ci case INTEL_PCH_SPT_DEVICE_ID_TYPE: 6162306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found SunrisePoint PCH\n"); 6262306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 6362306a36Sopenharmony_ci !IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv)); 6462306a36Sopenharmony_ci return PCH_SPT; 6562306a36Sopenharmony_ci case INTEL_PCH_SPT_LP_DEVICE_ID_TYPE: 6662306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found SunrisePoint LP PCH\n"); 6762306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 6862306a36Sopenharmony_ci !IS_SKYLAKE(dev_priv) && 6962306a36Sopenharmony_ci !IS_KABYLAKE(dev_priv) && 7062306a36Sopenharmony_ci !IS_COFFEELAKE(dev_priv) && 7162306a36Sopenharmony_ci !IS_COMETLAKE(dev_priv)); 7262306a36Sopenharmony_ci return PCH_SPT; 7362306a36Sopenharmony_ci case INTEL_PCH_KBP_DEVICE_ID_TYPE: 7462306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Kaby Lake PCH (KBP)\n"); 7562306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 7662306a36Sopenharmony_ci !IS_SKYLAKE(dev_priv) && 7762306a36Sopenharmony_ci !IS_KABYLAKE(dev_priv) && 7862306a36Sopenharmony_ci !IS_COFFEELAKE(dev_priv) && 7962306a36Sopenharmony_ci !IS_COMETLAKE(dev_priv)); 8062306a36Sopenharmony_ci /* KBP is SPT compatible */ 8162306a36Sopenharmony_ci return PCH_SPT; 8262306a36Sopenharmony_ci case INTEL_PCH_CNP_DEVICE_ID_TYPE: 8362306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Cannon Lake PCH (CNP)\n"); 8462306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 8562306a36Sopenharmony_ci !IS_COFFEELAKE(dev_priv) && 8662306a36Sopenharmony_ci !IS_COMETLAKE(dev_priv)); 8762306a36Sopenharmony_ci return PCH_CNP; 8862306a36Sopenharmony_ci case INTEL_PCH_CNP_LP_DEVICE_ID_TYPE: 8962306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, 9062306a36Sopenharmony_ci "Found Cannon Lake LP PCH (CNP-LP)\n"); 9162306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 9262306a36Sopenharmony_ci !IS_COFFEELAKE(dev_priv) && 9362306a36Sopenharmony_ci !IS_COMETLAKE(dev_priv)); 9462306a36Sopenharmony_ci return PCH_CNP; 9562306a36Sopenharmony_ci case INTEL_PCH_CMP_DEVICE_ID_TYPE: 9662306a36Sopenharmony_ci case INTEL_PCH_CMP2_DEVICE_ID_TYPE: 9762306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Comet Lake PCH (CMP)\n"); 9862306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 9962306a36Sopenharmony_ci !IS_COFFEELAKE(dev_priv) && 10062306a36Sopenharmony_ci !IS_COMETLAKE(dev_priv) && 10162306a36Sopenharmony_ci !IS_ROCKETLAKE(dev_priv)); 10262306a36Sopenharmony_ci /* CMP is CNP compatible */ 10362306a36Sopenharmony_ci return PCH_CNP; 10462306a36Sopenharmony_ci case INTEL_PCH_CMP_V_DEVICE_ID_TYPE: 10562306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Comet Lake V PCH (CMP-V)\n"); 10662306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, 10762306a36Sopenharmony_ci !IS_COFFEELAKE(dev_priv) && 10862306a36Sopenharmony_ci !IS_COMETLAKE(dev_priv)); 10962306a36Sopenharmony_ci /* CMP-V is based on KBP, which is SPT compatible */ 11062306a36Sopenharmony_ci return PCH_SPT; 11162306a36Sopenharmony_ci case INTEL_PCH_ICP_DEVICE_ID_TYPE: 11262306a36Sopenharmony_ci case INTEL_PCH_ICP2_DEVICE_ID_TYPE: 11362306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Ice Lake PCH\n"); 11462306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, !IS_ICELAKE(dev_priv)); 11562306a36Sopenharmony_ci return PCH_ICP; 11662306a36Sopenharmony_ci case INTEL_PCH_MCC_DEVICE_ID_TYPE: 11762306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Mule Creek Canyon PCH\n"); 11862306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, !(IS_JASPERLAKE(dev_priv) || 11962306a36Sopenharmony_ci IS_ELKHARTLAKE(dev_priv))); 12062306a36Sopenharmony_ci /* MCC is TGP compatible */ 12162306a36Sopenharmony_ci return PCH_TGP; 12262306a36Sopenharmony_ci case INTEL_PCH_TGP_DEVICE_ID_TYPE: 12362306a36Sopenharmony_ci case INTEL_PCH_TGP2_DEVICE_ID_TYPE: 12462306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Tiger Lake LP PCH\n"); 12562306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, !IS_TIGERLAKE(dev_priv) && 12662306a36Sopenharmony_ci !IS_ROCKETLAKE(dev_priv) && 12762306a36Sopenharmony_ci !IS_GEN9_BC(dev_priv)); 12862306a36Sopenharmony_ci return PCH_TGP; 12962306a36Sopenharmony_ci case INTEL_PCH_JSP_DEVICE_ID_TYPE: 13062306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Jasper Lake PCH\n"); 13162306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, !(IS_JASPERLAKE(dev_priv) || 13262306a36Sopenharmony_ci IS_ELKHARTLAKE(dev_priv))); 13362306a36Sopenharmony_ci /* JSP is ICP compatible */ 13462306a36Sopenharmony_ci return PCH_ICP; 13562306a36Sopenharmony_ci case INTEL_PCH_ADP_DEVICE_ID_TYPE: 13662306a36Sopenharmony_ci case INTEL_PCH_ADP2_DEVICE_ID_TYPE: 13762306a36Sopenharmony_ci case INTEL_PCH_ADP3_DEVICE_ID_TYPE: 13862306a36Sopenharmony_ci case INTEL_PCH_ADP4_DEVICE_ID_TYPE: 13962306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Alder Lake PCH\n"); 14062306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, !IS_ALDERLAKE_S(dev_priv) && 14162306a36Sopenharmony_ci !IS_ALDERLAKE_P(dev_priv)); 14262306a36Sopenharmony_ci return PCH_ADP; 14362306a36Sopenharmony_ci case INTEL_PCH_MTP_DEVICE_ID_TYPE: 14462306a36Sopenharmony_ci case INTEL_PCH_MTP2_DEVICE_ID_TYPE: 14562306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Found Meteor Lake PCH\n"); 14662306a36Sopenharmony_ci drm_WARN_ON(&dev_priv->drm, !IS_METEORLAKE(dev_priv)); 14762306a36Sopenharmony_ci return PCH_MTP; 14862306a36Sopenharmony_ci default: 14962306a36Sopenharmony_ci return PCH_NONE; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic bool intel_is_virt_pch(unsigned short id, 15462306a36Sopenharmony_ci unsigned short svendor, unsigned short sdevice) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci return (id == INTEL_PCH_P2X_DEVICE_ID_TYPE || 15762306a36Sopenharmony_ci id == INTEL_PCH_P3X_DEVICE_ID_TYPE || 15862306a36Sopenharmony_ci (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE && 15962306a36Sopenharmony_ci svendor == PCI_SUBVENDOR_ID_REDHAT_QUMRANET && 16062306a36Sopenharmony_ci sdevice == PCI_SUBDEVICE_ID_QEMU)); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic void 16462306a36Sopenharmony_ciintel_virt_detect_pch(const struct drm_i915_private *dev_priv, 16562306a36Sopenharmony_ci unsigned short *pch_id, enum intel_pch *pch_type) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci unsigned short id = 0; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * In a virtualized passthrough environment we can be in a 17162306a36Sopenharmony_ci * setup where the ISA bridge is not able to be passed through. 17262306a36Sopenharmony_ci * In this case, a south bridge can be emulated and we have to 17362306a36Sopenharmony_ci * make an educated guess as to which PCH is really there. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (IS_METEORLAKE(dev_priv)) 17762306a36Sopenharmony_ci id = INTEL_PCH_MTP_DEVICE_ID_TYPE; 17862306a36Sopenharmony_ci else if (IS_ALDERLAKE_S(dev_priv) || IS_ALDERLAKE_P(dev_priv)) 17962306a36Sopenharmony_ci id = INTEL_PCH_ADP_DEVICE_ID_TYPE; 18062306a36Sopenharmony_ci else if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) 18162306a36Sopenharmony_ci id = INTEL_PCH_TGP_DEVICE_ID_TYPE; 18262306a36Sopenharmony_ci else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) 18362306a36Sopenharmony_ci id = INTEL_PCH_MCC_DEVICE_ID_TYPE; 18462306a36Sopenharmony_ci else if (IS_ICELAKE(dev_priv)) 18562306a36Sopenharmony_ci id = INTEL_PCH_ICP_DEVICE_ID_TYPE; 18662306a36Sopenharmony_ci else if (IS_COFFEELAKE(dev_priv) || 18762306a36Sopenharmony_ci IS_COMETLAKE(dev_priv)) 18862306a36Sopenharmony_ci id = INTEL_PCH_CNP_DEVICE_ID_TYPE; 18962306a36Sopenharmony_ci else if (IS_KABYLAKE(dev_priv) || IS_SKYLAKE(dev_priv)) 19062306a36Sopenharmony_ci id = INTEL_PCH_SPT_DEVICE_ID_TYPE; 19162306a36Sopenharmony_ci else if (IS_HASWELL_ULT(dev_priv) || IS_BROADWELL_ULT(dev_priv)) 19262306a36Sopenharmony_ci id = INTEL_PCH_LPT_LP_DEVICE_ID_TYPE; 19362306a36Sopenharmony_ci else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) 19462306a36Sopenharmony_ci id = INTEL_PCH_LPT_DEVICE_ID_TYPE; 19562306a36Sopenharmony_ci else if (GRAPHICS_VER(dev_priv) == 6 || IS_IVYBRIDGE(dev_priv)) 19662306a36Sopenharmony_ci id = INTEL_PCH_CPT_DEVICE_ID_TYPE; 19762306a36Sopenharmony_ci else if (GRAPHICS_VER(dev_priv) == 5) 19862306a36Sopenharmony_ci id = INTEL_PCH_IBX_DEVICE_ID_TYPE; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (id) 20162306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Assuming PCH ID %04x\n", id); 20262306a36Sopenharmony_ci else 20362306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "Assuming no PCH\n"); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci *pch_type = intel_pch_type(dev_priv, id); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Sanity check virtual PCH id */ 20862306a36Sopenharmony_ci if (drm_WARN_ON(&dev_priv->drm, 20962306a36Sopenharmony_ci id && *pch_type == PCH_NONE)) 21062306a36Sopenharmony_ci id = 0; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci *pch_id = id; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_civoid intel_detect_pch(struct drm_i915_private *dev_priv) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct pci_dev *pch = NULL; 21862306a36Sopenharmony_ci unsigned short id; 21962306a36Sopenharmony_ci enum intel_pch pch_type; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* DG1 has south engine display on the same PCI device */ 22262306a36Sopenharmony_ci if (IS_DG1(dev_priv)) { 22362306a36Sopenharmony_ci dev_priv->pch_type = PCH_DG1; 22462306a36Sopenharmony_ci return; 22562306a36Sopenharmony_ci } else if (IS_DG2(dev_priv)) { 22662306a36Sopenharmony_ci dev_priv->pch_type = PCH_DG2; 22762306a36Sopenharmony_ci return; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * The reason to probe ISA bridge instead of Dev31:Fun0 is to 23262306a36Sopenharmony_ci * make graphics device passthrough work easy for VMM, that only 23362306a36Sopenharmony_ci * need to expose ISA bridge to let driver know the real hardware 23462306a36Sopenharmony_ci * underneath. This is a requirement from virtualization team. 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * In some virtualized environments (e.g. XEN), there is irrelevant 23762306a36Sopenharmony_ci * ISA bridge in the system. To work reliably, we should scan trhough 23862306a36Sopenharmony_ci * all the ISA bridge devices and check for the first match, instead 23962306a36Sopenharmony_ci * of only checking the first one. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) { 24262306a36Sopenharmony_ci if (pch->vendor != PCI_VENDOR_ID_INTEL) 24362306a36Sopenharmony_ci continue; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci id = pch->device & INTEL_PCH_DEVICE_ID_MASK; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci pch_type = intel_pch_type(dev_priv, id); 24862306a36Sopenharmony_ci if (pch_type != PCH_NONE) { 24962306a36Sopenharmony_ci dev_priv->pch_type = pch_type; 25062306a36Sopenharmony_ci dev_priv->pch_id = id; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci } else if (intel_is_virt_pch(id, pch->subsystem_vendor, 25362306a36Sopenharmony_ci pch->subsystem_device)) { 25462306a36Sopenharmony_ci intel_virt_detect_pch(dev_priv, &id, &pch_type); 25562306a36Sopenharmony_ci dev_priv->pch_type = pch_type; 25662306a36Sopenharmony_ci dev_priv->pch_id = id; 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* 26262306a36Sopenharmony_ci * Use PCH_NOP (PCH but no South Display) for PCH platforms without 26362306a36Sopenharmony_ci * display. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci if (pch && !HAS_DISPLAY(dev_priv)) { 26662306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, 26762306a36Sopenharmony_ci "Display disabled, reverting to NOP PCH\n"); 26862306a36Sopenharmony_ci dev_priv->pch_type = PCH_NOP; 26962306a36Sopenharmony_ci dev_priv->pch_id = 0; 27062306a36Sopenharmony_ci } else if (!pch) { 27162306a36Sopenharmony_ci if (i915_run_as_guest() && HAS_DISPLAY(dev_priv)) { 27262306a36Sopenharmony_ci intel_virt_detect_pch(dev_priv, &id, &pch_type); 27362306a36Sopenharmony_ci dev_priv->pch_type = pch_type; 27462306a36Sopenharmony_ci dev_priv->pch_id = id; 27562306a36Sopenharmony_ci } else { 27662306a36Sopenharmony_ci drm_dbg_kms(&dev_priv->drm, "No PCH found.\n"); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci pci_dev_put(pch); 28162306a36Sopenharmony_ci} 282