1 /* $NetBSD: intel_pch.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $ */ 2 3 // SPDX-License-Identifier: MIT 4 /* 5 * Copyright 2019 Intel Corporation. 6 */ 7 8 #include <sys/cdefs.h> 9 __KERNEL_RCSID(0, "$NetBSD: intel_pch.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $"); 10 11 #include "i915_drv.h" 12 #include "intel_pch.h" 13 14 /* Map PCH device id to PCH type, or PCH_NONE if unknown. */ 15 static enum intel_pch 16 intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) 17 { 18 switch (id) { 19 case INTEL_PCH_IBX_DEVICE_ID_TYPE: 20 drm_dbg_kms(&dev_priv->drm, "Found Ibex Peak PCH\n"); 21 WARN_ON(!IS_GEN(dev_priv, 5)); 22 return PCH_IBX; 23 case INTEL_PCH_CPT_DEVICE_ID_TYPE: 24 drm_dbg_kms(&dev_priv->drm, "Found CougarPoint PCH\n"); 25 WARN_ON(!IS_GEN(dev_priv, 6) && !IS_IVYBRIDGE(dev_priv)); 26 return PCH_CPT; 27 case INTEL_PCH_PPT_DEVICE_ID_TYPE: 28 drm_dbg_kms(&dev_priv->drm, "Found PantherPoint PCH\n"); 29 WARN_ON(!IS_GEN(dev_priv, 6) && !IS_IVYBRIDGE(dev_priv)); 30 /* PantherPoint is CPT compatible */ 31 return PCH_CPT; 32 case INTEL_PCH_LPT_DEVICE_ID_TYPE: 33 drm_dbg_kms(&dev_priv->drm, "Found LynxPoint PCH\n"); 34 WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 35 WARN_ON(IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv)); 36 return PCH_LPT; 37 case INTEL_PCH_LPT_LP_DEVICE_ID_TYPE: 38 drm_dbg_kms(&dev_priv->drm, "Found LynxPoint LP PCH\n"); 39 WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 40 WARN_ON(!IS_HSW_ULT(dev_priv) && !IS_BDW_ULT(dev_priv)); 41 return PCH_LPT; 42 case INTEL_PCH_WPT_DEVICE_ID_TYPE: 43 drm_dbg_kms(&dev_priv->drm, "Found WildcatPoint PCH\n"); 44 WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 45 WARN_ON(IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv)); 46 /* WildcatPoint is LPT compatible */ 47 return PCH_LPT; 48 case INTEL_PCH_WPT_LP_DEVICE_ID_TYPE: 49 drm_dbg_kms(&dev_priv->drm, "Found WildcatPoint LP PCH\n"); 50 WARN_ON(!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)); 51 WARN_ON(!IS_HSW_ULT(dev_priv) && !IS_BDW_ULT(dev_priv)); 52 /* WildcatPoint is LPT compatible */ 53 return PCH_LPT; 54 case INTEL_PCH_SPT_DEVICE_ID_TYPE: 55 drm_dbg_kms(&dev_priv->drm, "Found SunrisePoint PCH\n"); 56 WARN_ON(!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv)); 57 return PCH_SPT; 58 case INTEL_PCH_SPT_LP_DEVICE_ID_TYPE: 59 drm_dbg_kms(&dev_priv->drm, "Found SunrisePoint LP PCH\n"); 60 WARN_ON(!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv) && 61 !IS_COFFEELAKE(dev_priv)); 62 return PCH_SPT; 63 case INTEL_PCH_KBP_DEVICE_ID_TYPE: 64 drm_dbg_kms(&dev_priv->drm, "Found Kaby Lake PCH (KBP)\n"); 65 WARN_ON(!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv) && 66 !IS_COFFEELAKE(dev_priv)); 67 /* KBP is SPT compatible */ 68 return PCH_SPT; 69 case INTEL_PCH_CNP_DEVICE_ID_TYPE: 70 drm_dbg_kms(&dev_priv->drm, "Found Cannon Lake PCH (CNP)\n"); 71 WARN_ON(!IS_CANNONLAKE(dev_priv) && !IS_COFFEELAKE(dev_priv)); 72 return PCH_CNP; 73 case INTEL_PCH_CNP_LP_DEVICE_ID_TYPE: 74 drm_dbg_kms(&dev_priv->drm, 75 "Found Cannon Lake LP PCH (CNP-LP)\n"); 76 WARN_ON(!IS_CANNONLAKE(dev_priv) && !IS_COFFEELAKE(dev_priv)); 77 return PCH_CNP; 78 case INTEL_PCH_CMP_DEVICE_ID_TYPE: 79 case INTEL_PCH_CMP2_DEVICE_ID_TYPE: 80 drm_dbg_kms(&dev_priv->drm, "Found Comet Lake PCH (CMP)\n"); 81 WARN_ON(!IS_COFFEELAKE(dev_priv)); 82 /* CometPoint is CNP Compatible */ 83 return PCH_CNP; 84 case INTEL_PCH_CMP_V_DEVICE_ID_TYPE: 85 drm_dbg_kms(&dev_priv->drm, "Found Comet Lake V PCH (CMP-V)\n"); 86 WARN_ON(!IS_COFFEELAKE(dev_priv)); 87 /* Comet Lake V PCH is based on KBP, which is SPT compatible */ 88 return PCH_SPT; 89 case INTEL_PCH_ICP_DEVICE_ID_TYPE: 90 drm_dbg_kms(&dev_priv->drm, "Found Ice Lake PCH\n"); 91 WARN_ON(!IS_ICELAKE(dev_priv)); 92 return PCH_ICP; 93 case INTEL_PCH_MCC_DEVICE_ID_TYPE: 94 drm_dbg_kms(&dev_priv->drm, "Found Mule Creek Canyon PCH\n"); 95 WARN_ON(!IS_ELKHARTLAKE(dev_priv)); 96 return PCH_MCC; 97 case INTEL_PCH_TGP_DEVICE_ID_TYPE: 98 case INTEL_PCH_TGP2_DEVICE_ID_TYPE: 99 drm_dbg_kms(&dev_priv->drm, "Found Tiger Lake LP PCH\n"); 100 WARN_ON(!IS_TIGERLAKE(dev_priv)); 101 return PCH_TGP; 102 case INTEL_PCH_JSP_DEVICE_ID_TYPE: 103 case INTEL_PCH_JSP2_DEVICE_ID_TYPE: 104 drm_dbg_kms(&dev_priv->drm, "Found Jasper Lake PCH\n"); 105 WARN_ON(!IS_ELKHARTLAKE(dev_priv)); 106 return PCH_JSP; 107 default: 108 return PCH_NONE; 109 } 110 } 111 112 static bool intel_is_virt_pch(unsigned short id, 113 unsigned short svendor, unsigned short sdevice) 114 { 115 return (id == INTEL_PCH_P2X_DEVICE_ID_TYPE || 116 id == INTEL_PCH_P3X_DEVICE_ID_TYPE || 117 (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE && 118 svendor == PCI_SUBVENDOR_ID_REDHAT_QUMRANET && 119 sdevice == PCI_SUBDEVICE_ID_QEMU)); 120 } 121 122 static unsigned short 123 intel_virt_detect_pch(const struct drm_i915_private *dev_priv) 124 { 125 unsigned short id = 0; 126 127 /* 128 * In a virtualized passthrough environment we can be in a 129 * setup where the ISA bridge is not able to be passed through. 130 * In this case, a south bridge can be emulated and we have to 131 * make an educated guess as to which PCH is really there. 132 */ 133 134 if (IS_TIGERLAKE(dev_priv)) 135 id = INTEL_PCH_TGP_DEVICE_ID_TYPE; 136 else if (IS_ELKHARTLAKE(dev_priv)) 137 id = INTEL_PCH_MCC_DEVICE_ID_TYPE; 138 else if (IS_ICELAKE(dev_priv)) 139 id = INTEL_PCH_ICP_DEVICE_ID_TYPE; 140 else if (IS_CANNONLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) 141 id = INTEL_PCH_CNP_DEVICE_ID_TYPE; 142 else if (IS_KABYLAKE(dev_priv) || IS_SKYLAKE(dev_priv)) 143 id = INTEL_PCH_SPT_DEVICE_ID_TYPE; 144 else if (IS_HSW_ULT(dev_priv) || IS_BDW_ULT(dev_priv)) 145 id = INTEL_PCH_LPT_LP_DEVICE_ID_TYPE; 146 else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) 147 id = INTEL_PCH_LPT_DEVICE_ID_TYPE; 148 else if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv)) 149 id = INTEL_PCH_CPT_DEVICE_ID_TYPE; 150 else if (IS_GEN(dev_priv, 5)) 151 id = INTEL_PCH_IBX_DEVICE_ID_TYPE; 152 153 if (id) 154 drm_dbg_kms(&dev_priv->drm, "Assuming PCH ID %04x\n", id); 155 else 156 drm_dbg_kms(&dev_priv->drm, "Assuming no PCH\n"); 157 158 return id; 159 } 160 161 void intel_detect_pch(struct drm_i915_private *dev_priv) 162 { 163 struct pci_dev *pch = NULL; 164 165 /* 166 * The reason to probe ISA bridge instead of Dev31:Fun0 is to 167 * make graphics device passthrough work easy for VMM, that only 168 * need to expose ISA bridge to let driver know the real hardware 169 * underneath. This is a requirement from virtualization team. 170 * 171 * In some virtualized environments (e.g. XEN), there is irrelevant 172 * ISA bridge in the system. To work reliably, we should scan trhough 173 * all the ISA bridge devices and check for the first match, instead 174 * of only checking the first one. 175 */ 176 while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) { 177 unsigned short id; 178 enum intel_pch pch_type; 179 180 if (pch->vendor != PCI_VENDOR_ID_INTEL) 181 continue; 182 183 id = pch->device & INTEL_PCH_DEVICE_ID_MASK; 184 185 pch_type = intel_pch_type(dev_priv, id); 186 if (pch_type != PCH_NONE) { 187 dev_priv->pch_type = pch_type; 188 dev_priv->pch_id = id; 189 break; 190 } else if (intel_is_virt_pch(id, pch->subsystem_vendor, 191 pch->subsystem_device)) { 192 id = intel_virt_detect_pch(dev_priv); 193 pch_type = intel_pch_type(dev_priv, id); 194 195 /* Sanity check virtual PCH id */ 196 if (WARN_ON(id && pch_type == PCH_NONE)) 197 id = 0; 198 199 dev_priv->pch_type = pch_type; 200 dev_priv->pch_id = id; 201 break; 202 } 203 } 204 205 /* 206 * Use PCH_NOP (PCH but no South Display) for PCH platforms without 207 * display. 208 */ 209 if (pch && !HAS_DISPLAY(dev_priv)) { 210 drm_dbg_kms(&dev_priv->drm, 211 "Display disabled, reverting to NOP PCH\n"); 212 dev_priv->pch_type = PCH_NOP; 213 dev_priv->pch_id = 0; 214 } 215 216 if (!pch) 217 drm_dbg_kms(&dev_priv->drm, "No PCH found.\n"); 218 219 pci_dev_put(pch); 220 } 221