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