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