1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2025 Intel Corporation. 4 */ 5 6 #include <drm/drm_print.h> 7 8 #include "i915_utils.h" 9 #include "intel_display_core.h" 10 #include "intel_pch.h" 11 12 #define INTEL_PCH_DEVICE_ID_MASK 0xff80 13 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 14 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 15 #define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00 16 #define INTEL_PCH_LPT_DEVICE_ID_TYPE 0x8c00 17 #define INTEL_PCH_LPT_LP_DEVICE_ID_TYPE 0x9c00 18 #define INTEL_PCH_WPT_DEVICE_ID_TYPE 0x8c80 19 #define INTEL_PCH_WPT_LP_DEVICE_ID_TYPE 0x9c80 20 #define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100 21 #define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE 0x9D00 22 #define INTEL_PCH_KBP_DEVICE_ID_TYPE 0xA280 23 #define INTEL_PCH_CNP_DEVICE_ID_TYPE 0xA300 24 #define INTEL_PCH_CNP_LP_DEVICE_ID_TYPE 0x9D80 25 #define INTEL_PCH_CMP_DEVICE_ID_TYPE 0x0280 26 #define INTEL_PCH_CMP2_DEVICE_ID_TYPE 0x0680 27 #define INTEL_PCH_CMP_V_DEVICE_ID_TYPE 0xA380 28 #define INTEL_PCH_ICP_DEVICE_ID_TYPE 0x3480 29 #define INTEL_PCH_ICP2_DEVICE_ID_TYPE 0x3880 30 #define INTEL_PCH_MCC_DEVICE_ID_TYPE 0x4B00 31 #define INTEL_PCH_TGP_DEVICE_ID_TYPE 0xA080 32 #define INTEL_PCH_TGP2_DEVICE_ID_TYPE 0x4380 33 #define INTEL_PCH_JSP_DEVICE_ID_TYPE 0x4D80 34 #define INTEL_PCH_ADP_DEVICE_ID_TYPE 0x7A80 35 #define INTEL_PCH_ADP2_DEVICE_ID_TYPE 0x5180 36 #define INTEL_PCH_ADP3_DEVICE_ID_TYPE 0x7A00 37 #define INTEL_PCH_ADP4_DEVICE_ID_TYPE 0x5480 38 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 39 #define INTEL_PCH_P3X_DEVICE_ID_TYPE 0x7000 40 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ 41 42 /* 43 * Check for platforms where the south display is on the same PCI device or SoC 44 * die as the north display. The PCH (if it even exists) is not involved in 45 * display. Return a fake PCH type for south display handling on these 46 * platforms, without actually detecting the PCH, and PCH_NONE otherwise. 47 */ 48 static enum intel_pch intel_pch_fake_for_south_display(struct intel_display *display) 49 { 50 enum intel_pch pch_type = PCH_NONE; 51 52 if (DISPLAY_VER(display) >= 20) 53 pch_type = PCH_LNL; 54 else if (display->platform.battlemage || display->platform.meteorlake) 55 pch_type = PCH_MTL; 56 else if (display->platform.dg2) 57 pch_type = PCH_DG2; 58 else if (display->platform.dg1) 59 pch_type = PCH_DG1; 60 61 return pch_type; 62 } 63 64 /* Map PCH device id to PCH type, or PCH_NONE if unknown. */ 65 static enum intel_pch 66 intel_pch_type(const struct intel_display *display, unsigned short id) 67 { 68 switch (id) { 69 case INTEL_PCH_IBX_DEVICE_ID_TYPE: 70 drm_dbg_kms(display->drm, "Found Ibex Peak PCH\n"); 71 drm_WARN_ON(display->drm, DISPLAY_VER(display) != 5); 72 return PCH_IBX; 73 case INTEL_PCH_CPT_DEVICE_ID_TYPE: 74 drm_dbg_kms(display->drm, "Found CougarPoint PCH\n"); 75 drm_WARN_ON(display->drm, 76 DISPLAY_VER(display) != 6 && 77 !display->platform.ivybridge); 78 return PCH_CPT; 79 case INTEL_PCH_PPT_DEVICE_ID_TYPE: 80 drm_dbg_kms(display->drm, "Found PantherPoint PCH\n"); 81 drm_WARN_ON(display->drm, 82 DISPLAY_VER(display) != 6 && 83 !display->platform.ivybridge); 84 /* PPT is CPT compatible */ 85 return PCH_CPT; 86 case INTEL_PCH_LPT_DEVICE_ID_TYPE: 87 drm_dbg_kms(display->drm, "Found LynxPoint PCH\n"); 88 drm_WARN_ON(display->drm, 89 !display->platform.haswell && 90 !display->platform.broadwell); 91 drm_WARN_ON(display->drm, 92 display->platform.haswell_ult || 93 display->platform.broadwell_ult); 94 return PCH_LPT_H; 95 case INTEL_PCH_LPT_LP_DEVICE_ID_TYPE: 96 drm_dbg_kms(display->drm, "Found LynxPoint LP PCH\n"); 97 drm_WARN_ON(display->drm, 98 !display->platform.haswell && 99 !display->platform.broadwell); 100 drm_WARN_ON(display->drm, 101 !display->platform.haswell_ult && 102 !display->platform.broadwell_ult); 103 return PCH_LPT_LP; 104 case INTEL_PCH_WPT_DEVICE_ID_TYPE: 105 drm_dbg_kms(display->drm, "Found WildcatPoint PCH\n"); 106 drm_WARN_ON(display->drm, 107 !display->platform.haswell && 108 !display->platform.broadwell); 109 drm_WARN_ON(display->drm, 110 display->platform.haswell_ult || 111 display->platform.broadwell_ult); 112 /* WPT is LPT compatible */ 113 return PCH_LPT_H; 114 case INTEL_PCH_WPT_LP_DEVICE_ID_TYPE: 115 drm_dbg_kms(display->drm, "Found WildcatPoint LP PCH\n"); 116 drm_WARN_ON(display->drm, 117 !display->platform.haswell && 118 !display->platform.broadwell); 119 drm_WARN_ON(display->drm, 120 !display->platform.haswell_ult && 121 !display->platform.broadwell_ult); 122 /* WPT is LPT compatible */ 123 return PCH_LPT_LP; 124 case INTEL_PCH_SPT_DEVICE_ID_TYPE: 125 drm_dbg_kms(display->drm, "Found SunrisePoint PCH\n"); 126 drm_WARN_ON(display->drm, 127 !display->platform.skylake && 128 !display->platform.kabylake && 129 !display->platform.coffeelake); 130 return PCH_SPT; 131 case INTEL_PCH_SPT_LP_DEVICE_ID_TYPE: 132 drm_dbg_kms(display->drm, "Found SunrisePoint LP PCH\n"); 133 drm_WARN_ON(display->drm, 134 !display->platform.skylake && 135 !display->platform.kabylake && 136 !display->platform.coffeelake && 137 !display->platform.cometlake); 138 return PCH_SPT; 139 case INTEL_PCH_KBP_DEVICE_ID_TYPE: 140 drm_dbg_kms(display->drm, "Found Kaby Lake PCH (KBP)\n"); 141 drm_WARN_ON(display->drm, 142 !display->platform.skylake && 143 !display->platform.kabylake && 144 !display->platform.coffeelake && 145 !display->platform.cometlake); 146 /* KBP is SPT compatible */ 147 return PCH_SPT; 148 case INTEL_PCH_CNP_DEVICE_ID_TYPE: 149 drm_dbg_kms(display->drm, "Found Cannon Lake PCH (CNP)\n"); 150 drm_WARN_ON(display->drm, 151 !display->platform.coffeelake && 152 !display->platform.cometlake); 153 return PCH_CNP; 154 case INTEL_PCH_CNP_LP_DEVICE_ID_TYPE: 155 drm_dbg_kms(display->drm, 156 "Found Cannon Lake LP PCH (CNP-LP)\n"); 157 drm_WARN_ON(display->drm, 158 !display->platform.coffeelake && 159 !display->platform.cometlake); 160 return PCH_CNP; 161 case INTEL_PCH_CMP_DEVICE_ID_TYPE: 162 case INTEL_PCH_CMP2_DEVICE_ID_TYPE: 163 drm_dbg_kms(display->drm, "Found Comet Lake PCH (CMP)\n"); 164 drm_WARN_ON(display->drm, 165 !display->platform.coffeelake && 166 !display->platform.cometlake && 167 !display->platform.rocketlake); 168 /* CMP is CNP compatible */ 169 return PCH_CNP; 170 case INTEL_PCH_CMP_V_DEVICE_ID_TYPE: 171 drm_dbg_kms(display->drm, "Found Comet Lake V PCH (CMP-V)\n"); 172 drm_WARN_ON(display->drm, 173 !display->platform.coffeelake && 174 !display->platform.cometlake); 175 /* CMP-V is based on KBP, which is SPT compatible */ 176 return PCH_SPT; 177 case INTEL_PCH_ICP_DEVICE_ID_TYPE: 178 case INTEL_PCH_ICP2_DEVICE_ID_TYPE: 179 drm_dbg_kms(display->drm, "Found Ice Lake PCH\n"); 180 drm_WARN_ON(display->drm, !display->platform.icelake); 181 return PCH_ICP; 182 case INTEL_PCH_MCC_DEVICE_ID_TYPE: 183 drm_dbg_kms(display->drm, "Found Mule Creek Canyon PCH\n"); 184 drm_WARN_ON(display->drm, !(display->platform.jasperlake || 185 display->platform.elkhartlake)); 186 /* MCC is TGP compatible */ 187 return PCH_TGP; 188 case INTEL_PCH_TGP_DEVICE_ID_TYPE: 189 case INTEL_PCH_TGP2_DEVICE_ID_TYPE: 190 drm_dbg_kms(display->drm, "Found Tiger Lake LP PCH\n"); 191 drm_WARN_ON(display->drm, !display->platform.tigerlake && 192 !display->platform.rocketlake && 193 !display->platform.skylake && 194 !display->platform.kabylake && 195 !display->platform.coffeelake && 196 !display->platform.cometlake); 197 return PCH_TGP; 198 case INTEL_PCH_JSP_DEVICE_ID_TYPE: 199 drm_dbg_kms(display->drm, "Found Jasper Lake PCH\n"); 200 drm_WARN_ON(display->drm, !(display->platform.jasperlake || 201 display->platform.elkhartlake)); 202 /* JSP is ICP compatible */ 203 return PCH_ICP; 204 case INTEL_PCH_ADP_DEVICE_ID_TYPE: 205 case INTEL_PCH_ADP2_DEVICE_ID_TYPE: 206 case INTEL_PCH_ADP3_DEVICE_ID_TYPE: 207 case INTEL_PCH_ADP4_DEVICE_ID_TYPE: 208 drm_dbg_kms(display->drm, "Found Alder Lake PCH\n"); 209 drm_WARN_ON(display->drm, !display->platform.alderlake_s && 210 !display->platform.alderlake_p); 211 return PCH_ADP; 212 default: 213 return PCH_NONE; 214 } 215 } 216 217 static bool intel_is_virt_pch(unsigned short id, 218 unsigned short svendor, unsigned short sdevice) 219 { 220 return (id == INTEL_PCH_P2X_DEVICE_ID_TYPE || 221 id == INTEL_PCH_P3X_DEVICE_ID_TYPE || 222 (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE && 223 svendor == PCI_SUBVENDOR_ID_REDHAT_QUMRANET && 224 sdevice == PCI_SUBDEVICE_ID_QEMU)); 225 } 226 227 static void 228 intel_virt_detect_pch(const struct intel_display *display, 229 unsigned short *pch_id, enum intel_pch *pch_type) 230 { 231 unsigned short id = 0; 232 233 /* 234 * In a virtualized passthrough environment we can be in a 235 * setup where the ISA bridge is not able to be passed through. 236 * In this case, a south bridge can be emulated and we have to 237 * make an educated guess as to which PCH is really there. 238 */ 239 240 if (display->platform.alderlake_s || display->platform.alderlake_p) 241 id = INTEL_PCH_ADP_DEVICE_ID_TYPE; 242 else if (display->platform.tigerlake || display->platform.rocketlake) 243 id = INTEL_PCH_TGP_DEVICE_ID_TYPE; 244 else if (display->platform.jasperlake || display->platform.elkhartlake) 245 id = INTEL_PCH_MCC_DEVICE_ID_TYPE; 246 else if (display->platform.icelake) 247 id = INTEL_PCH_ICP_DEVICE_ID_TYPE; 248 else if (display->platform.coffeelake || 249 display->platform.cometlake) 250 id = INTEL_PCH_CNP_DEVICE_ID_TYPE; 251 else if (display->platform.kabylake || display->platform.skylake) 252 id = INTEL_PCH_SPT_DEVICE_ID_TYPE; 253 else if (display->platform.haswell_ult || 254 display->platform.broadwell_ult) 255 id = INTEL_PCH_LPT_LP_DEVICE_ID_TYPE; 256 else if (display->platform.haswell || display->platform.broadwell) 257 id = INTEL_PCH_LPT_DEVICE_ID_TYPE; 258 else if (DISPLAY_VER(display) == 6 || display->platform.ivybridge) 259 id = INTEL_PCH_CPT_DEVICE_ID_TYPE; 260 else if (DISPLAY_VER(display) == 5) 261 id = INTEL_PCH_IBX_DEVICE_ID_TYPE; 262 263 if (id) 264 drm_dbg_kms(display->drm, "Assuming PCH ID %04x\n", id); 265 else 266 drm_dbg_kms(display->drm, "Assuming no PCH\n"); 267 268 *pch_type = intel_pch_type(display, id); 269 270 /* Sanity check virtual PCH id */ 271 if (drm_WARN_ON(display->drm, 272 id && *pch_type == PCH_NONE)) 273 id = 0; 274 275 *pch_id = id; 276 } 277 278 void intel_pch_detect(struct intel_display *display) 279 { 280 struct pci_dev *pch = NULL; 281 unsigned short id; 282 enum intel_pch pch_type; 283 284 pch_type = intel_pch_fake_for_south_display(display); 285 if (pch_type != PCH_NONE) { 286 display->pch_type = pch_type; 287 drm_dbg_kms(display->drm, 288 "PCH not involved in display, using fake PCH type %d for south display\n", 289 pch_type); 290 return; 291 } 292 293 /* 294 * The reason to probe ISA bridge instead of Dev31:Fun0 is to 295 * make graphics device passthrough work easy for VMM, that only 296 * need to expose ISA bridge to let driver know the real hardware 297 * underneath. This is a requirement from virtualization team. 298 * 299 * In some virtualized environments (e.g. XEN), there is irrelevant 300 * ISA bridge in the system. To work reliably, we should scan through 301 * all the ISA bridge devices and check for the first match, instead 302 * of only checking the first one. 303 */ 304 while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) { 305 if (pch->vendor != PCI_VENDOR_ID_INTEL) 306 continue; 307 308 id = pch->device & INTEL_PCH_DEVICE_ID_MASK; 309 310 pch_type = intel_pch_type(display, id); 311 if (pch_type != PCH_NONE) { 312 display->pch_type = pch_type; 313 break; 314 } else if (intel_is_virt_pch(id, pch->subsystem_vendor, 315 pch->subsystem_device)) { 316 intel_virt_detect_pch(display, &id, &pch_type); 317 display->pch_type = pch_type; 318 break; 319 } 320 } 321 322 /* 323 * Use PCH_NOP (PCH but no South Display) for PCH platforms without 324 * display. 325 */ 326 if (pch && !HAS_DISPLAY(display)) { 327 drm_dbg_kms(display->drm, 328 "Display disabled, reverting to NOP PCH\n"); 329 display->pch_type = PCH_NOP; 330 } else if (!pch) { 331 if (i915_run_as_guest() && HAS_DISPLAY(display)) { 332 intel_virt_detect_pch(display, &id, &pch_type); 333 display->pch_type = pch_type; 334 } else { 335 drm_dbg_kms(display->drm, "No PCH found.\n"); 336 } 337 } 338 339 pci_dev_put(pch); 340 } 341