File: | dev/pci/drm/i915/display/intel_combo_phy.c |
Warning: | line 425, column 33 The left operand of '+' is a garbage value due to array index out of bounds |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // SPDX-License-Identifier: MIT | |||
2 | /* | |||
3 | * Copyright © 2018 Intel Corporation | |||
4 | */ | |||
5 | ||||
6 | #include "intel_combo_phy.h" | |||
7 | #include "intel_combo_phy_regs.h" | |||
8 | #include "intel_de.h" | |||
9 | #include "intel_display_types.h" | |||
10 | ||||
11 | #define for_each_combo_phy(__dev_priv, __phy)for ((__phy) = PHY_A; (__phy) < I915_MAX_PHYS; (__phy)++) if (!(intel_phy_is_combo(__dev_priv, __phy))) {} else \ | |||
12 | for ((__phy) = PHY_A; (__phy) < I915_MAX_PHYS; (__phy)++) \ | |||
13 | for_each_if(intel_phy_is_combo(__dev_priv, __phy))if (!(intel_phy_is_combo(__dev_priv, __phy))) {} else | |||
14 | ||||
15 | #define for_each_combo_phy_reverse(__dev_priv, __phy)for ((__phy) = I915_MAX_PHYS; (__phy)-- > PHY_A;) if (!(intel_phy_is_combo (__dev_priv, __phy))) {} else \ | |||
16 | for ((__phy) = I915_MAX_PHYS; (__phy)-- > PHY_A;) \ | |||
17 | for_each_if(intel_phy_is_combo(__dev_priv, __phy))if (!(intel_phy_is_combo(__dev_priv, __phy))) {} else | |||
18 | ||||
19 | enum { | |||
20 | PROCMON_0_85V_DOT_0, | |||
21 | PROCMON_0_95V_DOT_0, | |||
22 | PROCMON_0_95V_DOT_1, | |||
23 | PROCMON_1_05V_DOT_0, | |||
24 | PROCMON_1_05V_DOT_1, | |||
25 | }; | |||
26 | ||||
27 | static const struct icl_procmon { | |||
28 | const char *name; | |||
29 | u32 dw1, dw9, dw10; | |||
30 | } icl_procmon_values[] = { | |||
31 | [PROCMON_0_85V_DOT_0] = { | |||
32 | .name = "0.85V dot0 (low-voltage)", | |||
33 | .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96, | |||
34 | }, | |||
35 | [PROCMON_0_95V_DOT_0] = { | |||
36 | .name = "0.95V dot0", | |||
37 | .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB, | |||
38 | }, | |||
39 | [PROCMON_0_95V_DOT_1] = { | |||
40 | .name = "0.95V dot1", | |||
41 | .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5, | |||
42 | }, | |||
43 | [PROCMON_1_05V_DOT_0] = { | |||
44 | .name = "1.05V dot0", | |||
45 | .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1, | |||
46 | }, | |||
47 | [PROCMON_1_05V_DOT_1] = { | |||
48 | .name = "1.05V dot1", | |||
49 | .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, | |||
50 | }, | |||
51 | }; | |||
52 | ||||
53 | static const struct icl_procmon * | |||
54 | icl_get_procmon_ref_values(struct drm_i915_privateinteldrm_softc *dev_priv, enum phy phy) | |||
55 | { | |||
56 | const struct icl_procmon *procmon; | |||
57 | u32 val; | |||
58 | ||||
59 | val = intel_de_read(dev_priv, ICL_PORT_COMP_DW3(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (3))) } )); | |||
60 | switch (val & (PROCESS_INFO_MASK(7 << 26) | VOLTAGE_INFO_MASK(3 << 24))) { | |||
61 | default: | |||
62 | MISSING_CASE(val)({ int __ret = !!(1); if (__ret) printf("Missing case (%s == %ld)\n" , "val", (long)(val)); __builtin_expect(!!(__ret), 0); }); | |||
63 | fallthroughdo {} while (0); | |||
64 | case VOLTAGE_INFO_0_85V(0 << 24) | PROCESS_INFO_DOT_0(0 << 26): | |||
65 | procmon = &icl_procmon_values[PROCMON_0_85V_DOT_0]; | |||
66 | break; | |||
67 | case VOLTAGE_INFO_0_95V(1 << 24) | PROCESS_INFO_DOT_0(0 << 26): | |||
68 | procmon = &icl_procmon_values[PROCMON_0_95V_DOT_0]; | |||
69 | break; | |||
70 | case VOLTAGE_INFO_0_95V(1 << 24) | PROCESS_INFO_DOT_1(1 << 26): | |||
71 | procmon = &icl_procmon_values[PROCMON_0_95V_DOT_1]; | |||
72 | break; | |||
73 | case VOLTAGE_INFO_1_05V(2 << 24) | PROCESS_INFO_DOT_0(0 << 26): | |||
74 | procmon = &icl_procmon_values[PROCMON_1_05V_DOT_0]; | |||
75 | break; | |||
76 | case VOLTAGE_INFO_1_05V(2 << 24) | PROCESS_INFO_DOT_1(1 << 26): | |||
77 | procmon = &icl_procmon_values[PROCMON_1_05V_DOT_1]; | |||
78 | break; | |||
79 | } | |||
80 | ||||
81 | return procmon; | |||
82 | } | |||
83 | ||||
84 | static void icl_set_procmon_ref_values(struct drm_i915_privateinteldrm_softc *dev_priv, | |||
85 | enum phy phy) | |||
86 | { | |||
87 | const struct icl_procmon *procmon; | |||
88 | u32 val; | |||
89 | ||||
90 | procmon = icl_get_procmon_ref_values(dev_priv, phy); | |||
91 | ||||
92 | val = intel_de_read(dev_priv, ICL_PORT_COMP_DW1(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (1))) } )); | |||
93 | val &= ~((0xff << 16) | 0xff); | |||
94 | val |= procmon->dw1; | |||
95 | intel_de_write(dev_priv, ICL_PORT_COMP_DW1(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (1))) } ), val); | |||
96 | ||||
97 | intel_de_write(dev_priv, ICL_PORT_COMP_DW9(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (9))) } ), procmon->dw9); | |||
98 | intel_de_write(dev_priv, ICL_PORT_COMP_DW10(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (10))) } ), procmon->dw10); | |||
99 | } | |||
100 | ||||
101 | static bool_Bool check_phy_reg(struct drm_i915_privateinteldrm_softc *dev_priv, | |||
102 | enum phy phy, i915_reg_t reg, u32 mask, | |||
103 | u32 expected_val) | |||
104 | { | |||
105 | u32 val = intel_de_read(dev_priv, reg); | |||
106 | ||||
107 | if ((val & mask) != expected_val) { | |||
108 | drm_dbg(&dev_priv->drm,__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c reg %08x state mismatch: " "current %08x mask %08x expected %08x\n", ((phy) + 'A'), reg .reg, val, mask, expected_val) | |||
109 | "Combo PHY %c reg %08x state mismatch: "__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c reg %08x state mismatch: " "current %08x mask %08x expected %08x\n", ((phy) + 'A'), reg .reg, val, mask, expected_val) | |||
110 | "current %08x mask %08x expected %08x\n",__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c reg %08x state mismatch: " "current %08x mask %08x expected %08x\n", ((phy) + 'A'), reg .reg, val, mask, expected_val) | |||
111 | phy_name(phy),__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c reg %08x state mismatch: " "current %08x mask %08x expected %08x\n", ((phy) + 'A'), reg .reg, val, mask, expected_val) | |||
112 | reg.reg, val, mask, expected_val)__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c reg %08x state mismatch: " "current %08x mask %08x expected %08x\n", ((phy) + 'A'), reg .reg, val, mask, expected_val); | |||
113 | return false0; | |||
114 | } | |||
115 | ||||
116 | return true1; | |||
117 | } | |||
118 | ||||
119 | static bool_Bool icl_verify_procmon_ref_values(struct drm_i915_privateinteldrm_softc *dev_priv, | |||
120 | enum phy phy) | |||
121 | { | |||
122 | const struct icl_procmon *procmon; | |||
123 | bool_Bool ret; | |||
124 | ||||
125 | procmon = icl_get_procmon_ref_values(dev_priv, phy); | |||
126 | ||||
127 | drm_dbg_kms(&dev_priv->drm,__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "Combo PHY %c Voltage/Process Info : %s\n" , ((phy) + 'A'), procmon->name) | |||
128 | "Combo PHY %c Voltage/Process Info : %s\n",__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "Combo PHY %c Voltage/Process Info : %s\n" , ((phy) + 'A'), procmon->name) | |||
129 | phy_name(phy), procmon->name)__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "Combo PHY %c Voltage/Process Info : %s\n" , ((phy) + 'A'), procmon->name); | |||
130 | ||||
131 | ret = check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW1(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (1))) } ), | |||
132 | (0xff << 16) | 0xff, procmon->dw1); | |||
133 | ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW9(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (9))) } ), | |||
134 | -1U, procmon->dw9); | |||
135 | ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW10(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (10))) } ), | |||
136 | -1U, procmon->dw10); | |||
137 | ||||
138 | return ret; | |||
139 | } | |||
140 | ||||
141 | static bool_Bool has_phy_misc(struct drm_i915_privateinteldrm_softc *i915, enum phy phy) | |||
142 | { | |||
143 | /* | |||
144 | * Some platforms only expect PHY_MISC to be programmed for PHY-A and | |||
145 | * PHY-B and may not even have instances of the register for the | |||
146 | * other combo PHY's. | |||
147 | * | |||
148 | * ADL-S technically has three instances of PHY_MISC, but only requires | |||
149 | * that we program it for PHY A. | |||
150 | */ | |||
151 | ||||
152 | if (IS_ALDERLAKE_S(i915)IS_PLATFORM(i915, INTEL_ALDERLAKE_S)) | |||
153 | return phy == PHY_A; | |||
154 | else if (IS_JSL_EHL(i915)(IS_PLATFORM(i915, INTEL_JASPERLAKE) || IS_PLATFORM(i915, INTEL_ELKHARTLAKE )) || | |||
155 | IS_ROCKETLAKE(i915)IS_PLATFORM(i915, INTEL_ROCKETLAKE) || | |||
156 | IS_DG1(i915)IS_PLATFORM(i915, INTEL_DG1)) | |||
157 | return phy < PHY_C; | |||
158 | ||||
159 | return true1; | |||
160 | } | |||
161 | ||||
162 | static bool_Bool icl_combo_phy_enabled(struct drm_i915_privateinteldrm_softc *dev_priv, | |||
163 | enum phy phy) | |||
164 | { | |||
165 | /* The PHY C added by EHL has no PHY_MISC register */ | |||
166 | if (!has_phy_misc(dev_priv, phy)) | |||
167 | return intel_de_read(dev_priv, ICL_PORT_COMP_DW0(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (0))) } )) & COMP_INIT(1 << 31); | |||
168 | else | |||
169 | return !(intel_de_read(dev_priv, ICL_PHY_MISC(phy)((const i915_reg_t){ .reg = (((0x64C00) + (phy) * ((0x64C04) - (0x64C00)))) })) & | |||
170 | ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN(1 << 23)) && | |||
171 | (intel_de_read(dev_priv, ICL_PORT_COMP_DW0(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (0))) } )) & COMP_INIT(1 << 31)); | |||
172 | } | |||
173 | ||||
174 | static bool_Bool ehl_vbt_ddi_d_present(struct drm_i915_privateinteldrm_softc *i915) | |||
175 | { | |||
176 | bool_Bool ddi_a_present = intel_bios_is_port_present(i915, PORT_A); | |||
177 | bool_Bool ddi_d_present = intel_bios_is_port_present(i915, PORT_D); | |||
178 | bool_Bool dsi_present = intel_bios_is_dsi_present(i915, NULL((void *)0)); | |||
179 | ||||
180 | /* | |||
181 | * VBT's 'dvo port' field for child devices references the DDI, not | |||
182 | * the PHY. So if combo PHY A is wired up to drive an external | |||
183 | * display, we should see a child device present on PORT_D and | |||
184 | * nothing on PORT_A and no DSI. | |||
185 | */ | |||
186 | if (ddi_d_present && !ddi_a_present && !dsi_present) | |||
187 | return true1; | |||
188 | ||||
189 | /* | |||
190 | * If we encounter a VBT that claims to have an external display on | |||
191 | * DDI-D _and_ an internal display on DDI-A/DSI leave an error message | |||
192 | * in the log and let the internal display win. | |||
193 | */ | |||
194 | if (ddi_d_present) | |||
195 | drm_err(&i915->drm,printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "VBT claims to have both internal and external displays on PHY A. Configuring for internal.\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__) | |||
196 | "VBT claims to have both internal and external displays on PHY A. Configuring for internal.\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "VBT claims to have both internal and external displays on PHY A. Configuring for internal.\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); | |||
197 | ||||
198 | return false0; | |||
199 | } | |||
200 | ||||
201 | static bool_Bool phy_is_master(struct drm_i915_privateinteldrm_softc *dev_priv, enum phy phy) | |||
202 | { | |||
203 | /* | |||
204 | * Certain PHYs are connected to compensation resistors and act | |||
205 | * as masters to other PHYs. | |||
206 | * | |||
207 | * ICL,TGL: | |||
208 | * A(master) -> B(slave), C(slave) | |||
209 | * RKL,DG1: | |||
210 | * A(master) -> B(slave) | |||
211 | * C(master) -> D(slave) | |||
212 | * ADL-S: | |||
213 | * A(master) -> B(slave), C(slave) | |||
214 | * D(master) -> E(slave) | |||
215 | * | |||
216 | * We must set the IREFGEN bit for any PHY acting as a master | |||
217 | * to another PHY. | |||
218 | */ | |||
219 | if (phy == PHY_A) | |||
220 | return true1; | |||
221 | else if (IS_ALDERLAKE_S(dev_priv)IS_PLATFORM(dev_priv, INTEL_ALDERLAKE_S)) | |||
222 | return phy == PHY_D; | |||
223 | else if (IS_DG1(dev_priv)IS_PLATFORM(dev_priv, INTEL_DG1) || IS_ROCKETLAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_ROCKETLAKE)) | |||
224 | return phy == PHY_C; | |||
225 | ||||
226 | return false0; | |||
227 | } | |||
228 | ||||
229 | static bool_Bool icl_combo_phy_verify_state(struct drm_i915_privateinteldrm_softc *dev_priv, | |||
230 | enum phy phy) | |||
231 | { | |||
232 | bool_Bool ret = true1; | |||
233 | u32 expected_val = 0; | |||
234 | ||||
235 | if (!icl_combo_phy_enabled(dev_priv, phy)) | |||
236 | return false0; | |||
237 | ||||
238 | if (DISPLAY_VER(dev_priv)((&(dev_priv)->__runtime)->display.ip.ver) >= 12) { | |||
239 | ret &= check_phy_reg(dev_priv, phy, ICL_PORT_TX_DW8_LN(0, phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + (0x880 + (0) * 0x100 ) + 4 * (8))) }), | |||
240 | ICL_PORT_TX_DW8_ODCC_CLK_SEL((u32)((1UL << (31)) + 0)) | | |||
241 | ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK((u32)((((~0UL) >> (64 - (30) - 1)) & ((~0UL) << (29))) + 0)), | |||
242 | ICL_PORT_TX_DW8_ODCC_CLK_SEL((u32)((1UL << (31)) + 0)) | | |||
243 | ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2((u32)((((typeof(((u32)((((~0UL) >> (64 - (30) - 1)) & ((~0UL) << (29))) + 0))))(0x1) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (30) - 1)) & ((~0UL) << (29))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (30 ) - 1)) & ((~0UL) << (29))) + 0)))) + 0 + 0 + 0 + 0 ))); | |||
244 | ||||
245 | ret &= check_phy_reg(dev_priv, phy, ICL_PORT_PCS_DW1_LN(0, phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + (0x800 + (0) * 0x100 ) + 4 * (1))) }), | |||
246 | DCC_MODE_SELECT_MASK(0x3 << 20), | |||
247 | DCC_MODE_SELECT_CONTINUOSLY(0x3 << 20)); | |||
248 | } | |||
249 | ||||
250 | ret &= icl_verify_procmon_ref_values(dev_priv, phy); | |||
251 | ||||
252 | if (phy_is_master(dev_priv, phy)) { | |||
253 | ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW8(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (8))) } ), | |||
254 | IREFGEN(1 << 24), IREFGEN(1 << 24)); | |||
255 | ||||
256 | if (IS_JSL_EHL(dev_priv)(IS_PLATFORM(dev_priv, INTEL_JASPERLAKE) || IS_PLATFORM(dev_priv , INTEL_ELKHARTLAKE))) { | |||
257 | if (ehl_vbt_ddi_d_present(dev_priv)) | |||
258 | expected_val = ICL_PHY_MISC_MUX_DDID(1 << 28); | |||
259 | ||||
260 | ret &= check_phy_reg(dev_priv, phy, ICL_PHY_MISC(phy)((const i915_reg_t){ .reg = (((0x64C00) + (phy) * ((0x64C04) - (0x64C00)))) }), | |||
261 | ICL_PHY_MISC_MUX_DDID(1 << 28), | |||
262 | expected_val); | |||
263 | } | |||
264 | } | |||
265 | ||||
266 | ret &= check_phy_reg(dev_priv, phy, ICL_PORT_CL_DW5(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 4 * (5))) }), | |||
267 | CL_POWER_DOWN_ENABLE(1 << 4), CL_POWER_DOWN_ENABLE(1 << 4)); | |||
268 | ||||
269 | return ret; | |||
270 | } | |||
271 | ||||
272 | void intel_combo_phy_power_up_lanes(struct drm_i915_privateinteldrm_softc *dev_priv, | |||
273 | enum phy phy, bool_Bool is_dsi, | |||
274 | int lane_count, bool_Bool lane_reversal) | |||
275 | { | |||
276 | u8 lane_mask; | |||
277 | u32 val; | |||
278 | ||||
279 | if (is_dsi) { | |||
280 | drm_WARN_ON(&dev_priv->drm, lane_reversal)({ int __ret = !!((lane_reversal)); if (__ret) printf("%s %s: " "%s", dev_driver_string(((&dev_priv->drm))->dev), "" , "drm_WARN_ON(" "lane_reversal" ")"); __builtin_expect(!!(__ret ), 0); }); | |||
281 | ||||
282 | switch (lane_count) { | |||
283 | case 1: | |||
284 | lane_mask = PWR_DOWN_LN_3_1_0(0xb << 4); | |||
285 | break; | |||
286 | case 2: | |||
287 | lane_mask = PWR_DOWN_LN_3_1(0xa << 4); | |||
288 | break; | |||
289 | case 3: | |||
290 | lane_mask = PWR_DOWN_LN_3(0x8 << 4); | |||
291 | break; | |||
292 | default: | |||
293 | MISSING_CASE(lane_count)({ int __ret = !!(1); if (__ret) printf("Missing case (%s == %ld)\n" , "lane_count", (long)(lane_count)); __builtin_expect(!!(__ret ), 0); }); | |||
294 | fallthroughdo {} while (0); | |||
295 | case 4: | |||
296 | lane_mask = PWR_UP_ALL_LANES(0x0 << 4); | |||
297 | break; | |||
298 | } | |||
299 | } else { | |||
300 | switch (lane_count) { | |||
301 | case 1: | |||
302 | lane_mask = lane_reversal ? PWR_DOWN_LN_2_1_0(0x7 << 4) : | |||
303 | PWR_DOWN_LN_3_2_1(0xe << 4); | |||
304 | break; | |||
305 | case 2: | |||
306 | lane_mask = lane_reversal ? PWR_DOWN_LN_1_0(0x3 << 4) : | |||
307 | PWR_DOWN_LN_3_2(0xc << 4); | |||
308 | break; | |||
309 | default: | |||
310 | MISSING_CASE(lane_count)({ int __ret = !!(1); if (__ret) printf("Missing case (%s == %ld)\n" , "lane_count", (long)(lane_count)); __builtin_expect(!!(__ret ), 0); }); | |||
311 | fallthroughdo {} while (0); | |||
312 | case 4: | |||
313 | lane_mask = PWR_UP_ALL_LANES(0x0 << 4); | |||
314 | break; | |||
315 | } | |||
316 | } | |||
317 | ||||
318 | val = intel_de_read(dev_priv, ICL_PORT_CL_DW10(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 4 * (10))) })); | |||
319 | val &= ~PWR_DOWN_LN_MASK(0xf << 4); | |||
320 | val |= lane_mask; | |||
321 | intel_de_write(dev_priv, ICL_PORT_CL_DW10(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 4 * (10))) }), val); | |||
322 | } | |||
323 | ||||
324 | static void icl_combo_phys_init(struct drm_i915_privateinteldrm_softc *dev_priv) | |||
325 | { | |||
326 | enum phy phy; | |||
327 | ||||
328 | for_each_combo_phy(dev_priv, phy)for ((phy) = PHY_A; (phy) < I915_MAX_PHYS; (phy)++) if (!( intel_phy_is_combo(dev_priv, phy))) {} else { | |||
329 | u32 val; | |||
330 | ||||
331 | if (icl_combo_phy_verify_state(dev_priv, phy)) { | |||
332 | drm_dbg(&dev_priv->drm,__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c already enabled, won't reprogram it.\n" , ((phy) + 'A')) | |||
333 | "Combo PHY %c already enabled, won't reprogram it.\n",__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c already enabled, won't reprogram it.\n" , ((phy) + 'A')) | |||
334 | phy_name(phy))__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_DRIVER, "Combo PHY %c already enabled, won't reprogram it.\n" , ((phy) + 'A')); | |||
335 | continue; | |||
336 | } | |||
337 | ||||
338 | if (!has_phy_misc(dev_priv, phy)) | |||
339 | goto skip_phy_misc; | |||
340 | ||||
341 | /* | |||
342 | * EHL's combo PHY A can be hooked up to either an external | |||
343 | * display (via DDI-D) or an internal display (via DDI-A or | |||
344 | * the DSI DPHY). This is a motherboard design decision that | |||
345 | * can't be changed on the fly, so initialize the PHY's mux | |||
346 | * based on whether our VBT indicates the presence of any | |||
347 | * "internal" child devices. | |||
348 | */ | |||
349 | val = intel_de_read(dev_priv, ICL_PHY_MISC(phy)((const i915_reg_t){ .reg = (((0x64C00) + (phy) * ((0x64C04) - (0x64C00)))) })); | |||
350 | if (IS_JSL_EHL(dev_priv)(IS_PLATFORM(dev_priv, INTEL_JASPERLAKE) || IS_PLATFORM(dev_priv , INTEL_ELKHARTLAKE)) && phy == PHY_A) { | |||
351 | val &= ~ICL_PHY_MISC_MUX_DDID(1 << 28); | |||
352 | ||||
353 | if (ehl_vbt_ddi_d_present(dev_priv)) | |||
354 | val |= ICL_PHY_MISC_MUX_DDID(1 << 28); | |||
355 | } | |||
356 | ||||
357 | val &= ~ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN(1 << 23); | |||
358 | intel_de_write(dev_priv, ICL_PHY_MISC(phy)((const i915_reg_t){ .reg = (((0x64C00) + (phy) * ((0x64C04) - (0x64C00)))) }), val); | |||
359 | ||||
360 | skip_phy_misc: | |||
361 | if (DISPLAY_VER(dev_priv)((&(dev_priv)->__runtime)->display.ip.ver) >= 12) { | |||
362 | val = intel_de_read(dev_priv, ICL_PORT_TX_DW8_LN(0, phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + (0x880 + (0) * 0x100 ) + 4 * (8))) })); | |||
363 | val &= ~ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK((u32)((((~0UL) >> (64 - (30) - 1)) & ((~0UL) << (29))) + 0)); | |||
364 | val |= ICL_PORT_TX_DW8_ODCC_CLK_SEL((u32)((1UL << (31)) + 0)); | |||
365 | val |= ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2((u32)((((typeof(((u32)((((~0UL) >> (64 - (30) - 1)) & ((~0UL) << (29))) + 0))))(0x1) << (__builtin_ffsll (((u32)((((~0UL) >> (64 - (30) - 1)) & ((~0UL) << (29))) + 0))) - 1)) & (((u32)((((~0UL) >> (64 - (30 ) - 1)) & ((~0UL) << (29))) + 0)))) + 0 + 0 + 0 + 0 )); | |||
366 | intel_de_write(dev_priv, ICL_PORT_TX_DW8_GRP(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x680 + 4 * (8))) } ), val); | |||
367 | ||||
368 | val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN(0, phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + (0x800 + (0) * 0x100 ) + 4 * (1))) })); | |||
369 | val &= ~DCC_MODE_SELECT_MASK(0x3 << 20); | |||
370 | val |= DCC_MODE_SELECT_CONTINUOSLY(0x3 << 20); | |||
371 | intel_de_write(dev_priv, ICL_PORT_PCS_DW1_GRP(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x600 + 4 * (1))) } ), val); | |||
372 | } | |||
373 | ||||
374 | icl_set_procmon_ref_values(dev_priv, phy); | |||
375 | ||||
376 | if (phy_is_master(dev_priv, phy)) { | |||
377 | val = intel_de_read(dev_priv, ICL_PORT_COMP_DW8(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (8))) } )); | |||
378 | val |= IREFGEN(1 << 24); | |||
379 | intel_de_write(dev_priv, ICL_PORT_COMP_DW8(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (8))) } ), val); | |||
380 | } | |||
381 | ||||
382 | val = intel_de_read(dev_priv, ICL_PORT_COMP_DW0(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (0))) } )); | |||
383 | val |= COMP_INIT(1 << 31); | |||
384 | intel_de_write(dev_priv, ICL_PORT_COMP_DW0(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (0))) } ), val); | |||
385 | ||||
386 | val = intel_de_read(dev_priv, ICL_PORT_CL_DW5(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 4 * (5))) })); | |||
387 | val |= CL_POWER_DOWN_ENABLE(1 << 4); | |||
388 | intel_de_write(dev_priv, ICL_PORT_CL_DW5(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 4 * (5))) }), val); | |||
389 | } | |||
390 | } | |||
391 | ||||
392 | static void icl_combo_phys_uninit(struct drm_i915_privateinteldrm_softc *dev_priv) | |||
393 | { | |||
394 | enum phy phy; | |||
395 | ||||
396 | for_each_combo_phy_reverse(dev_priv, phy)for ((phy) = I915_MAX_PHYS; (phy)-- > PHY_A;) if (!(intel_phy_is_combo (dev_priv, phy))) {} else { | |||
397 | u32 val; | |||
398 | ||||
399 | if (phy
| |||
400 | !icl_combo_phy_verify_state(dev_priv, phy)) { | |||
401 | if (IS_TIGERLAKE(dev_priv)IS_PLATFORM(dev_priv, INTEL_TIGERLAKE) || IS_DG1(dev_priv)IS_PLATFORM(dev_priv, INTEL_DG1)) { | |||
402 | /* | |||
403 | * A known problem with old ifwi: | |||
404 | * https://gitlab.freedesktop.org/drm/intel/-/issues/2411 | |||
405 | * Suppress the warning for CI. Remove ASAP! | |||
406 | */ | |||
407 | drm_dbg_kms(&dev_priv->drm,__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "Combo PHY %c HW state changed unexpectedly\n" , ((phy) + 'A')) | |||
408 | "Combo PHY %c HW state changed unexpectedly\n",__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "Combo PHY %c HW state changed unexpectedly\n" , ((phy) + 'A')) | |||
409 | phy_name(phy))__drm_dev_dbg(((void *)0), (&dev_priv->drm) ? (&dev_priv ->drm)->dev : ((void *)0), DRM_UT_KMS, "Combo PHY %c HW state changed unexpectedly\n" , ((phy) + 'A')); | |||
410 | } else { | |||
411 | drm_warn(&dev_priv->drm,printf("drm:pid%d:%s *WARNING* " "[drm] " "Combo PHY %c HW state changed unexpectedly\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , ((phy) + 'A')) | |||
412 | "Combo PHY %c HW state changed unexpectedly\n",printf("drm:pid%d:%s *WARNING* " "[drm] " "Combo PHY %c HW state changed unexpectedly\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , ((phy) + 'A')) | |||
413 | phy_name(phy))printf("drm:pid%d:%s *WARNING* " "[drm] " "Combo PHY %c HW state changed unexpectedly\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , ((phy) + 'A')); | |||
414 | } | |||
415 | } | |||
416 | ||||
417 | if (!has_phy_misc(dev_priv, phy)) | |||
418 | goto skip_phy_misc; | |||
419 | ||||
420 | val = intel_de_read(dev_priv, ICL_PHY_MISC(phy)((const i915_reg_t){ .reg = (((0x64C00) + (phy) * ((0x64C04) - (0x64C00)))) })); | |||
421 | val |= ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN(1 << 23); | |||
422 | intel_de_write(dev_priv, ICL_PHY_MISC(phy)((const i915_reg_t){ .reg = (((0x64C00) + (phy) * ((0x64C04) - (0x64C00)))) }), val); | |||
423 | ||||
424 | skip_phy_misc: | |||
425 | val = intel_de_read(dev_priv, ICL_PORT_COMP_DW0(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (0))) } )); | |||
| ||||
426 | val &= ~COMP_INIT(1 << 31); | |||
427 | intel_de_write(dev_priv, ICL_PORT_COMP_DW0(phy)((const i915_reg_t){ .reg = (((((const u32 []){ 0x162000, 0x6C000 , 0x160000, 0x161000, 0x16B000 })[phy]) + 0x100 + 4 * (0))) } ), val); | |||
428 | } | |||
429 | } | |||
430 | ||||
431 | void intel_combo_phy_init(struct drm_i915_privateinteldrm_softc *i915) | |||
432 | { | |||
433 | icl_combo_phys_init(i915); | |||
434 | } | |||
435 | ||||
436 | void intel_combo_phy_uninit(struct drm_i915_privateinteldrm_softc *i915) | |||
437 | { | |||
438 | icl_combo_phys_uninit(i915); | |||
| ||||
439 | } |