1c349dbc7Sjsg // SPDX-License-Identifier: MIT
2c349dbc7Sjsg /*
3c349dbc7Sjsg * Copyright © 2018 Intel Corporation
4c349dbc7Sjsg */
5c349dbc7Sjsg
6*f005ef32Sjsg #include "i915_reg.h"
7c349dbc7Sjsg #include "intel_combo_phy.h"
81bb76ff1Sjsg #include "intel_combo_phy_regs.h"
95ca02815Sjsg #include "intel_de.h"
10c349dbc7Sjsg #include "intel_display_types.h"
11c349dbc7Sjsg
12c349dbc7Sjsg #define for_each_combo_phy(__dev_priv, __phy) \
13c349dbc7Sjsg for ((__phy) = PHY_A; (__phy) < I915_MAX_PHYS; (__phy)++) \
14c349dbc7Sjsg for_each_if(intel_phy_is_combo(__dev_priv, __phy))
15c349dbc7Sjsg
16c349dbc7Sjsg #define for_each_combo_phy_reverse(__dev_priv, __phy) \
17c349dbc7Sjsg for ((__phy) = I915_MAX_PHYS; (__phy)-- > PHY_A;) \
18c349dbc7Sjsg for_each_if(intel_phy_is_combo(__dev_priv, __phy))
19c349dbc7Sjsg
20c349dbc7Sjsg enum {
21c349dbc7Sjsg PROCMON_0_85V_DOT_0,
22c349dbc7Sjsg PROCMON_0_95V_DOT_0,
23c349dbc7Sjsg PROCMON_0_95V_DOT_1,
24c349dbc7Sjsg PROCMON_1_05V_DOT_0,
25c349dbc7Sjsg PROCMON_1_05V_DOT_1,
26c349dbc7Sjsg };
27c349dbc7Sjsg
285ca02815Sjsg static const struct icl_procmon {
291bb76ff1Sjsg const char *name;
30c349dbc7Sjsg u32 dw1, dw9, dw10;
315ca02815Sjsg } icl_procmon_values[] = {
321bb76ff1Sjsg [PROCMON_0_85V_DOT_0] = {
331bb76ff1Sjsg .name = "0.85V dot0 (low-voltage)",
341bb76ff1Sjsg .dw1 = 0x00000000, .dw9 = 0x62AB67BB, .dw10 = 0x51914F96,
351bb76ff1Sjsg },
361bb76ff1Sjsg [PROCMON_0_95V_DOT_0] = {
371bb76ff1Sjsg .name = "0.95V dot0",
381bb76ff1Sjsg .dw1 = 0x00000000, .dw9 = 0x86E172C7, .dw10 = 0x77CA5EAB,
391bb76ff1Sjsg },
401bb76ff1Sjsg [PROCMON_0_95V_DOT_1] = {
411bb76ff1Sjsg .name = "0.95V dot1",
421bb76ff1Sjsg .dw1 = 0x00000000, .dw9 = 0x93F87FE1, .dw10 = 0x8AE871C5,
431bb76ff1Sjsg },
441bb76ff1Sjsg [PROCMON_1_05V_DOT_0] = {
451bb76ff1Sjsg .name = "1.05V dot0",
461bb76ff1Sjsg .dw1 = 0x00000000, .dw9 = 0x98FA82DD, .dw10 = 0x89E46DC1,
471bb76ff1Sjsg },
481bb76ff1Sjsg [PROCMON_1_05V_DOT_1] = {
491bb76ff1Sjsg .name = "1.05V dot1",
501bb76ff1Sjsg .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1,
511bb76ff1Sjsg },
52c349dbc7Sjsg };
53c349dbc7Sjsg
545ca02815Sjsg static const struct icl_procmon *
icl_get_procmon_ref_values(struct drm_i915_private * dev_priv,enum phy phy)555ca02815Sjsg icl_get_procmon_ref_values(struct drm_i915_private *dev_priv, enum phy phy)
56c349dbc7Sjsg {
57c349dbc7Sjsg u32 val;
58c349dbc7Sjsg
59c349dbc7Sjsg val = intel_de_read(dev_priv, ICL_PORT_COMP_DW3(phy));
60c349dbc7Sjsg switch (val & (PROCESS_INFO_MASK | VOLTAGE_INFO_MASK)) {
61c349dbc7Sjsg default:
62c349dbc7Sjsg MISSING_CASE(val);
63ad8b1aafSjsg fallthrough;
64c349dbc7Sjsg case VOLTAGE_INFO_0_85V | PROCESS_INFO_DOT_0:
65*f005ef32Sjsg return &icl_procmon_values[PROCMON_0_85V_DOT_0];
66c349dbc7Sjsg case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_0:
67*f005ef32Sjsg return &icl_procmon_values[PROCMON_0_95V_DOT_0];
68c349dbc7Sjsg case VOLTAGE_INFO_0_95V | PROCESS_INFO_DOT_1:
69*f005ef32Sjsg return &icl_procmon_values[PROCMON_0_95V_DOT_1];
70c349dbc7Sjsg case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_0:
71*f005ef32Sjsg return &icl_procmon_values[PROCMON_1_05V_DOT_0];
72c349dbc7Sjsg case VOLTAGE_INFO_1_05V | PROCESS_INFO_DOT_1:
73*f005ef32Sjsg return &icl_procmon_values[PROCMON_1_05V_DOT_1];
74c349dbc7Sjsg }
75c349dbc7Sjsg }
76c349dbc7Sjsg
icl_set_procmon_ref_values(struct drm_i915_private * dev_priv,enum phy phy)775ca02815Sjsg static void icl_set_procmon_ref_values(struct drm_i915_private *dev_priv,
78c349dbc7Sjsg enum phy phy)
79c349dbc7Sjsg {
805ca02815Sjsg const struct icl_procmon *procmon;
81c349dbc7Sjsg
825ca02815Sjsg procmon = icl_get_procmon_ref_values(dev_priv, phy);
83c349dbc7Sjsg
84*f005ef32Sjsg intel_de_rmw(dev_priv, ICL_PORT_COMP_DW1(phy),
85*f005ef32Sjsg (0xff << 16) | 0xff, procmon->dw1);
86c349dbc7Sjsg
87c349dbc7Sjsg intel_de_write(dev_priv, ICL_PORT_COMP_DW9(phy), procmon->dw9);
88c349dbc7Sjsg intel_de_write(dev_priv, ICL_PORT_COMP_DW10(phy), procmon->dw10);
89c349dbc7Sjsg }
90c349dbc7Sjsg
check_phy_reg(struct drm_i915_private * dev_priv,enum phy phy,i915_reg_t reg,u32 mask,u32 expected_val)91c349dbc7Sjsg static bool check_phy_reg(struct drm_i915_private *dev_priv,
92c349dbc7Sjsg enum phy phy, i915_reg_t reg, u32 mask,
93c349dbc7Sjsg u32 expected_val)
94c349dbc7Sjsg {
95c349dbc7Sjsg u32 val = intel_de_read(dev_priv, reg);
96c349dbc7Sjsg
97c349dbc7Sjsg if ((val & mask) != expected_val) {
98c349dbc7Sjsg drm_dbg(&dev_priv->drm,
99c349dbc7Sjsg "Combo PHY %c reg %08x state mismatch: "
100c349dbc7Sjsg "current %08x mask %08x expected %08x\n",
101c349dbc7Sjsg phy_name(phy),
102c349dbc7Sjsg reg.reg, val, mask, expected_val);
103c349dbc7Sjsg return false;
104c349dbc7Sjsg }
105c349dbc7Sjsg
106c349dbc7Sjsg return true;
107c349dbc7Sjsg }
108c349dbc7Sjsg
icl_verify_procmon_ref_values(struct drm_i915_private * dev_priv,enum phy phy)1095ca02815Sjsg static bool icl_verify_procmon_ref_values(struct drm_i915_private *dev_priv,
110c349dbc7Sjsg enum phy phy)
111c349dbc7Sjsg {
1125ca02815Sjsg const struct icl_procmon *procmon;
113c349dbc7Sjsg bool ret;
114c349dbc7Sjsg
1155ca02815Sjsg procmon = icl_get_procmon_ref_values(dev_priv, phy);
116c349dbc7Sjsg
1171bb76ff1Sjsg drm_dbg_kms(&dev_priv->drm,
1181bb76ff1Sjsg "Combo PHY %c Voltage/Process Info : %s\n",
1191bb76ff1Sjsg phy_name(phy), procmon->name);
1201bb76ff1Sjsg
121c349dbc7Sjsg ret = check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW1(phy),
122c349dbc7Sjsg (0xff << 16) | 0xff, procmon->dw1);
123c349dbc7Sjsg ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW9(phy),
124c349dbc7Sjsg -1U, procmon->dw9);
125c349dbc7Sjsg ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW10(phy),
126c349dbc7Sjsg -1U, procmon->dw10);
127c349dbc7Sjsg
128c349dbc7Sjsg return ret;
129c349dbc7Sjsg }
130c349dbc7Sjsg
has_phy_misc(struct drm_i915_private * i915,enum phy phy)131ad8b1aafSjsg static bool has_phy_misc(struct drm_i915_private *i915, enum phy phy)
132ad8b1aafSjsg {
133ad8b1aafSjsg /*
134ad8b1aafSjsg * Some platforms only expect PHY_MISC to be programmed for PHY-A and
135ad8b1aafSjsg * PHY-B and may not even have instances of the register for the
136ad8b1aafSjsg * other combo PHY's.
1375ca02815Sjsg *
1385ca02815Sjsg * ADL-S technically has three instances of PHY_MISC, but only requires
1395ca02815Sjsg * that we program it for PHY A.
140ad8b1aafSjsg */
1415ca02815Sjsg
1425ca02815Sjsg if (IS_ALDERLAKE_S(i915))
1435ca02815Sjsg return phy == PHY_A;
144*f005ef32Sjsg else if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) ||
1455ca02815Sjsg IS_ROCKETLAKE(i915) ||
1465ca02815Sjsg IS_DG1(i915))
147ad8b1aafSjsg return phy < PHY_C;
148ad8b1aafSjsg
149ad8b1aafSjsg return true;
150ad8b1aafSjsg }
151ad8b1aafSjsg
icl_combo_phy_enabled(struct drm_i915_private * dev_priv,enum phy phy)152c349dbc7Sjsg static bool icl_combo_phy_enabled(struct drm_i915_private *dev_priv,
153c349dbc7Sjsg enum phy phy)
154c349dbc7Sjsg {
155c349dbc7Sjsg /* The PHY C added by EHL has no PHY_MISC register */
156ad8b1aafSjsg if (!has_phy_misc(dev_priv, phy))
157c349dbc7Sjsg return intel_de_read(dev_priv, ICL_PORT_COMP_DW0(phy)) & COMP_INIT;
158c349dbc7Sjsg else
159c349dbc7Sjsg return !(intel_de_read(dev_priv, ICL_PHY_MISC(phy)) &
160c349dbc7Sjsg ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN) &&
161c349dbc7Sjsg (intel_de_read(dev_priv, ICL_PORT_COMP_DW0(phy)) & COMP_INIT);
162c349dbc7Sjsg }
163c349dbc7Sjsg
ehl_vbt_ddi_d_present(struct drm_i915_private * i915)164c349dbc7Sjsg static bool ehl_vbt_ddi_d_present(struct drm_i915_private *i915)
165c349dbc7Sjsg {
166c349dbc7Sjsg bool ddi_a_present = intel_bios_is_port_present(i915, PORT_A);
167c349dbc7Sjsg bool ddi_d_present = intel_bios_is_port_present(i915, PORT_D);
168c349dbc7Sjsg bool dsi_present = intel_bios_is_dsi_present(i915, NULL);
169c349dbc7Sjsg
170c349dbc7Sjsg /*
171c349dbc7Sjsg * VBT's 'dvo port' field for child devices references the DDI, not
172c349dbc7Sjsg * the PHY. So if combo PHY A is wired up to drive an external
173c349dbc7Sjsg * display, we should see a child device present on PORT_D and
174c349dbc7Sjsg * nothing on PORT_A and no DSI.
175c349dbc7Sjsg */
176c349dbc7Sjsg if (ddi_d_present && !ddi_a_present && !dsi_present)
177c349dbc7Sjsg return true;
178c349dbc7Sjsg
179c349dbc7Sjsg /*
180c349dbc7Sjsg * If we encounter a VBT that claims to have an external display on
181c349dbc7Sjsg * DDI-D _and_ an internal display on DDI-A/DSI leave an error message
182c349dbc7Sjsg * in the log and let the internal display win.
183c349dbc7Sjsg */
184c349dbc7Sjsg if (ddi_d_present)
185c349dbc7Sjsg drm_err(&i915->drm,
186c349dbc7Sjsg "VBT claims to have both internal and external displays on PHY A. Configuring for internal.\n");
187c349dbc7Sjsg
188c349dbc7Sjsg return false;
189c349dbc7Sjsg }
190c349dbc7Sjsg
phy_is_master(struct drm_i915_private * dev_priv,enum phy phy)191ad8b1aafSjsg static bool phy_is_master(struct drm_i915_private *dev_priv, enum phy phy)
192ad8b1aafSjsg {
193ad8b1aafSjsg /*
194ad8b1aafSjsg * Certain PHYs are connected to compensation resistors and act
195ad8b1aafSjsg * as masters to other PHYs.
196ad8b1aafSjsg *
197ad8b1aafSjsg * ICL,TGL:
198ad8b1aafSjsg * A(master) -> B(slave), C(slave)
1995ca02815Sjsg * RKL,DG1:
200ad8b1aafSjsg * A(master) -> B(slave)
201ad8b1aafSjsg * C(master) -> D(slave)
2025ca02815Sjsg * ADL-S:
2035ca02815Sjsg * A(master) -> B(slave), C(slave)
2045ca02815Sjsg * D(master) -> E(slave)
205ad8b1aafSjsg *
206ad8b1aafSjsg * We must set the IREFGEN bit for any PHY acting as a master
207ad8b1aafSjsg * to another PHY.
208ad8b1aafSjsg */
2095ca02815Sjsg if (phy == PHY_A)
210ad8b1aafSjsg return true;
2115ca02815Sjsg else if (IS_ALDERLAKE_S(dev_priv))
2125ca02815Sjsg return phy == PHY_D;
2135ca02815Sjsg else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv))
2145ca02815Sjsg return phy == PHY_C;
215ad8b1aafSjsg
2165ca02815Sjsg return false;
217ad8b1aafSjsg }
218ad8b1aafSjsg
icl_combo_phy_verify_state(struct drm_i915_private * dev_priv,enum phy phy)219c349dbc7Sjsg static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv,
220c349dbc7Sjsg enum phy phy)
221c349dbc7Sjsg {
222ad8b1aafSjsg bool ret = true;
223c349dbc7Sjsg u32 expected_val = 0;
224c349dbc7Sjsg
225c349dbc7Sjsg if (!icl_combo_phy_enabled(dev_priv, phy))
226c349dbc7Sjsg return false;
227c349dbc7Sjsg
2285ca02815Sjsg if (DISPLAY_VER(dev_priv) >= 12) {
2291bb76ff1Sjsg ret &= check_phy_reg(dev_priv, phy, ICL_PORT_TX_DW8_LN(0, phy),
230ad8b1aafSjsg ICL_PORT_TX_DW8_ODCC_CLK_SEL |
231ad8b1aafSjsg ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK,
232ad8b1aafSjsg ICL_PORT_TX_DW8_ODCC_CLK_SEL |
233ad8b1aafSjsg ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2);
234c349dbc7Sjsg
2351bb76ff1Sjsg ret &= check_phy_reg(dev_priv, phy, ICL_PORT_PCS_DW1_LN(0, phy),
236*f005ef32Sjsg DCC_MODE_SELECT_MASK, RUN_DCC_ONCE);
237ad8b1aafSjsg }
238ad8b1aafSjsg
2395ca02815Sjsg ret &= icl_verify_procmon_ref_values(dev_priv, phy);
240ad8b1aafSjsg
241ad8b1aafSjsg if (phy_is_master(dev_priv, phy)) {
242c349dbc7Sjsg ret &= check_phy_reg(dev_priv, phy, ICL_PORT_COMP_DW8(phy),
243c349dbc7Sjsg IREFGEN, IREFGEN);
244c349dbc7Sjsg
245*f005ef32Sjsg if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) {
246c349dbc7Sjsg if (ehl_vbt_ddi_d_present(dev_priv))
247c349dbc7Sjsg expected_val = ICL_PHY_MISC_MUX_DDID;
248c349dbc7Sjsg
249c349dbc7Sjsg ret &= check_phy_reg(dev_priv, phy, ICL_PHY_MISC(phy),
250c349dbc7Sjsg ICL_PHY_MISC_MUX_DDID,
251c349dbc7Sjsg expected_val);
252c349dbc7Sjsg }
253c349dbc7Sjsg }
254c349dbc7Sjsg
255c349dbc7Sjsg ret &= check_phy_reg(dev_priv, phy, ICL_PORT_CL_DW5(phy),
256c349dbc7Sjsg CL_POWER_DOWN_ENABLE, CL_POWER_DOWN_ENABLE);
257c349dbc7Sjsg
258c349dbc7Sjsg return ret;
259c349dbc7Sjsg }
260c349dbc7Sjsg
intel_combo_phy_power_up_lanes(struct drm_i915_private * dev_priv,enum phy phy,bool is_dsi,int lane_count,bool lane_reversal)261c349dbc7Sjsg void intel_combo_phy_power_up_lanes(struct drm_i915_private *dev_priv,
262c349dbc7Sjsg enum phy phy, bool is_dsi,
263c349dbc7Sjsg int lane_count, bool lane_reversal)
264c349dbc7Sjsg {
265c349dbc7Sjsg u8 lane_mask;
266c349dbc7Sjsg
267c349dbc7Sjsg if (is_dsi) {
268c349dbc7Sjsg drm_WARN_ON(&dev_priv->drm, lane_reversal);
269c349dbc7Sjsg
270c349dbc7Sjsg switch (lane_count) {
271c349dbc7Sjsg case 1:
272c349dbc7Sjsg lane_mask = PWR_DOWN_LN_3_1_0;
273c349dbc7Sjsg break;
274c349dbc7Sjsg case 2:
275c349dbc7Sjsg lane_mask = PWR_DOWN_LN_3_1;
276c349dbc7Sjsg break;
277c349dbc7Sjsg case 3:
278c349dbc7Sjsg lane_mask = PWR_DOWN_LN_3;
279c349dbc7Sjsg break;
280c349dbc7Sjsg default:
281c349dbc7Sjsg MISSING_CASE(lane_count);
282ad8b1aafSjsg fallthrough;
283c349dbc7Sjsg case 4:
284c349dbc7Sjsg lane_mask = PWR_UP_ALL_LANES;
285c349dbc7Sjsg break;
286c349dbc7Sjsg }
287c349dbc7Sjsg } else {
288c349dbc7Sjsg switch (lane_count) {
289c349dbc7Sjsg case 1:
290c349dbc7Sjsg lane_mask = lane_reversal ? PWR_DOWN_LN_2_1_0 :
291c349dbc7Sjsg PWR_DOWN_LN_3_2_1;
292c349dbc7Sjsg break;
293c349dbc7Sjsg case 2:
294c349dbc7Sjsg lane_mask = lane_reversal ? PWR_DOWN_LN_1_0 :
295c349dbc7Sjsg PWR_DOWN_LN_3_2;
296c349dbc7Sjsg break;
297c349dbc7Sjsg default:
298c349dbc7Sjsg MISSING_CASE(lane_count);
299ad8b1aafSjsg fallthrough;
300c349dbc7Sjsg case 4:
301c349dbc7Sjsg lane_mask = PWR_UP_ALL_LANES;
302c349dbc7Sjsg break;
303c349dbc7Sjsg }
304c349dbc7Sjsg }
305c349dbc7Sjsg
306*f005ef32Sjsg intel_de_rmw(dev_priv, ICL_PORT_CL_DW10(phy),
307*f005ef32Sjsg PWR_DOWN_LN_MASK, lane_mask);
308c349dbc7Sjsg }
309c349dbc7Sjsg
icl_combo_phys_init(struct drm_i915_private * dev_priv)310c349dbc7Sjsg static void icl_combo_phys_init(struct drm_i915_private *dev_priv)
311c349dbc7Sjsg {
312c349dbc7Sjsg enum phy phy;
313c349dbc7Sjsg
314c349dbc7Sjsg for_each_combo_phy(dev_priv, phy) {
315c349dbc7Sjsg u32 val;
316c349dbc7Sjsg
317c349dbc7Sjsg if (icl_combo_phy_verify_state(dev_priv, phy)) {
318c349dbc7Sjsg drm_dbg(&dev_priv->drm,
319c349dbc7Sjsg "Combo PHY %c already enabled, won't reprogram it.\n",
320c349dbc7Sjsg phy_name(phy));
321c349dbc7Sjsg continue;
322c349dbc7Sjsg }
323c349dbc7Sjsg
324ad8b1aafSjsg if (!has_phy_misc(dev_priv, phy))
325c349dbc7Sjsg goto skip_phy_misc;
326c349dbc7Sjsg
327c349dbc7Sjsg /*
328c349dbc7Sjsg * EHL's combo PHY A can be hooked up to either an external
329c349dbc7Sjsg * display (via DDI-D) or an internal display (via DDI-A or
330c349dbc7Sjsg * the DSI DPHY). This is a motherboard design decision that
331c349dbc7Sjsg * can't be changed on the fly, so initialize the PHY's mux
332c349dbc7Sjsg * based on whether our VBT indicates the presence of any
333c349dbc7Sjsg * "internal" child devices.
334c349dbc7Sjsg */
335c349dbc7Sjsg val = intel_de_read(dev_priv, ICL_PHY_MISC(phy));
336*f005ef32Sjsg if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) &&
337*f005ef32Sjsg phy == PHY_A) {
338c349dbc7Sjsg val &= ~ICL_PHY_MISC_MUX_DDID;
339c349dbc7Sjsg
340c349dbc7Sjsg if (ehl_vbt_ddi_d_present(dev_priv))
341c349dbc7Sjsg val |= ICL_PHY_MISC_MUX_DDID;
342c349dbc7Sjsg }
343c349dbc7Sjsg
344c349dbc7Sjsg val &= ~ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
345c349dbc7Sjsg intel_de_write(dev_priv, ICL_PHY_MISC(phy), val);
346c349dbc7Sjsg
347c349dbc7Sjsg skip_phy_misc:
3485ca02815Sjsg if (DISPLAY_VER(dev_priv) >= 12) {
3491bb76ff1Sjsg val = intel_de_read(dev_priv, ICL_PORT_TX_DW8_LN(0, phy));
350ad8b1aafSjsg val &= ~ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_MASK;
351ad8b1aafSjsg val |= ICL_PORT_TX_DW8_ODCC_CLK_SEL;
352ad8b1aafSjsg val |= ICL_PORT_TX_DW8_ODCC_CLK_DIV_SEL_DIV2;
353ad8b1aafSjsg intel_de_write(dev_priv, ICL_PORT_TX_DW8_GRP(phy), val);
354ad8b1aafSjsg
3551bb76ff1Sjsg val = intel_de_read(dev_priv, ICL_PORT_PCS_DW1_LN(0, phy));
356ad8b1aafSjsg val &= ~DCC_MODE_SELECT_MASK;
357*f005ef32Sjsg val |= RUN_DCC_ONCE;
358ad8b1aafSjsg intel_de_write(dev_priv, ICL_PORT_PCS_DW1_GRP(phy), val);
359ad8b1aafSjsg }
360ad8b1aafSjsg
3615ca02815Sjsg icl_set_procmon_ref_values(dev_priv, phy);
362c349dbc7Sjsg
363*f005ef32Sjsg if (phy_is_master(dev_priv, phy))
364*f005ef32Sjsg intel_de_rmw(dev_priv, ICL_PORT_COMP_DW8(phy),
365*f005ef32Sjsg 0, IREFGEN);
366c349dbc7Sjsg
367*f005ef32Sjsg intel_de_rmw(dev_priv, ICL_PORT_COMP_DW0(phy), 0, COMP_INIT);
368*f005ef32Sjsg intel_de_rmw(dev_priv, ICL_PORT_CL_DW5(phy),
369*f005ef32Sjsg 0, CL_POWER_DOWN_ENABLE);
370c349dbc7Sjsg }
371c349dbc7Sjsg }
372c349dbc7Sjsg
icl_combo_phys_uninit(struct drm_i915_private * dev_priv)373c349dbc7Sjsg static void icl_combo_phys_uninit(struct drm_i915_private *dev_priv)
374c349dbc7Sjsg {
375c349dbc7Sjsg enum phy phy;
376c349dbc7Sjsg
377c349dbc7Sjsg for_each_combo_phy_reverse(dev_priv, phy) {
378c349dbc7Sjsg if (phy == PHY_A &&
3795ca02815Sjsg !icl_combo_phy_verify_state(dev_priv, phy)) {
3805ca02815Sjsg if (IS_TIGERLAKE(dev_priv) || IS_DG1(dev_priv)) {
3815ca02815Sjsg /*
3825ca02815Sjsg * A known problem with old ifwi:
3835ca02815Sjsg * https://gitlab.freedesktop.org/drm/intel/-/issues/2411
3845ca02815Sjsg * Suppress the warning for CI. Remove ASAP!
3855ca02815Sjsg */
3865ca02815Sjsg drm_dbg_kms(&dev_priv->drm,
3875ca02815Sjsg "Combo PHY %c HW state changed unexpectedly\n",
3885ca02815Sjsg phy_name(phy));
3895ca02815Sjsg } else {
390c349dbc7Sjsg drm_warn(&dev_priv->drm,
391c349dbc7Sjsg "Combo PHY %c HW state changed unexpectedly\n",
392c349dbc7Sjsg phy_name(phy));
3935ca02815Sjsg }
3945ca02815Sjsg }
395c349dbc7Sjsg
396ad8b1aafSjsg if (!has_phy_misc(dev_priv, phy))
397c349dbc7Sjsg goto skip_phy_misc;
398c349dbc7Sjsg
399*f005ef32Sjsg intel_de_rmw(dev_priv, ICL_PHY_MISC(phy), 0,
400*f005ef32Sjsg ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN);
401c349dbc7Sjsg
402c349dbc7Sjsg skip_phy_misc:
403*f005ef32Sjsg intel_de_rmw(dev_priv, ICL_PORT_COMP_DW0(phy), COMP_INIT, 0);
404c349dbc7Sjsg }
405c349dbc7Sjsg }
406c349dbc7Sjsg
intel_combo_phy_init(struct drm_i915_private * i915)407c349dbc7Sjsg void intel_combo_phy_init(struct drm_i915_private *i915)
408c349dbc7Sjsg {
409c349dbc7Sjsg icl_combo_phys_init(i915);
410c349dbc7Sjsg }
411c349dbc7Sjsg
intel_combo_phy_uninit(struct drm_i915_private * i915)412c349dbc7Sjsg void intel_combo_phy_uninit(struct drm_i915_private *i915)
413c349dbc7Sjsg {
414c349dbc7Sjsg icl_combo_phys_uninit(i915);
415c349dbc7Sjsg }
416