Commit | Line | Data |
---|---|---|
7d57382e EA |
1 | /* |
2 | * Copyright 2006 Dave Airlie <airlied@linux.ie> | |
3 | * Copyright © 2006-2009 Intel Corporation | |
4 | * | |
5 | * Permission is hereby granted, free of charge, to any person obtaining a | |
6 | * copy of this software and associated documentation files (the "Software"), | |
7 | * to deal in the Software without restriction, including without limitation | |
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
9 | * and/or sell copies of the Software, and to permit persons to whom the | |
10 | * Software is furnished to do so, subject to the following conditions: | |
11 | * | |
12 | * The above copyright notice and this permission notice (including the next | |
13 | * paragraph) shall be included in all copies or substantial portions of the | |
14 | * Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
22 | * DEALINGS IN THE SOFTWARE. | |
23 | * | |
24 | * Authors: | |
25 | * Eric Anholt <eric@anholt.net> | |
26 | * Jesse Barnes <jesse.barnes@intel.com> | |
27 | */ | |
28 | ||
7d57382e | 29 | #include <linux/delay.h> |
178f736a | 30 | #include <linux/hdmi.h> |
331c201a JN |
31 | #include <linux/i2c.h> |
32 | #include <linux/slab.h> | |
01fabda8 | 33 | #include <linux/string_helpers.h> |
331c201a | 34 | |
6a99099f | 35 | #include <drm/display/drm_hdcp_helper.h> |
4fc8cb47 | 36 | #include <drm/display/drm_hdmi_helper.h> |
644edf52 | 37 | #include <drm/display/drm_scdc_helper.h> |
c6f95f27 | 38 | #include <drm/drm_atomic_helper.h> |
760285e7 DH |
39 | #include <drm/drm_crtc.h> |
40 | #include <drm/drm_edid.h> | |
07260855 | 41 | #include <drm/drm_print.h> |
11d0613a | 42 | #include <drm/drm_probe_helper.h> |
a1ed6865 | 43 | #include <drm/intel/intel_lpe_audio.h> |
331c201a | 44 | |
ae19ba91 JN |
45 | #include <media/cec-notifier.h> |
46 | ||
dafa65d1 | 47 | #include "g4x_hdmi.h" |
801543b2 | 48 | #include "i915_reg.h" |
07260855 | 49 | #include "i915_utils.h" |
12392a74 | 50 | #include "intel_atomic.h" |
5d986635 | 51 | #include "intel_audio.h" |
ec7f29ff | 52 | #include "intel_connector.h" |
5836bc5f | 53 | #include "intel_cx0_phy.h" |
fdc24cf3 | 54 | #include "intel_ddi.h" |
7785ae0b | 55 | #include "intel_de.h" |
bab87ef4 | 56 | #include "intel_display_driver.h" |
1d455f8d | 57 | #include "intel_display_types.h" |
27fec1f9 | 58 | #include "intel_dp.h" |
3ce2ea65 | 59 | #include "intel_gmbus.h" |
408bd917 | 60 | #include "intel_hdcp.h" |
9e6a82b9 | 61 | #include "intel_hdcp_regs.h" |
c0e08c20 | 62 | #include "intel_hdcp_shim.h" |
0550691d | 63 | #include "intel_hdmi.h" |
f3e18947 | 64 | #include "intel_lspcon.h" |
44c1220a | 65 | #include "intel_panel.h" |
0f16cd2a | 66 | #include "intel_pfit.h" |
865b73ea | 67 | #include "intel_snps_phy.h" |
635125e3 | 68 | #include "intel_vrr.h" |
7d57382e | 69 | |
afba0188 DV |
70 | static void |
71 | assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) | |
72 | { | |
1138137c | 73 | struct intel_display *display = to_intel_display(intel_hdmi); |
faa087c4 | 74 | u32 enabled_bits; |
afba0188 | 75 | |
1138137c | 76 | enabled_bits = HAS_DDI(display) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; |
afba0188 | 77 | |
1138137c JN |
78 | drm_WARN(display->drm, |
79 | intel_de_read(display, intel_hdmi->hdmi_reg) & enabled_bits, | |
10d4e146 | 80 | "HDMI port enabled, expecting disabled\n"); |
afba0188 DV |
81 | } |
82 | ||
8fc0aa6e | 83 | static void |
1138137c | 84 | assert_hdmi_transcoder_func_disabled(struct intel_display *display, |
8fc0aa6e ID |
85 | enum transcoder cpu_transcoder) |
86 | { | |
1138137c JN |
87 | drm_WARN(display->drm, |
88 | intel_de_read(display, TRANS_DDI_FUNC_CTL(display, cpu_transcoder)) & | |
10d4e146 PB |
89 | TRANS_DDI_FUNC_ENABLE, |
90 | "HDMI transcoder function enabled, expecting disabled\n"); | |
8fc0aa6e ID |
91 | } |
92 | ||
1d776538 | 93 | static u32 g4x_infoframe_index(unsigned int type) |
3c17fe4b | 94 | { |
178f736a | 95 | switch (type) { |
5cb3c1a1 VS |
96 | case HDMI_PACKET_TYPE_GAMUT_METADATA: |
97 | return VIDEO_DIP_SELECT_GAMUT; | |
178f736a | 98 | case HDMI_INFOFRAME_TYPE_AVI: |
ed517fbb | 99 | return VIDEO_DIP_SELECT_AVI; |
178f736a | 100 | case HDMI_INFOFRAME_TYPE_SPD: |
ed517fbb | 101 | return VIDEO_DIP_SELECT_SPD; |
c8bb75af LD |
102 | case HDMI_INFOFRAME_TYPE_VENDOR: |
103 | return VIDEO_DIP_SELECT_VENDOR; | |
45187ace | 104 | default: |
ffc85dab | 105 | MISSING_CASE(type); |
ed517fbb | 106 | return 0; |
45187ace | 107 | } |
45187ace JB |
108 | } |
109 | ||
1d776538 | 110 | static u32 g4x_infoframe_enable(unsigned int type) |
45187ace | 111 | { |
178f736a | 112 | switch (type) { |
5cb3c1a1 VS |
113 | case HDMI_PACKET_TYPE_GENERAL_CONTROL: |
114 | return VIDEO_DIP_ENABLE_GCP; | |
115 | case HDMI_PACKET_TYPE_GAMUT_METADATA: | |
116 | return VIDEO_DIP_ENABLE_GAMUT; | |
509efa2b VS |
117 | case DP_SDP_VSC: |
118 | return 0; | |
12ea8929 MG |
119 | case DP_SDP_ADAPTIVE_SYNC: |
120 | return 0; | |
178f736a | 121 | case HDMI_INFOFRAME_TYPE_AVI: |
ed517fbb | 122 | return VIDEO_DIP_ENABLE_AVI; |
178f736a | 123 | case HDMI_INFOFRAME_TYPE_SPD: |
ed517fbb | 124 | return VIDEO_DIP_ENABLE_SPD; |
c8bb75af LD |
125 | case HDMI_INFOFRAME_TYPE_VENDOR: |
126 | return VIDEO_DIP_ENABLE_VENDOR; | |
c0560fab US |
127 | case HDMI_INFOFRAME_TYPE_DRM: |
128 | return 0; | |
fa193ff7 | 129 | default: |
ffc85dab | 130 | MISSING_CASE(type); |
ed517fbb | 131 | return 0; |
fa193ff7 | 132 | } |
fa193ff7 PZ |
133 | } |
134 | ||
1d776538 | 135 | static u32 hsw_infoframe_enable(unsigned int type) |
2da8af54 | 136 | { |
178f736a | 137 | switch (type) { |
5cb3c1a1 VS |
138 | case HDMI_PACKET_TYPE_GENERAL_CONTROL: |
139 | return VIDEO_DIP_ENABLE_GCP_HSW; | |
140 | case HDMI_PACKET_TYPE_GAMUT_METADATA: | |
141 | return VIDEO_DIP_ENABLE_GMP_HSW; | |
1d776538 VS |
142 | case DP_SDP_VSC: |
143 | return VIDEO_DIP_ENABLE_VSC_HSW; | |
12ea8929 MG |
144 | case DP_SDP_ADAPTIVE_SYNC: |
145 | return VIDEO_DIP_ENABLE_AS_ADL; | |
4c614831 MN |
146 | case DP_SDP_PPS: |
147 | return VDIP_ENABLE_PPS; | |
178f736a | 148 | case HDMI_INFOFRAME_TYPE_AVI: |
2da8af54 | 149 | return VIDEO_DIP_ENABLE_AVI_HSW; |
178f736a | 150 | case HDMI_INFOFRAME_TYPE_SPD: |
2da8af54 | 151 | return VIDEO_DIP_ENABLE_SPD_HSW; |
c8bb75af LD |
152 | case HDMI_INFOFRAME_TYPE_VENDOR: |
153 | return VIDEO_DIP_ENABLE_VS_HSW; | |
44b42ebf VS |
154 | case HDMI_INFOFRAME_TYPE_DRM: |
155 | return VIDEO_DIP_ENABLE_DRM_GLK; | |
2da8af54 | 156 | default: |
ffc85dab | 157 | MISSING_CASE(type); |
2da8af54 PZ |
158 | return 0; |
159 | } | |
160 | } | |
161 | ||
f0f59a00 | 162 | static i915_reg_t |
1138137c | 163 | hsw_dip_data_reg(struct intel_display *display, |
f0f59a00 | 164 | enum transcoder cpu_transcoder, |
1d776538 | 165 | unsigned int type, |
f0f59a00 | 166 | int i) |
2da8af54 | 167 | { |
178f736a | 168 | switch (type) { |
5cb3c1a1 | 169 | case HDMI_PACKET_TYPE_GAMUT_METADATA: |
1138137c | 170 | return HSW_TVIDEO_DIP_GMP_DATA(display, cpu_transcoder, i); |
1d776538 | 171 | case DP_SDP_VSC: |
1138137c | 172 | return HSW_TVIDEO_DIP_VSC_DATA(display, cpu_transcoder, i); |
12ea8929 | 173 | case DP_SDP_ADAPTIVE_SYNC: |
1138137c | 174 | return ADL_TVIDEO_DIP_AS_SDP_DATA(display, cpu_transcoder, i); |
4c614831 | 175 | case DP_SDP_PPS: |
1138137c | 176 | return ICL_VIDEO_DIP_PPS_DATA(display, cpu_transcoder, i); |
178f736a | 177 | case HDMI_INFOFRAME_TYPE_AVI: |
1138137c | 178 | return HSW_TVIDEO_DIP_AVI_DATA(display, cpu_transcoder, i); |
178f736a | 179 | case HDMI_INFOFRAME_TYPE_SPD: |
1138137c | 180 | return HSW_TVIDEO_DIP_SPD_DATA(display, cpu_transcoder, i); |
c8bb75af | 181 | case HDMI_INFOFRAME_TYPE_VENDOR: |
1138137c | 182 | return HSW_TVIDEO_DIP_VS_DATA(display, cpu_transcoder, i); |
44b42ebf | 183 | case HDMI_INFOFRAME_TYPE_DRM: |
1138137c | 184 | return GLK_TVIDEO_DIP_DRM_DATA(display, cpu_transcoder, i); |
2da8af54 | 185 | default: |
ffc85dab | 186 | MISSING_CASE(type); |
f0f59a00 | 187 | return INVALID_MMIO_REG; |
2da8af54 PZ |
188 | } |
189 | } | |
190 | ||
1138137c | 191 | static int hsw_dip_data_size(struct intel_display *display, |
922430dd | 192 | unsigned int type) |
4c614831 MN |
193 | { |
194 | switch (type) { | |
195 | case DP_SDP_VSC: | |
196 | return VIDEO_DIP_VSC_DATA_SIZE; | |
12ea8929 MG |
197 | case DP_SDP_ADAPTIVE_SYNC: |
198 | return VIDEO_DIP_ASYNC_DATA_SIZE; | |
4c614831 MN |
199 | case DP_SDP_PPS: |
200 | return VIDEO_DIP_PPS_DATA_SIZE; | |
922430dd | 201 | case HDMI_PACKET_TYPE_GAMUT_METADATA: |
1138137c | 202 | if (DISPLAY_VER(display) >= 11) |
922430dd GM |
203 | return VIDEO_DIP_GMP_DATA_SIZE; |
204 | else | |
205 | return VIDEO_DIP_DATA_SIZE; | |
4c614831 MN |
206 | default: |
207 | return VIDEO_DIP_DATA_SIZE; | |
208 | } | |
209 | } | |
210 | ||
790ea70c | 211 | static void g4x_write_infoframe(struct intel_encoder *encoder, |
ac240288 | 212 | const struct intel_crtc_state *crtc_state, |
1d776538 | 213 | unsigned int type, |
fff63867 | 214 | const void *frame, ssize_t len) |
45187ace | 215 | { |
1138137c | 216 | struct intel_display *display = to_intel_display(encoder); |
faa087c4 | 217 | const u32 *data = frame; |
1138137c | 218 | u32 val = intel_de_read(display, VIDEO_DIP_CTL); |
178f736a | 219 | int i; |
3c17fe4b | 220 | |
1138137c | 221 | drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), |
10d4e146 | 222 | "Writing DIP with CTL reg disabled\n"); |
822974ae | 223 | |
1d4f85ac | 224 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
178f736a | 225 | val |= g4x_infoframe_index(type); |
22509ec8 | 226 | |
178f736a | 227 | val &= ~g4x_infoframe_enable(type); |
45187ace | 228 | |
1138137c | 229 | intel_de_write(display, VIDEO_DIP_CTL, val); |
3c17fe4b | 230 | |
45187ace | 231 | for (i = 0; i < len; i += 4) { |
1138137c | 232 | intel_de_write(display, VIDEO_DIP_DATA, *data); |
3c17fe4b DH |
233 | data++; |
234 | } | |
adf00b26 PZ |
235 | /* Write every possible data byte to force correct ECC calculation. */ |
236 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) | |
1138137c | 237 | intel_de_write(display, VIDEO_DIP_DATA, 0); |
3c17fe4b | 238 | |
178f736a | 239 | val |= g4x_infoframe_enable(type); |
60c5ea2d | 240 | val &= ~VIDEO_DIP_FREQ_MASK; |
4b24c933 | 241 | val |= VIDEO_DIP_FREQ_VSYNC; |
45187ace | 242 | |
1138137c JN |
243 | intel_de_write(display, VIDEO_DIP_CTL, val); |
244 | intel_de_posting_read(display, VIDEO_DIP_CTL); | |
3c17fe4b DH |
245 | } |
246 | ||
f2a10d61 VS |
247 | static void g4x_read_infoframe(struct intel_encoder *encoder, |
248 | const struct intel_crtc_state *crtc_state, | |
249 | unsigned int type, | |
250 | void *frame, ssize_t len) | |
251 | { | |
1138137c | 252 | struct intel_display *display = to_intel_display(encoder); |
cd5103ee | 253 | u32 *data = frame; |
f2a10d61 VS |
254 | int i; |
255 | ||
1138137c | 256 | intel_de_rmw(display, VIDEO_DIP_CTL, |
cd5103ee | 257 | VIDEO_DIP_SELECT_MASK | 0xf, g4x_infoframe_index(type)); |
f2a10d61 VS |
258 | |
259 | for (i = 0; i < len; i += 4) | |
1138137c | 260 | *data++ = intel_de_read(display, VIDEO_DIP_DATA); |
f2a10d61 VS |
261 | } |
262 | ||
509efa2b | 263 | static u32 g4x_infoframes_enabled(struct intel_encoder *encoder, |
cda0aaaf | 264 | const struct intel_crtc_state *pipe_config) |
e43823ec | 265 | { |
1138137c JN |
266 | struct intel_display *display = to_intel_display(encoder); |
267 | u32 val = intel_de_read(display, VIDEO_DIP_CTL); | |
e43823ec | 268 | |
ec1dc603 | 269 | if ((val & VIDEO_DIP_ENABLE) == 0) |
509efa2b | 270 | return 0; |
89a35ecd | 271 | |
790ea70c | 272 | if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port)) |
509efa2b | 273 | return 0; |
ec1dc603 VS |
274 | |
275 | return val & (VIDEO_DIP_ENABLE_AVI | | |
276 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); | |
e43823ec JB |
277 | } |
278 | ||
790ea70c | 279 | static void ibx_write_infoframe(struct intel_encoder *encoder, |
ac240288 | 280 | const struct intel_crtc_state *crtc_state, |
1d776538 | 281 | unsigned int type, |
fff63867 | 282 | const void *frame, ssize_t len) |
fdf1250a | 283 | { |
1138137c | 284 | struct intel_display *display = to_intel_display(encoder); |
faa087c4 | 285 | const u32 *data = frame; |
f15f01a7 VS |
286 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
287 | i915_reg_t reg = TVIDEO_DIP_CTL(crtc->pipe); | |
1138137c | 288 | u32 val = intel_de_read(display, reg); |
f0f59a00 | 289 | int i; |
fdf1250a | 290 | |
1138137c | 291 | drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), |
10d4e146 | 292 | "Writing DIP with CTL reg disabled\n"); |
822974ae | 293 | |
fdf1250a | 294 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
178f736a | 295 | val |= g4x_infoframe_index(type); |
fdf1250a | 296 | |
178f736a | 297 | val &= ~g4x_infoframe_enable(type); |
fdf1250a | 298 | |
1138137c | 299 | intel_de_write(display, reg, val); |
fdf1250a PZ |
300 | |
301 | for (i = 0; i < len; i += 4) { | |
1138137c | 302 | intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe), |
8192c82c | 303 | *data); |
fdf1250a PZ |
304 | data++; |
305 | } | |
adf00b26 PZ |
306 | /* Write every possible data byte to force correct ECC calculation. */ |
307 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) | |
1138137c | 308 | intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe), 0); |
fdf1250a | 309 | |
178f736a | 310 | val |= g4x_infoframe_enable(type); |
fdf1250a | 311 | val &= ~VIDEO_DIP_FREQ_MASK; |
4b24c933 | 312 | val |= VIDEO_DIP_FREQ_VSYNC; |
fdf1250a | 313 | |
1138137c JN |
314 | intel_de_write(display, reg, val); |
315 | intel_de_posting_read(display, reg); | |
fdf1250a PZ |
316 | } |
317 | ||
f2a10d61 VS |
318 | static void ibx_read_infoframe(struct intel_encoder *encoder, |
319 | const struct intel_crtc_state *crtc_state, | |
320 | unsigned int type, | |
321 | void *frame, ssize_t len) | |
322 | { | |
1138137c | 323 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 324 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
cd5103ee | 325 | u32 *data = frame; |
f2a10d61 VS |
326 | int i; |
327 | ||
1138137c | 328 | intel_de_rmw(display, TVIDEO_DIP_CTL(crtc->pipe), |
cd5103ee | 329 | VIDEO_DIP_SELECT_MASK | 0xf, g4x_infoframe_index(type)); |
f2a10d61 VS |
330 | |
331 | for (i = 0; i < len; i += 4) | |
1138137c | 332 | *data++ = intel_de_read(display, TVIDEO_DIP_DATA(crtc->pipe)); |
f2a10d61 VS |
333 | } |
334 | ||
509efa2b | 335 | static u32 ibx_infoframes_enabled(struct intel_encoder *encoder, |
cda0aaaf | 336 | const struct intel_crtc_state *pipe_config) |
e43823ec | 337 | { |
1138137c | 338 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 339 | enum pipe pipe = to_intel_crtc(pipe_config->uapi.crtc)->pipe; |
cda0aaaf | 340 | i915_reg_t reg = TVIDEO_DIP_CTL(pipe); |
1138137c | 341 | u32 val = intel_de_read(display, reg); |
e43823ec | 342 | |
ec1dc603 | 343 | if ((val & VIDEO_DIP_ENABLE) == 0) |
509efa2b | 344 | return 0; |
ec1dc603 | 345 | |
790ea70c | 346 | if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port)) |
509efa2b | 347 | return 0; |
052f62f7 | 348 | |
ec1dc603 VS |
349 | return val & (VIDEO_DIP_ENABLE_AVI | |
350 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
351 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
e43823ec JB |
352 | } |
353 | ||
790ea70c | 354 | static void cpt_write_infoframe(struct intel_encoder *encoder, |
ac240288 | 355 | const struct intel_crtc_state *crtc_state, |
1d776538 | 356 | unsigned int type, |
fff63867 | 357 | const void *frame, ssize_t len) |
b055c8f3 | 358 | { |
1138137c | 359 | struct intel_display *display = to_intel_display(encoder); |
faa087c4 | 360 | const u32 *data = frame; |
f15f01a7 VS |
361 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
362 | i915_reg_t reg = TVIDEO_DIP_CTL(crtc->pipe); | |
1138137c | 363 | u32 val = intel_de_read(display, reg); |
f0f59a00 | 364 | int i; |
b055c8f3 | 365 | |
1138137c | 366 | drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), |
10d4e146 | 367 | "Writing DIP with CTL reg disabled\n"); |
822974ae | 368 | |
64a8fc01 | 369 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
178f736a | 370 | val |= g4x_infoframe_index(type); |
45187ace | 371 | |
ecb97851 PZ |
372 | /* The DIP control register spec says that we need to update the AVI |
373 | * infoframe without clearing its enable bit */ | |
178f736a DL |
374 | if (type != HDMI_INFOFRAME_TYPE_AVI) |
375 | val &= ~g4x_infoframe_enable(type); | |
ecb97851 | 376 | |
1138137c | 377 | intel_de_write(display, reg, val); |
45187ace JB |
378 | |
379 | for (i = 0; i < len; i += 4) { | |
1138137c | 380 | intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe), |
8192c82c | 381 | *data); |
b055c8f3 JB |
382 | data++; |
383 | } | |
adf00b26 PZ |
384 | /* Write every possible data byte to force correct ECC calculation. */ |
385 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) | |
1138137c | 386 | intel_de_write(display, TVIDEO_DIP_DATA(crtc->pipe), 0); |
b055c8f3 | 387 | |
178f736a | 388 | val |= g4x_infoframe_enable(type); |
60c5ea2d | 389 | val &= ~VIDEO_DIP_FREQ_MASK; |
4b24c933 | 390 | val |= VIDEO_DIP_FREQ_VSYNC; |
45187ace | 391 | |
1138137c JN |
392 | intel_de_write(display, reg, val); |
393 | intel_de_posting_read(display, reg); | |
45187ace | 394 | } |
90b107c8 | 395 | |
f2a10d61 VS |
396 | static void cpt_read_infoframe(struct intel_encoder *encoder, |
397 | const struct intel_crtc_state *crtc_state, | |
398 | unsigned int type, | |
399 | void *frame, ssize_t len) | |
400 | { | |
1138137c | 401 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 402 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
cd5103ee | 403 | u32 *data = frame; |
f2a10d61 VS |
404 | int i; |
405 | ||
1138137c | 406 | intel_de_rmw(display, TVIDEO_DIP_CTL(crtc->pipe), |
cd5103ee | 407 | VIDEO_DIP_SELECT_MASK | 0xf, g4x_infoframe_index(type)); |
f2a10d61 VS |
408 | |
409 | for (i = 0; i < len; i += 4) | |
1138137c | 410 | *data++ = intel_de_read(display, TVIDEO_DIP_DATA(crtc->pipe)); |
f2a10d61 VS |
411 | } |
412 | ||
509efa2b | 413 | static u32 cpt_infoframes_enabled(struct intel_encoder *encoder, |
cda0aaaf | 414 | const struct intel_crtc_state *pipe_config) |
e43823ec | 415 | { |
1138137c | 416 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 417 | enum pipe pipe = to_intel_crtc(pipe_config->uapi.crtc)->pipe; |
1138137c | 418 | u32 val = intel_de_read(display, TVIDEO_DIP_CTL(pipe)); |
e43823ec | 419 | |
ec1dc603 | 420 | if ((val & VIDEO_DIP_ENABLE) == 0) |
509efa2b | 421 | return 0; |
ec1dc603 VS |
422 | |
423 | return val & (VIDEO_DIP_ENABLE_AVI | | |
424 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
425 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
e43823ec JB |
426 | } |
427 | ||
790ea70c | 428 | static void vlv_write_infoframe(struct intel_encoder *encoder, |
ac240288 | 429 | const struct intel_crtc_state *crtc_state, |
1d776538 | 430 | unsigned int type, |
fff63867 | 431 | const void *frame, ssize_t len) |
90b107c8 | 432 | { |
1138137c | 433 | struct intel_display *display = to_intel_display(encoder); |
faa087c4 | 434 | const u32 *data = frame; |
f15f01a7 VS |
435 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
436 | i915_reg_t reg = VLV_TVIDEO_DIP_CTL(crtc->pipe); | |
1138137c | 437 | u32 val = intel_de_read(display, reg); |
f0f59a00 | 438 | int i; |
90b107c8 | 439 | |
1138137c | 440 | drm_WARN(display->drm, !(val & VIDEO_DIP_ENABLE), |
10d4e146 | 441 | "Writing DIP with CTL reg disabled\n"); |
822974ae | 442 | |
90b107c8 | 443 | val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */ |
178f736a | 444 | val |= g4x_infoframe_index(type); |
22509ec8 | 445 | |
178f736a | 446 | val &= ~g4x_infoframe_enable(type); |
90b107c8 | 447 | |
1138137c | 448 | intel_de_write(display, reg, val); |
90b107c8 SK |
449 | |
450 | for (i = 0; i < len; i += 4) { | |
1138137c | 451 | intel_de_write(display, |
f15f01a7 | 452 | VLV_TVIDEO_DIP_DATA(crtc->pipe), *data); |
90b107c8 SK |
453 | data++; |
454 | } | |
adf00b26 PZ |
455 | /* Write every possible data byte to force correct ECC calculation. */ |
456 | for (; i < VIDEO_DIP_DATA_SIZE; i += 4) | |
1138137c | 457 | intel_de_write(display, |
f15f01a7 | 458 | VLV_TVIDEO_DIP_DATA(crtc->pipe), 0); |
90b107c8 | 459 | |
178f736a | 460 | val |= g4x_infoframe_enable(type); |
60c5ea2d | 461 | val &= ~VIDEO_DIP_FREQ_MASK; |
4b24c933 | 462 | val |= VIDEO_DIP_FREQ_VSYNC; |
90b107c8 | 463 | |
1138137c JN |
464 | intel_de_write(display, reg, val); |
465 | intel_de_posting_read(display, reg); | |
90b107c8 SK |
466 | } |
467 | ||
f2a10d61 VS |
468 | static void vlv_read_infoframe(struct intel_encoder *encoder, |
469 | const struct intel_crtc_state *crtc_state, | |
470 | unsigned int type, | |
471 | void *frame, ssize_t len) | |
472 | { | |
1138137c | 473 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 474 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
cd5103ee | 475 | u32 *data = frame; |
f2a10d61 VS |
476 | int i; |
477 | ||
1138137c | 478 | intel_de_rmw(display, VLV_TVIDEO_DIP_CTL(crtc->pipe), |
cd5103ee | 479 | VIDEO_DIP_SELECT_MASK | 0xf, g4x_infoframe_index(type)); |
f2a10d61 VS |
480 | |
481 | for (i = 0; i < len; i += 4) | |
1138137c | 482 | *data++ = intel_de_read(display, |
8192c82c | 483 | VLV_TVIDEO_DIP_DATA(crtc->pipe)); |
f2a10d61 VS |
484 | } |
485 | ||
509efa2b | 486 | static u32 vlv_infoframes_enabled(struct intel_encoder *encoder, |
cda0aaaf | 487 | const struct intel_crtc_state *pipe_config) |
e43823ec | 488 | { |
1138137c | 489 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 490 | enum pipe pipe = to_intel_crtc(pipe_config->uapi.crtc)->pipe; |
1138137c | 491 | u32 val = intel_de_read(display, VLV_TVIDEO_DIP_CTL(pipe)); |
e43823ec | 492 | |
ec1dc603 | 493 | if ((val & VIDEO_DIP_ENABLE) == 0) |
509efa2b | 494 | return 0; |
ec1dc603 | 495 | |
790ea70c | 496 | if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(encoder->port)) |
509efa2b | 497 | return 0; |
535afa2e | 498 | |
ec1dc603 VS |
499 | return val & (VIDEO_DIP_ENABLE_AVI | |
500 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
501 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
e43823ec JB |
502 | } |
503 | ||
1a911350 US |
504 | void hsw_write_infoframe(struct intel_encoder *encoder, |
505 | const struct intel_crtc_state *crtc_state, | |
506 | unsigned int type, | |
507 | const void *frame, ssize_t len) | |
8c5f5f7c | 508 | { |
1138137c | 509 | struct intel_display *display = to_intel_display(encoder); |
faa087c4 | 510 | const u32 *data = frame; |
ac240288 | 511 | enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; |
1138137c | 512 | i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(display, cpu_transcoder); |
4c614831 | 513 | int data_size; |
178f736a | 514 | int i; |
1138137c | 515 | u32 val = intel_de_read(display, ctl_reg); |
8c5f5f7c | 516 | |
1138137c | 517 | data_size = hsw_dip_data_size(display, type); |
922430dd | 518 | |
1138137c | 519 | drm_WARN_ON(display->drm, len > data_size); |
4c614831 | 520 | |
178f736a | 521 | val &= ~hsw_infoframe_enable(type); |
1138137c | 522 | intel_de_write(display, ctl_reg, val); |
2da8af54 PZ |
523 | |
524 | for (i = 0; i < len; i += 4) { | |
1138137c JN |
525 | intel_de_write(display, |
526 | hsw_dip_data_reg(display, cpu_transcoder, type, i >> 2), | |
8192c82c | 527 | *data); |
2da8af54 PZ |
528 | data++; |
529 | } | |
adf00b26 | 530 | /* Write every possible data byte to force correct ECC calculation. */ |
1d776538 | 531 | for (; i < data_size; i += 4) |
1138137c JN |
532 | intel_de_write(display, |
533 | hsw_dip_data_reg(display, cpu_transcoder, type, i >> 2), | |
8192c82c | 534 | 0); |
8c5f5f7c | 535 | |
09df8ba5 | 536 | /* Wa_14013475917 */ |
1138137c | 537 | if (!(IS_DISPLAY_VER(display, 13, 14) && crtc_state->has_psr && |
54599011 | 538 | !crtc_state->has_panel_replay && type == DP_SDP_VSC)) |
bac2d7d8 JH |
539 | val |= hsw_infoframe_enable(type); |
540 | ||
541 | if (type == DP_SDP_VSC) | |
542 | val |= VSC_DIP_HW_DATA_SW_HEA; | |
09df8ba5 | 543 | |
1138137c JN |
544 | intel_de_write(display, ctl_reg, val); |
545 | intel_de_posting_read(display, ctl_reg); | |
8c5f5f7c ED |
546 | } |
547 | ||
b7594150 US |
548 | void hsw_read_infoframe(struct intel_encoder *encoder, |
549 | const struct intel_crtc_state *crtc_state, | |
550 | unsigned int type, void *frame, ssize_t len) | |
f2a10d61 | 551 | { |
1138137c | 552 | struct intel_display *display = to_intel_display(encoder); |
f2a10d61 | 553 | enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; |
a37937cd | 554 | u32 *data = frame; |
f2a10d61 VS |
555 | int i; |
556 | ||
f2a10d61 | 557 | for (i = 0; i < len; i += 4) |
1138137c JN |
558 | *data++ = intel_de_read(display, |
559 | hsw_dip_data_reg(display, cpu_transcoder, type, i >> 2)); | |
f2a10d61 VS |
560 | } |
561 | ||
509efa2b | 562 | static u32 hsw_infoframes_enabled(struct intel_encoder *encoder, |
cda0aaaf | 563 | const struct intel_crtc_state *pipe_config) |
e43823ec | 564 | { |
1138137c JN |
565 | struct intel_display *display = to_intel_display(encoder); |
566 | u32 val = intel_de_read(display, | |
567 | HSW_TVIDEO_DIP_CTL(display, pipe_config->cpu_transcoder)); | |
44b42ebf VS |
568 | u32 mask; |
569 | ||
570 | mask = (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | | |
571 | VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | | |
572 | VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW); | |
573 | ||
1138137c | 574 | if (DISPLAY_VER(display) >= 10) |
44b42ebf | 575 | mask |= VIDEO_DIP_ENABLE_DRM_GLK; |
e43823ec | 576 | |
1138137c | 577 | if (HAS_AS_SDP(display)) |
12ea8929 MG |
578 | mask |= VIDEO_DIP_ENABLE_AS_ADL; |
579 | ||
44b42ebf | 580 | return val & mask; |
e43823ec JB |
581 | } |
582 | ||
509efa2b VS |
583 | static const u8 infoframe_type_to_idx[] = { |
584 | HDMI_PACKET_TYPE_GENERAL_CONTROL, | |
585 | HDMI_PACKET_TYPE_GAMUT_METADATA, | |
586 | DP_SDP_VSC, | |
12ea8929 | 587 | DP_SDP_ADAPTIVE_SYNC, |
509efa2b VS |
588 | HDMI_INFOFRAME_TYPE_AVI, |
589 | HDMI_INFOFRAME_TYPE_SPD, | |
590 | HDMI_INFOFRAME_TYPE_VENDOR, | |
5a0200f6 | 591 | HDMI_INFOFRAME_TYPE_DRM, |
509efa2b VS |
592 | }; |
593 | ||
fbf08556 VS |
594 | u32 intel_hdmi_infoframe_enable(unsigned int type) |
595 | { | |
596 | int i; | |
597 | ||
598 | for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) { | |
599 | if (infoframe_type_to_idx[i] == type) | |
600 | return BIT(i); | |
601 | } | |
602 | ||
603 | return 0; | |
604 | } | |
605 | ||
509efa2b VS |
606 | u32 intel_hdmi_infoframes_enabled(struct intel_encoder *encoder, |
607 | const struct intel_crtc_state *crtc_state) | |
608 | { | |
1138137c | 609 | struct intel_display *display = to_intel_display(encoder); |
b7d02c3a | 610 | struct intel_digital_port *dig_port = enc_to_dig_port(encoder); |
509efa2b VS |
611 | u32 val, ret = 0; |
612 | int i; | |
613 | ||
614 | val = dig_port->infoframes_enabled(encoder, crtc_state); | |
615 | ||
616 | /* map from hardware bits to dip idx */ | |
617 | for (i = 0; i < ARRAY_SIZE(infoframe_type_to_idx); i++) { | |
618 | unsigned int type = infoframe_type_to_idx[i]; | |
619 | ||
1138137c | 620 | if (HAS_DDI(display)) { |
509efa2b VS |
621 | if (val & hsw_infoframe_enable(type)) |
622 | ret |= BIT(i); | |
623 | } else { | |
624 | if (val & g4x_infoframe_enable(type)) | |
625 | ret |= BIT(i); | |
626 | } | |
627 | } | |
628 | ||
629 | return ret; | |
630 | } | |
631 | ||
5adaea79 DL |
632 | /* |
633 | * The data we write to the DIP data buffer registers is 1 byte bigger than the | |
634 | * HDMI infoframe size because of an ECC/reserved byte at position 3 (starting | |
635 | * at 0). It's also a byte used by DisplayPort so the same DIP registers can be | |
636 | * used for both technologies. | |
637 | * | |
638 | * DW0: Reserved/ECC/DP | HB2 | HB1 | HB0 | |
639 | * DW1: DB3 | DB2 | DB1 | DB0 | |
640 | * DW2: DB7 | DB6 | DB5 | DB4 | |
641 | * DW3: ... | |
642 | * | |
643 | * (HB is Header Byte, DB is Data Byte) | |
644 | * | |
645 | * The hdmi pack() functions don't know about that hardware specific hole so we | |
646 | * trick them by giving an offset into the buffer and moving back the header | |
647 | * bytes by one. | |
648 | */ | |
790ea70c | 649 | static void intel_write_infoframe(struct intel_encoder *encoder, |
ac240288 | 650 | const struct intel_crtc_state *crtc_state, |
fbf08556 VS |
651 | enum hdmi_infoframe_type type, |
652 | const union hdmi_infoframe *frame) | |
45187ace | 653 | { |
7801f3b7 | 654 | struct intel_digital_port *dig_port = enc_to_dig_port(encoder); |
faa087c4 | 655 | u8 buffer[VIDEO_DIP_DATA_SIZE]; |
5adaea79 | 656 | ssize_t len; |
45187ace | 657 | |
fbf08556 VS |
658 | if ((crtc_state->infoframes.enable & |
659 | intel_hdmi_infoframe_enable(type)) == 0) | |
660 | return; | |
661 | ||
3a47ae20 | 662 | if (drm_WARN_ON(encoder->base.dev, frame->any.type != type)) |
fbf08556 VS |
663 | return; |
664 | ||
5adaea79 | 665 | /* see comment above for the reason for this offset */ |
fbf08556 | 666 | len = hdmi_infoframe_pack_only(frame, buffer + 1, sizeof(buffer) - 1); |
3a47ae20 | 667 | if (drm_WARN_ON(encoder->base.dev, len < 0)) |
5adaea79 DL |
668 | return; |
669 | ||
670 | /* Insert the 'hole' (see big comment above) at position 3 */ | |
121f0ff5 | 671 | memmove(&buffer[0], &buffer[1], 3); |
5adaea79 DL |
672 | buffer[3] = 0; |
673 | len++; | |
45187ace | 674 | |
7801f3b7 | 675 | dig_port->write_infoframe(encoder, crtc_state, type, buffer, len); |
45187ace JB |
676 | } |
677 | ||
f2a10d61 VS |
678 | void intel_read_infoframe(struct intel_encoder *encoder, |
679 | const struct intel_crtc_state *crtc_state, | |
680 | enum hdmi_infoframe_type type, | |
681 | union hdmi_infoframe *frame) | |
682 | { | |
7801f3b7 | 683 | struct intel_digital_port *dig_port = enc_to_dig_port(encoder); |
f2a10d61 VS |
684 | u8 buffer[VIDEO_DIP_DATA_SIZE]; |
685 | int ret; | |
686 | ||
687 | if ((crtc_state->infoframes.enable & | |
688 | intel_hdmi_infoframe_enable(type)) == 0) | |
689 | return; | |
690 | ||
7801f3b7 | 691 | dig_port->read_infoframe(encoder, crtc_state, |
f2a10d61 VS |
692 | type, buffer, sizeof(buffer)); |
693 | ||
694 | /* Fill the 'hole' (see big comment above) at position 3 */ | |
695 | memmove(&buffer[1], &buffer[0], 3); | |
696 | ||
697 | /* see comment above for the reason for this offset */ | |
698 | ret = hdmi_infoframe_unpack(frame, buffer + 1, sizeof(buffer) - 1); | |
699 | if (ret) { | |
7015f127 | 700 | drm_dbg_kms(encoder->base.dev, |
41919042 | 701 | "Failed to unpack infoframe type 0x%02x\n", type); |
f2a10d61 VS |
702 | return; |
703 | } | |
704 | ||
705 | if (frame->any.type != type) | |
7015f127 | 706 | drm_dbg_kms(encoder->base.dev, |
41919042 JN |
707 | "Found the wrong infoframe type 0x%x (expected 0x%02x)\n", |
708 | frame->any.type, type); | |
f2a10d61 VS |
709 | } |
710 | ||
fbf08556 VS |
711 | static bool |
712 | intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder, | |
713 | struct intel_crtc_state *crtc_state, | |
714 | struct drm_connector_state *conn_state) | |
45187ace | 715 | { |
fbf08556 | 716 | struct hdmi_avi_infoframe *frame = &crtc_state->infoframes.avi.avi; |
779c4c28 | 717 | const struct drm_display_mode *adjusted_mode = |
1326a92c | 718 | &crtc_state->hw.adjusted_mode; |
506f254e | 719 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
5adaea79 | 720 | int ret; |
45187ace | 721 | |
fbf08556 VS |
722 | if (!crtc_state->has_infoframe) |
723 | return true; | |
724 | ||
725 | crtc_state->infoframes.enable |= | |
726 | intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI); | |
727 | ||
506f254e | 728 | ret = drm_hdmi_avi_infoframe_from_display_mode(frame, &connector->base, |
13d0add3 | 729 | adjusted_mode); |
fbf08556 VS |
730 | if (ret) |
731 | return false; | |
c846b619 | 732 | |
33b7f3ee | 733 | if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420) |
fbf08556 | 734 | frame->colorspace = HDMI_COLORSPACE_YUV420; |
8c79f844 | 735 | else if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) |
fbf08556 | 736 | frame->colorspace = HDMI_COLORSPACE_YUV444; |
2d8bd2bf | 737 | else |
fbf08556 | 738 | frame->colorspace = HDMI_COLORSPACE_RGB; |
2d8bd2bf | 739 | |
4a46e5d2 | 740 | drm_hdmi_avi_infoframe_colorimetry(frame, conn_state); |
2d8bd2bf | 741 | |
cae154fc | 742 | /* nonsense combination */ |
3a47ae20 PB |
743 | drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && |
744 | crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB); | |
cae154fc | 745 | |
791ad5f1 | 746 | if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB) { |
506f254e | 747 | drm_hdmi_avi_infoframe_quant_range(frame, &connector->base, |
791ad5f1 VS |
748 | adjusted_mode, |
749 | crtc_state->limited_color_range ? | |
750 | HDMI_QUANTIZATION_RANGE_LIMITED : | |
751 | HDMI_QUANTIZATION_RANGE_FULL); | |
752 | } else { | |
753 | frame->quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; | |
754 | frame->ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; | |
755 | } | |
abedc077 | 756 | |
fbf08556 | 757 | drm_hdmi_avi_infoframe_content_type(frame, conn_state); |
6553b123 | 758 | |
2d8bd2bf | 759 | /* TODO: handle pixel repetition for YCBCR420 outputs */ |
fbf08556 VS |
760 | |
761 | ret = hdmi_avi_infoframe_check(frame); | |
3a47ae20 | 762 | if (drm_WARN_ON(encoder->base.dev, ret)) |
fbf08556 VS |
763 | return false; |
764 | ||
765 | return true; | |
b055c8f3 JB |
766 | } |
767 | ||
fbf08556 VS |
768 | static bool |
769 | intel_hdmi_compute_spd_infoframe(struct intel_encoder *encoder, | |
770 | struct intel_crtc_state *crtc_state, | |
771 | struct drm_connector_state *conn_state) | |
c0864cb3 | 772 | { |
4a3506d1 | 773 | struct intel_display *display = to_intel_display(crtc_state); |
fbf08556 | 774 | struct hdmi_spd_infoframe *frame = &crtc_state->infoframes.spd.spd; |
5adaea79 DL |
775 | int ret; |
776 | ||
fbf08556 VS |
777 | if (!crtc_state->has_infoframe) |
778 | return true; | |
c0864cb3 | 779 | |
fbf08556 VS |
780 | crtc_state->infoframes.enable |= |
781 | intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_SPD); | |
c0864cb3 | 782 | |
4a3506d1 | 783 | if (display->platform.dgfx) |
7d1675dc TC |
784 | ret = hdmi_spd_infoframe_init(frame, "Intel", "Discrete gfx"); |
785 | else | |
786 | ret = hdmi_spd_infoframe_init(frame, "Intel", "Integrated gfx"); | |
787 | ||
3a47ae20 | 788 | if (drm_WARN_ON(encoder->base.dev, ret)) |
fbf08556 VS |
789 | return false; |
790 | ||
791 | frame->sdi = HDMI_SPD_SDI_PC; | |
792 | ||
793 | ret = hdmi_spd_infoframe_check(frame); | |
3a47ae20 | 794 | if (drm_WARN_ON(encoder->base.dev, ret)) |
fbf08556 VS |
795 | return false; |
796 | ||
797 | return true; | |
c0864cb3 JB |
798 | } |
799 | ||
fbf08556 VS |
800 | static bool |
801 | intel_hdmi_compute_hdmi_infoframe(struct intel_encoder *encoder, | |
802 | struct intel_crtc_state *crtc_state, | |
803 | struct drm_connector_state *conn_state) | |
804 | { | |
805 | struct hdmi_vendor_infoframe *frame = | |
806 | &crtc_state->infoframes.hdmi.vendor.hdmi; | |
807 | const struct drm_display_info *info = | |
808 | &conn_state->connector->display_info; | |
c8bb75af LD |
809 | int ret; |
810 | ||
fbf08556 VS |
811 | if (!crtc_state->has_infoframe || !info->has_hdmi_infoframe) |
812 | return true; | |
813 | ||
814 | crtc_state->infoframes.enable |= | |
815 | intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_VENDOR); | |
816 | ||
817 | ret = drm_hdmi_vendor_infoframe_from_display_mode(frame, | |
f1781e9b | 818 | conn_state->connector, |
1326a92c | 819 | &crtc_state->hw.adjusted_mode); |
3a47ae20 | 820 | if (drm_WARN_ON(encoder->base.dev, ret)) |
fbf08556 | 821 | return false; |
c8bb75af | 822 | |
fbf08556 | 823 | ret = hdmi_vendor_infoframe_check(frame); |
3a47ae20 | 824 | if (drm_WARN_ON(encoder->base.dev, ret)) |
fbf08556 VS |
825 | return false; |
826 | ||
827 | return true; | |
c8bb75af LD |
828 | } |
829 | ||
5a0200f6 US |
830 | static bool |
831 | intel_hdmi_compute_drm_infoframe(struct intel_encoder *encoder, | |
832 | struct intel_crtc_state *crtc_state, | |
833 | struct drm_connector_state *conn_state) | |
834 | { | |
1138137c | 835 | struct intel_display *display = to_intel_display(encoder); |
5a0200f6 | 836 | struct hdmi_drm_infoframe *frame = &crtc_state->infoframes.drm.drm; |
5a0200f6 US |
837 | int ret; |
838 | ||
1138137c | 839 | if (DISPLAY_VER(display) < 10) |
5a0200f6 US |
840 | return true; |
841 | ||
842 | if (!crtc_state->has_infoframe) | |
843 | return true; | |
844 | ||
845 | if (!conn_state->hdr_output_metadata) | |
846 | return true; | |
847 | ||
848 | crtc_state->infoframes.enable |= | |
849 | intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_DRM); | |
850 | ||
851 | ret = drm_hdmi_infoframe_set_hdr_metadata(frame, conn_state); | |
852 | if (ret < 0) { | |
1138137c | 853 | drm_dbg_kms(display->drm, |
41919042 | 854 | "couldn't set HDR metadata in infoframe\n"); |
5a0200f6 US |
855 | return false; |
856 | } | |
857 | ||
858 | ret = hdmi_drm_infoframe_check(frame); | |
1138137c | 859 | if (drm_WARN_ON(display->drm, ret)) |
5a0200f6 US |
860 | return false; |
861 | ||
862 | return true; | |
863 | } | |
864 | ||
790ea70c | 865 | static void g4x_set_infoframes(struct intel_encoder *encoder, |
6897b4b5 | 866 | bool enable, |
ac240288 ML |
867 | const struct intel_crtc_state *crtc_state, |
868 | const struct drm_connector_state *conn_state) | |
687f4d06 | 869 | { |
1138137c | 870 | struct intel_display *display = to_intel_display(encoder); |
7801f3b7 LDM |
871 | struct intel_digital_port *dig_port = enc_to_dig_port(encoder); |
872 | struct intel_hdmi *intel_hdmi = &dig_port->hdmi; | |
f0f59a00 | 873 | i915_reg_t reg = VIDEO_DIP_CTL; |
1138137c | 874 | u32 val = intel_de_read(display, reg); |
790ea70c | 875 | u32 port = VIDEO_DIP_PORT(encoder->port); |
0c14c7f9 | 876 | |
afba0188 DV |
877 | assert_hdmi_port_disabled(intel_hdmi); |
878 | ||
0c14c7f9 PZ |
879 | /* If the registers were not initialized yet, they might be zeroes, |
880 | * which means we're selecting the AVI DIP and we're setting its | |
881 | * frequency to once. This seems to really confuse the HW and make | |
882 | * things stop working (the register spec says the AVI always needs to | |
883 | * be sent every VSync). So here we avoid writing to the register more | |
884 | * than we need and also explicitly select the AVI DIP and explicitly | |
885 | * set its frequency to every VSync. Avoiding to write it twice seems to | |
886 | * be enough to solve the problem, but being defensive shouldn't hurt us | |
887 | * either. */ | |
888 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; | |
889 | ||
6897b4b5 | 890 | if (!enable) { |
0c14c7f9 PZ |
891 | if (!(val & VIDEO_DIP_ENABLE)) |
892 | return; | |
0be6f0c8 | 893 | if (port != (val & VIDEO_DIP_PORT_MASK)) { |
1138137c | 894 | drm_dbg_kms(display->drm, |
41919042 JN |
895 | "video DIP still enabled on port %c\n", |
896 | (val & VIDEO_DIP_PORT_MASK) >> 29); | |
0be6f0c8 VS |
897 | return; |
898 | } | |
899 | val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | | |
900 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); | |
1138137c JN |
901 | intel_de_write(display, reg, val); |
902 | intel_de_posting_read(display, reg); | |
0c14c7f9 PZ |
903 | return; |
904 | } | |
905 | ||
72b78c9d PZ |
906 | if (port != (val & VIDEO_DIP_PORT_MASK)) { |
907 | if (val & VIDEO_DIP_ENABLE) { | |
1138137c | 908 | drm_dbg_kms(display->drm, |
41919042 JN |
909 | "video DIP already enabled on port %c\n", |
910 | (val & VIDEO_DIP_PORT_MASK) >> 29); | |
0be6f0c8 | 911 | return; |
72b78c9d PZ |
912 | } |
913 | val &= ~VIDEO_DIP_PORT_MASK; | |
914 | val |= port; | |
915 | } | |
916 | ||
822974ae | 917 | val |= VIDEO_DIP_ENABLE; |
0be6f0c8 VS |
918 | val &= ~(VIDEO_DIP_ENABLE_AVI | |
919 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); | |
822974ae | 920 | |
1138137c JN |
921 | intel_de_write(display, reg, val); |
922 | intel_de_posting_read(display, reg); | |
f278d972 | 923 | |
fbf08556 VS |
924 | intel_write_infoframe(encoder, crtc_state, |
925 | HDMI_INFOFRAME_TYPE_AVI, | |
926 | &crtc_state->infoframes.avi); | |
927 | intel_write_infoframe(encoder, crtc_state, | |
928 | HDMI_INFOFRAME_TYPE_SPD, | |
929 | &crtc_state->infoframes.spd); | |
930 | intel_write_infoframe(encoder, crtc_state, | |
931 | HDMI_INFOFRAME_TYPE_VENDOR, | |
932 | &crtc_state->infoframes.hdmi); | |
687f4d06 PZ |
933 | } |
934 | ||
12aa3290 VS |
935 | /* |
936 | * Determine if default_phase=1 can be indicated in the GCP infoframe. | |
937 | * | |
938 | * From HDMI specification 1.4a: | |
939 | * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0 | |
940 | * - The first pixel following each Video Data Period shall have a pixel packing phase of 0 | |
941 | * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase | |
942 | * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing | |
943 | * phase of 0 | |
944 | */ | |
945 | static bool gcp_default_phase_possible(int pipe_bpp, | |
946 | const struct drm_display_mode *mode) | |
947 | { | |
948 | unsigned int pixels_per_group; | |
949 | ||
950 | switch (pipe_bpp) { | |
951 | case 30: | |
952 | /* 4 pixels in 5 clocks */ | |
953 | pixels_per_group = 4; | |
954 | break; | |
955 | case 36: | |
956 | /* 2 pixels in 3 clocks */ | |
957 | pixels_per_group = 2; | |
958 | break; | |
959 | case 48: | |
960 | /* 1 pixel in 2 clocks */ | |
961 | pixels_per_group = 1; | |
962 | break; | |
963 | default: | |
964 | /* phase information not relevant for 8bpc */ | |
965 | return false; | |
966 | } | |
967 | ||
968 | return mode->crtc_hdisplay % pixels_per_group == 0 && | |
969 | mode->crtc_htotal % pixels_per_group == 0 && | |
970 | mode->crtc_hblank_start % pixels_per_group == 0 && | |
971 | mode->crtc_hblank_end % pixels_per_group == 0 && | |
972 | mode->crtc_hsync_start % pixels_per_group == 0 && | |
973 | mode->crtc_hsync_end % pixels_per_group == 0 && | |
974 | ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 || | |
975 | mode->crtc_htotal/2 % pixels_per_group == 0); | |
976 | } | |
977 | ||
790ea70c | 978 | static bool intel_hdmi_set_gcp_infoframe(struct intel_encoder *encoder, |
ac240288 ML |
979 | const struct intel_crtc_state *crtc_state, |
980 | const struct drm_connector_state *conn_state) | |
6d67415f | 981 | { |
1138137c | 982 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 983 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
f0f59a00 | 984 | i915_reg_t reg; |
fbf08556 VS |
985 | |
986 | if ((crtc_state->infoframes.enable & | |
987 | intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0) | |
988 | return false; | |
6d67415f | 989 | |
1138137c JN |
990 | if (HAS_DDI(display)) |
991 | reg = HSW_TVIDEO_DIP_GCP(display, crtc_state->cpu_transcoder); | |
4a3506d1 | 992 | else if (display->platform.valleyview || display->platform.cherryview) |
6d67415f | 993 | reg = VLV_TVIDEO_DIP_GCP(crtc->pipe); |
4e9b0ac1 | 994 | else if (HAS_PCH_SPLIT(display)) |
6d67415f VS |
995 | reg = TVIDEO_DIP_GCP(crtc->pipe); |
996 | else | |
997 | return false; | |
998 | ||
1138137c | 999 | intel_de_write(display, reg, crtc_state->infoframes.gcp); |
fbf08556 VS |
1000 | |
1001 | return true; | |
1002 | } | |
1003 | ||
f2a10d61 VS |
1004 | void intel_hdmi_read_gcp_infoframe(struct intel_encoder *encoder, |
1005 | struct intel_crtc_state *crtc_state) | |
1006 | { | |
1138137c | 1007 | struct intel_display *display = to_intel_display(encoder); |
2225f3c6 | 1008 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
f2a10d61 VS |
1009 | i915_reg_t reg; |
1010 | ||
1011 | if ((crtc_state->infoframes.enable & | |
1012 | intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL)) == 0) | |
1013 | return; | |
1014 | ||
1138137c JN |
1015 | if (HAS_DDI(display)) |
1016 | reg = HSW_TVIDEO_DIP_GCP(display, crtc_state->cpu_transcoder); | |
4a3506d1 | 1017 | else if (display->platform.valleyview || display->platform.cherryview) |
f2a10d61 | 1018 | reg = VLV_TVIDEO_DIP_GCP(crtc->pipe); |
4e9b0ac1 | 1019 | else if (HAS_PCH_SPLIT(display)) |
f2a10d61 VS |
1020 | reg = TVIDEO_DIP_GCP(crtc->pipe); |
1021 | else | |
1022 | return; | |
1023 | ||
1138137c | 1024 | crtc_state->infoframes.gcp = intel_de_read(display, reg); |
f2a10d61 VS |
1025 | } |
1026 | ||
fbf08556 VS |
1027 | static void intel_hdmi_compute_gcp_infoframe(struct intel_encoder *encoder, |
1028 | struct intel_crtc_state *crtc_state, | |
1029 | struct drm_connector_state *conn_state) | |
1030 | { | |
4a3506d1 | 1031 | struct intel_display *display = to_intel_display(encoder); |
fbf08556 | 1032 | |
4a3506d1 | 1033 | if (display->platform.g4x || !crtc_state->has_infoframe) |
fbf08556 VS |
1034 | return; |
1035 | ||
1036 | crtc_state->infoframes.enable |= | |
1037 | intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GENERAL_CONTROL); | |
1038 | ||
05d9c878 CT |
1039 | /* Indicate color indication for deep color mode */ |
1040 | if (crtc_state->pipe_bpp > 24) | |
fbf08556 | 1041 | crtc_state->infoframes.gcp |= GCP_COLOR_INDICATION; |
6d67415f | 1042 | |
12aa3290 | 1043 | /* Enable default_phase whenever the display mode is suitably aligned */ |
ac240288 | 1044 | if (gcp_default_phase_possible(crtc_state->pipe_bpp, |
1326a92c | 1045 | &crtc_state->hw.adjusted_mode)) |
fbf08556 | 1046 | crtc_state->infoframes.gcp |= GCP_DEFAULT_PHASE_ENABLE; |
6d67415f VS |
1047 | } |
1048 | ||
790ea70c | 1049 | static void ibx_set_infoframes(struct intel_encoder *encoder, |
6897b4b5 | 1050 | bool enable, |
ac240288 ML |
1051 | const struct intel_crtc_state *crtc_state, |
1052 | const struct drm_connector_state *conn_state) | |
687f4d06 | 1053 | { |
1138137c | 1054 | struct intel_display *display = to_intel_display(encoder); |
f15f01a7 | 1055 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
7801f3b7 LDM |
1056 | struct intel_digital_port *dig_port = enc_to_dig_port(encoder); |
1057 | struct intel_hdmi *intel_hdmi = &dig_port->hdmi; | |
f15f01a7 | 1058 | i915_reg_t reg = TVIDEO_DIP_CTL(crtc->pipe); |
1138137c | 1059 | u32 val = intel_de_read(display, reg); |
790ea70c | 1060 | u32 port = VIDEO_DIP_PORT(encoder->port); |
0c14c7f9 | 1061 | |
afba0188 DV |
1062 | assert_hdmi_port_disabled(intel_hdmi); |
1063 | ||
0c14c7f9 PZ |
1064 | /* See the big comment in g4x_set_infoframes() */ |
1065 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; | |
1066 | ||
6897b4b5 | 1067 | if (!enable) { |
0c14c7f9 PZ |
1068 | if (!(val & VIDEO_DIP_ENABLE)) |
1069 | return; | |
0be6f0c8 VS |
1070 | val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | |
1071 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
1072 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
1138137c JN |
1073 | intel_de_write(display, reg, val); |
1074 | intel_de_posting_read(display, reg); | |
0c14c7f9 PZ |
1075 | return; |
1076 | } | |
1077 | ||
72b78c9d | 1078 | if (port != (val & VIDEO_DIP_PORT_MASK)) { |
1138137c | 1079 | drm_WARN(display->drm, val & VIDEO_DIP_ENABLE, |
10d4e146 PB |
1080 | "DIP already enabled on port %c\n", |
1081 | (val & VIDEO_DIP_PORT_MASK) >> 29); | |
72b78c9d PZ |
1082 | val &= ~VIDEO_DIP_PORT_MASK; |
1083 | val |= port; | |
1084 | } | |
1085 | ||
822974ae | 1086 | val |= VIDEO_DIP_ENABLE; |
0be6f0c8 VS |
1087 | val &= ~(VIDEO_DIP_ENABLE_AVI | |
1088 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
1089 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
822974ae | 1090 | |
ac240288 | 1091 | if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state)) |
6d67415f VS |
1092 | val |= VIDEO_DIP_ENABLE_GCP; |
1093 | ||
1138137c JN |
1094 | intel_de_write(display, reg, val); |
1095 | intel_de_posting_read(display, reg); | |
f278d972 | 1096 | |
fbf08556 VS |
1097 | intel_write_infoframe(encoder, crtc_state, |
1098 | HDMI_INFOFRAME_TYPE_AVI, | |
1099 | &crtc_state->infoframes.avi); | |
1100 | intel_write_infoframe(encoder, crtc_state, | |
1101 | HDMI_INFOFRAME_TYPE_SPD, | |
1102 | &crtc_state->infoframes.spd); | |
1103 | intel_write_infoframe(encoder, crtc_state, | |
1104 | HDMI_INFOFRAME_TYPE_VENDOR, | |
1105 | &crtc_state->infoframes.hdmi); | |
687f4d06 PZ |
1106 | } |
1107 | ||
790ea70c | 1108 | static void cpt_set_infoframes(struct intel_encoder *encoder, |
6897b4b5 | 1109 | bool enable, |
ac240288 ML |
1110 | const struct intel_crtc_state *crtc_state, |
1111 | const struct drm_connector_state *conn_state) | |
687f4d06 | 1112 | { |
1138137c | 1113 | struct intel_display *display = to_intel_display(encoder); |
f15f01a7 | 1114 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
b7d02c3a | 1115 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
f15f01a7 | 1116 | i915_reg_t reg = TVIDEO_DIP_CTL(crtc->pipe); |
1138137c | 1117 | u32 val = intel_de_read(display, reg); |
0c14c7f9 | 1118 | |
afba0188 DV |
1119 | assert_hdmi_port_disabled(intel_hdmi); |
1120 | ||
0c14c7f9 PZ |
1121 | /* See the big comment in g4x_set_infoframes() */ |
1122 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; | |
1123 | ||
6897b4b5 | 1124 | if (!enable) { |
0c14c7f9 PZ |
1125 | if (!(val & VIDEO_DIP_ENABLE)) |
1126 | return; | |
0be6f0c8 VS |
1127 | val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | |
1128 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
1129 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
1138137c JN |
1130 | intel_de_write(display, reg, val); |
1131 | intel_de_posting_read(display, reg); | |
0c14c7f9 PZ |
1132 | return; |
1133 | } | |
1134 | ||
822974ae PZ |
1135 | /* Set both together, unset both together: see the spec. */ |
1136 | val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI; | |
0dd87d20 | 1137 | val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | |
0be6f0c8 | 1138 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); |
822974ae | 1139 | |
ac240288 | 1140 | if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state)) |
6d67415f VS |
1141 | val |= VIDEO_DIP_ENABLE_GCP; |
1142 | ||
1138137c JN |
1143 | intel_de_write(display, reg, val); |
1144 | intel_de_posting_read(display, reg); | |
822974ae | 1145 | |
fbf08556 VS |
1146 | intel_write_infoframe(encoder, crtc_state, |
1147 | HDMI_INFOFRAME_TYPE_AVI, | |
1148 | &crtc_state->infoframes.avi); | |
1149 | intel_write_infoframe(encoder, crtc_state, | |
1150 | HDMI_INFOFRAME_TYPE_SPD, | |
1151 | &crtc_state->infoframes.spd); | |
1152 | intel_write_infoframe(encoder, crtc_state, | |
1153 | HDMI_INFOFRAME_TYPE_VENDOR, | |
1154 | &crtc_state->infoframes.hdmi); | |
687f4d06 PZ |
1155 | } |
1156 | ||
790ea70c | 1157 | static void vlv_set_infoframes(struct intel_encoder *encoder, |
6897b4b5 | 1158 | bool enable, |
ac240288 ML |
1159 | const struct intel_crtc_state *crtc_state, |
1160 | const struct drm_connector_state *conn_state) | |
687f4d06 | 1161 | { |
1138137c | 1162 | struct intel_display *display = to_intel_display(encoder); |
f15f01a7 | 1163 | struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); |
b7d02c3a | 1164 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
f15f01a7 | 1165 | i915_reg_t reg = VLV_TVIDEO_DIP_CTL(crtc->pipe); |
1138137c | 1166 | u32 val = intel_de_read(display, reg); |
790ea70c | 1167 | u32 port = VIDEO_DIP_PORT(encoder->port); |
0c14c7f9 | 1168 | |
afba0188 DV |
1169 | assert_hdmi_port_disabled(intel_hdmi); |
1170 | ||
0c14c7f9 PZ |
1171 | /* See the big comment in g4x_set_infoframes() */ |
1172 | val |= VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC; | |
1173 | ||
6897b4b5 | 1174 | if (!enable) { |
0c14c7f9 PZ |
1175 | if (!(val & VIDEO_DIP_ENABLE)) |
1176 | return; | |
0be6f0c8 VS |
1177 | val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | |
1178 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
1179 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
1138137c JN |
1180 | intel_de_write(display, reg, val); |
1181 | intel_de_posting_read(display, reg); | |
0c14c7f9 PZ |
1182 | return; |
1183 | } | |
1184 | ||
6a2b8021 | 1185 | if (port != (val & VIDEO_DIP_PORT_MASK)) { |
1138137c | 1186 | drm_WARN(display->drm, val & VIDEO_DIP_ENABLE, |
10d4e146 PB |
1187 | "DIP already enabled on port %c\n", |
1188 | (val & VIDEO_DIP_PORT_MASK) >> 29); | |
6a2b8021 JB |
1189 | val &= ~VIDEO_DIP_PORT_MASK; |
1190 | val |= port; | |
1191 | } | |
1192 | ||
822974ae | 1193 | val |= VIDEO_DIP_ENABLE; |
0be6f0c8 VS |
1194 | val &= ~(VIDEO_DIP_ENABLE_AVI | |
1195 | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | | |
1196 | VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); | |
822974ae | 1197 | |
ac240288 | 1198 | if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state)) |
6d67415f VS |
1199 | val |= VIDEO_DIP_ENABLE_GCP; |
1200 | ||
1138137c JN |
1201 | intel_de_write(display, reg, val); |
1202 | intel_de_posting_read(display, reg); | |
822974ae | 1203 | |
fbf08556 VS |
1204 | intel_write_infoframe(encoder, crtc_state, |
1205 | HDMI_INFOFRAME_TYPE_AVI, | |
1206 | &crtc_state->infoframes.avi); | |
1207 | intel_write_infoframe(encoder, crtc_state, | |
1208 | HDMI_INFOFRAME_TYPE_SPD, | |
1209 | &crtc_state->infoframes.spd); | |
1210 | intel_write_infoframe(encoder, crtc_state, | |
1211 | HDMI_INFOFRAME_TYPE_VENDOR, | |
1212 | &crtc_state->infoframes.hdmi); | |
687f4d06 PZ |
1213 | } |
1214 | ||
82ab75c4 CKB |
1215 | void intel_hdmi_fastset_infoframes(struct intel_encoder *encoder, |
1216 | const struct intel_crtc_state *crtc_state, | |
1217 | const struct drm_connector_state *conn_state) | |
1218 | { | |
1219 | struct intel_display *display = to_intel_display(encoder); | |
1220 | i915_reg_t reg = HSW_TVIDEO_DIP_CTL(display, | |
1221 | crtc_state->cpu_transcoder); | |
1222 | u32 val = intel_de_read(display, reg); | |
1223 | ||
1224 | if ((crtc_state->infoframes.enable & | |
1225 | intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_DRM)) == 0 && | |
1226 | (val & VIDEO_DIP_ENABLE_DRM_GLK) == 0) | |
1227 | return; | |
1228 | ||
1229 | val &= ~(VIDEO_DIP_ENABLE_DRM_GLK); | |
1230 | ||
1231 | intel_de_write(display, reg, val); | |
1232 | intel_de_posting_read(display, reg); | |
1233 | ||
1234 | intel_write_infoframe(encoder, crtc_state, | |
1235 | HDMI_INFOFRAME_TYPE_DRM, | |
1236 | &crtc_state->infoframes.drm); | |
1237 | } | |
1238 | ||
790ea70c | 1239 | static void hsw_set_infoframes(struct intel_encoder *encoder, |
6897b4b5 | 1240 | bool enable, |
ac240288 ML |
1241 | const struct intel_crtc_state *crtc_state, |
1242 | const struct drm_connector_state *conn_state) | |
687f4d06 | 1243 | { |
1138137c JN |
1244 | struct intel_display *display = to_intel_display(encoder); |
1245 | i915_reg_t reg = HSW_TVIDEO_DIP_CTL(display, | |
cc13f293 | 1246 | crtc_state->cpu_transcoder); |
1138137c | 1247 | u32 val = intel_de_read(display, reg); |
0c14c7f9 | 1248 | |
1138137c | 1249 | assert_hdmi_transcoder_func_disabled(display, |
8fc0aa6e | 1250 | crtc_state->cpu_transcoder); |
afba0188 | 1251 | |
0be6f0c8 VS |
1252 | val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | |
1253 | VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | | |
44b42ebf | 1254 | VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW | |
12ea8929 | 1255 | VIDEO_DIP_ENABLE_DRM_GLK | VIDEO_DIP_ENABLE_AS_ADL); |
0be6f0c8 | 1256 | |
6897b4b5 | 1257 | if (!enable) { |
1138137c JN |
1258 | intel_de_write(display, reg, val); |
1259 | intel_de_posting_read(display, reg); | |
0c14c7f9 PZ |
1260 | return; |
1261 | } | |
1262 | ||
ac240288 | 1263 | if (intel_hdmi_set_gcp_infoframe(encoder, crtc_state, conn_state)) |
6d67415f VS |
1264 | val |= VIDEO_DIP_ENABLE_GCP_HSW; |
1265 | ||
1138137c JN |
1266 | intel_de_write(display, reg, val); |
1267 | intel_de_posting_read(display, reg); | |
0dd87d20 | 1268 | |
fbf08556 VS |
1269 | intel_write_infoframe(encoder, crtc_state, |
1270 | HDMI_INFOFRAME_TYPE_AVI, | |
1271 | &crtc_state->infoframes.avi); | |
1272 | intel_write_infoframe(encoder, crtc_state, | |
1273 | HDMI_INFOFRAME_TYPE_SPD, | |
1274 | &crtc_state->infoframes.spd); | |
1275 | intel_write_infoframe(encoder, crtc_state, | |
1276 | HDMI_INFOFRAME_TYPE_VENDOR, | |
1277 | &crtc_state->infoframes.hdmi); | |
5a0200f6 US |
1278 | intel_write_infoframe(encoder, crtc_state, |
1279 | HDMI_INFOFRAME_TYPE_DRM, | |
1280 | &crtc_state->infoframes.drm); | |
687f4d06 PZ |
1281 | } |
1282 | ||
b2ccb822 VS |
1283 | void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable) |
1284 | { | |
1138137c | 1285 | struct intel_display *display = to_intel_display(hdmi); |
e046d156 | 1286 | struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; |
b2ccb822 VS |
1287 | |
1288 | if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI) | |
1289 | return; | |
1290 | ||
1138137c | 1291 | drm_dbg_kms(display->drm, "%s DP dual mode adaptor TMDS output\n", |
41919042 | 1292 | enable ? "Enabling" : "Disabling"); |
b2ccb822 | 1293 | |
1138137c | 1294 | drm_dp_dual_mode_set_tmds_output(display->drm, |
30b98ecb | 1295 | hdmi->dp_dual_mode.type, ddc, enable); |
b2ccb822 VS |
1296 | } |
1297 | ||
7801f3b7 | 1298 | static int intel_hdmi_hdcp_read(struct intel_digital_port *dig_port, |
2320175f SP |
1299 | unsigned int offset, void *buffer, size_t size) |
1300 | { | |
7801f3b7 | 1301 | struct intel_hdmi *hdmi = &dig_port->hdmi; |
e046d156 | 1302 | struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; |
2320175f SP |
1303 | int ret; |
1304 | u8 start = offset & 0xff; | |
1305 | struct i2c_msg msgs[] = { | |
1306 | { | |
1307 | .addr = DRM_HDCP_DDC_ADDR, | |
1308 | .flags = 0, | |
1309 | .len = 1, | |
1310 | .buf = &start, | |
1311 | }, | |
1312 | { | |
1313 | .addr = DRM_HDCP_DDC_ADDR, | |
1314 | .flags = I2C_M_RD, | |
1315 | .len = size, | |
1316 | .buf = buffer | |
1317 | } | |
1318 | }; | |
30b98ecb | 1319 | ret = i2c_transfer(ddc, msgs, ARRAY_SIZE(msgs)); |
2320175f SP |
1320 | if (ret == ARRAY_SIZE(msgs)) |
1321 | return 0; | |
1322 | return ret >= 0 ? -EIO : ret; | |
1323 | } | |
1324 | ||
7801f3b7 | 1325 | static int intel_hdmi_hdcp_write(struct intel_digital_port *dig_port, |
2320175f SP |
1326 | unsigned int offset, void *buffer, size_t size) |
1327 | { | |
7801f3b7 | 1328 | struct intel_hdmi *hdmi = &dig_port->hdmi; |
e046d156 | 1329 | struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; |
2320175f SP |
1330 | int ret; |
1331 | u8 *write_buf; | |
1332 | struct i2c_msg msg; | |
1333 | ||
1334 | write_buf = kzalloc(size + 1, GFP_KERNEL); | |
1335 | if (!write_buf) | |
1336 | return -ENOMEM; | |
1337 | ||
1338 | write_buf[0] = offset & 0xff; | |
1339 | memcpy(&write_buf[1], buffer, size); | |
1340 | ||
1341 | msg.addr = DRM_HDCP_DDC_ADDR; | |
7cd1049a CN |
1342 | msg.flags = 0; |
1343 | msg.len = size + 1; | |
2320175f SP |
1344 | msg.buf = write_buf; |
1345 | ||
30b98ecb | 1346 | ret = i2c_transfer(ddc, &msg, 1); |
2320175f | 1347 | if (ret == 1) |
1b1b1162 RV |
1348 | ret = 0; |
1349 | else if (ret >= 0) | |
1350 | ret = -EIO; | |
1351 | ||
1352 | kfree(write_buf); | |
1353 | return ret; | |
2320175f SP |
1354 | } |
1355 | ||
1356 | static | |
7801f3b7 | 1357 | int intel_hdmi_hdcp_write_an_aksv(struct intel_digital_port *dig_port, |
2320175f SP |
1358 | u8 *an) |
1359 | { | |
1138137c | 1360 | struct intel_display *display = to_intel_display(dig_port); |
7801f3b7 | 1361 | struct intel_hdmi *hdmi = &dig_port->hdmi; |
e046d156 | 1362 | struct i2c_adapter *ddc = hdmi->attached_connector->base.ddc; |
2320175f SP |
1363 | int ret; |
1364 | ||
7801f3b7 | 1365 | ret = intel_hdmi_hdcp_write(dig_port, DRM_HDCP_DDC_AN, an, |
2320175f SP |
1366 | DRM_HDCP_AN_LEN); |
1367 | if (ret) { | |
1138137c | 1368 | drm_dbg_kms(display->drm, "Write An over DDC failed (%d)\n", |
41919042 | 1369 | ret); |
2320175f SP |
1370 | return ret; |
1371 | } | |
1372 | ||
30b98ecb | 1373 | ret = intel_gmbus_output_aksv(ddc); |
2320175f | 1374 | if (ret < 0) { |
1138137c | 1375 | drm_dbg_kms(display->drm, "Failed to output aksv (%d)\n", ret); |
2320175f SP |
1376 | return ret; |
1377 | } | |
1378 | return 0; | |
1379 | } | |
1380 | ||
7801f3b7 | 1381 | static int intel_hdmi_hdcp_read_bksv(struct intel_digital_port *dig_port, |
2320175f SP |
1382 | u8 *bksv) |
1383 | { | |
1138137c | 1384 | struct intel_display *display = to_intel_display(dig_port); |
41919042 | 1385 | |
2320175f | 1386 | int ret; |
7801f3b7 | 1387 | ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BKSV, bksv, |
2320175f SP |
1388 | DRM_HDCP_KSV_LEN); |
1389 | if (ret) | |
1138137c | 1390 | drm_dbg_kms(display->drm, "Read Bksv over DDC failed (%d)\n", |
41919042 | 1391 | ret); |
2320175f SP |
1392 | return ret; |
1393 | } | |
1394 | ||
1395 | static | |
7801f3b7 | 1396 | int intel_hdmi_hdcp_read_bstatus(struct intel_digital_port *dig_port, |
2320175f SP |
1397 | u8 *bstatus) |
1398 | { | |
1138137c | 1399 | struct intel_display *display = to_intel_display(dig_port); |
41919042 | 1400 | |
2320175f | 1401 | int ret; |
7801f3b7 | 1402 | ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BSTATUS, |
2320175f SP |
1403 | bstatus, DRM_HDCP_BSTATUS_LEN); |
1404 | if (ret) | |
1138137c JN |
1405 | drm_dbg_kms(display->drm, |
1406 | "Read bstatus over DDC failed (%d)\n", | |
41919042 | 1407 | ret); |
2320175f SP |
1408 | return ret; |
1409 | } | |
1410 | ||
1411 | static | |
7801f3b7 | 1412 | int intel_hdmi_hdcp_repeater_present(struct intel_digital_port *dig_port, |
2320175f SP |
1413 | bool *repeater_present) |
1414 | { | |
1138137c | 1415 | struct intel_display *display = to_intel_display(dig_port); |
2320175f SP |
1416 | int ret; |
1417 | u8 val; | |
1418 | ||
7801f3b7 | 1419 | ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1); |
2320175f | 1420 | if (ret) { |
1138137c | 1421 | drm_dbg_kms(display->drm, "Read bcaps over DDC failed (%d)\n", |
41919042 | 1422 | ret); |
2320175f SP |
1423 | return ret; |
1424 | } | |
1425 | *repeater_present = val & DRM_HDCP_DDC_BCAPS_REPEATER_PRESENT; | |
1426 | return 0; | |
1427 | } | |
1428 | ||
1429 | static | |
7801f3b7 | 1430 | int intel_hdmi_hdcp_read_ri_prime(struct intel_digital_port *dig_port, |
2320175f SP |
1431 | u8 *ri_prime) |
1432 | { | |
1138137c | 1433 | struct intel_display *display = to_intel_display(dig_port); |
41919042 | 1434 | |
2320175f | 1435 | int ret; |
7801f3b7 | 1436 | ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_RI_PRIME, |
2320175f SP |
1437 | ri_prime, DRM_HDCP_RI_LEN); |
1438 | if (ret) | |
1138137c | 1439 | drm_dbg_kms(display->drm, "Read Ri' over DDC failed (%d)\n", |
41919042 | 1440 | ret); |
2320175f SP |
1441 | return ret; |
1442 | } | |
1443 | ||
1444 | static | |
7801f3b7 | 1445 | int intel_hdmi_hdcp_read_ksv_ready(struct intel_digital_port *dig_port, |
2320175f SP |
1446 | bool *ksv_ready) |
1447 | { | |
1138137c | 1448 | struct intel_display *display = to_intel_display(dig_port); |
2320175f SP |
1449 | int ret; |
1450 | u8 val; | |
1451 | ||
7801f3b7 | 1452 | ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_BCAPS, &val, 1); |
2320175f | 1453 | if (ret) { |
1138137c | 1454 | drm_dbg_kms(display->drm, "Read bcaps over DDC failed (%d)\n", |
41919042 | 1455 | ret); |
2320175f SP |
1456 | return ret; |
1457 | } | |
1458 | *ksv_ready = val & DRM_HDCP_DDC_BCAPS_KSV_FIFO_READY; | |
1459 | return 0; | |
1460 | } | |
1461 | ||
1462 | static | |
7801f3b7 | 1463 | int intel_hdmi_hdcp_read_ksv_fifo(struct intel_digital_port *dig_port, |
2320175f SP |
1464 | int num_downstream, u8 *ksv_fifo) |
1465 | { | |
1138137c | 1466 | struct intel_display *display = to_intel_display(dig_port); |
2320175f | 1467 | int ret; |
7801f3b7 | 1468 | ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_KSV_FIFO, |
2320175f SP |
1469 | ksv_fifo, num_downstream * DRM_HDCP_KSV_LEN); |
1470 | if (ret) { | |
1138137c | 1471 | drm_dbg_kms(display->drm, |
41919042 | 1472 | "Read ksv fifo over DDC failed (%d)\n", ret); |
2320175f SP |
1473 | return ret; |
1474 | } | |
1475 | return 0; | |
1476 | } | |
1477 | ||
1478 | static | |
7801f3b7 | 1479 | int intel_hdmi_hdcp_read_v_prime_part(struct intel_digital_port *dig_port, |
2320175f SP |
1480 | int i, u32 *part) |
1481 | { | |
1138137c | 1482 | struct intel_display *display = to_intel_display(dig_port); |
2320175f SP |
1483 | int ret; |
1484 | ||
1485 | if (i >= DRM_HDCP_V_PRIME_NUM_PARTS) | |
1486 | return -EINVAL; | |
1487 | ||
7801f3b7 | 1488 | ret = intel_hdmi_hdcp_read(dig_port, DRM_HDCP_DDC_V_PRIME(i), |
2320175f SP |
1489 | part, DRM_HDCP_V_PRIME_PART_LEN); |
1490 | if (ret) | |
1138137c JN |
1491 | drm_dbg_kms(display->drm, |
1492 | "Read V'[%d] over DDC failed (%d)\n", | |
41919042 | 1493 | i, ret); |
2320175f SP |
1494 | return ret; |
1495 | } | |
1496 | ||
0b9c9290 SP |
1497 | static int kbl_repositioning_enc_en_signal(struct intel_connector *connector, |
1498 | enum transcoder cpu_transcoder) | |
7412826c | 1499 | { |
1138137c | 1500 | struct intel_display *display = to_intel_display(connector); |
7801f3b7 | 1501 | struct intel_digital_port *dig_port = intel_attached_dig_port(connector); |
f15f01a7 | 1502 | struct intel_crtc *crtc = to_intel_crtc(connector->base.state->crtc); |
7412826c R |
1503 | u32 scanline; |
1504 | int ret; | |
1505 | ||
1506 | for (;;) { | |
1138137c JN |
1507 | scanline = intel_de_read(display, |
1508 | PIPEDSL(display, crtc->pipe)); | |
7412826c R |
1509 | if (scanline > 100 && scanline < 200) |
1510 | break; | |
1511 | usleep_range(25, 50); | |
1512 | } | |
1513 | ||
1a67a168 AG |
1514 | ret = intel_ddi_toggle_hdcp_bits(&dig_port->base, cpu_transcoder, |
1515 | false, TRANS_DDI_HDCP_SIGNALLING); | |
7412826c | 1516 | if (ret) { |
1138137c | 1517 | drm_err(display->drm, |
41919042 | 1518 | "Disable HDCP signalling failed (%d)\n", ret); |
7412826c R |
1519 | return ret; |
1520 | } | |
1a67a168 AG |
1521 | |
1522 | ret = intel_ddi_toggle_hdcp_bits(&dig_port->base, cpu_transcoder, | |
1523 | true, TRANS_DDI_HDCP_SIGNALLING); | |
7412826c | 1524 | if (ret) { |
1138137c | 1525 | drm_err(display->drm, |
41919042 | 1526 | "Enable HDCP signalling failed (%d)\n", ret); |
7412826c R |
1527 | return ret; |
1528 | } | |
1529 | ||
1530 | return 0; | |
1531 | } | |
1532 | ||
2320175f | 1533 | static |
7801f3b7 | 1534 | int intel_hdmi_hdcp_toggle_signalling(struct intel_digital_port *dig_port, |
0b9c9290 | 1535 | enum transcoder cpu_transcoder, |
2320175f SP |
1536 | bool enable) |
1537 | { | |
1138137c | 1538 | struct intel_display *display = to_intel_display(dig_port); |
7801f3b7 | 1539 | struct intel_hdmi *hdmi = &dig_port->hdmi; |
7412826c | 1540 | struct intel_connector *connector = hdmi->attached_connector; |
2320175f SP |
1541 | int ret; |
1542 | ||
1543 | if (!enable) | |
1544 | usleep_range(6, 60); /* Bspec says >= 6us */ | |
1545 | ||
1a67a168 AG |
1546 | ret = intel_ddi_toggle_hdcp_bits(&dig_port->base, |
1547 | cpu_transcoder, enable, | |
1548 | TRANS_DDI_HDCP_SIGNALLING); | |
2320175f | 1549 | if (ret) { |
1138137c | 1550 | drm_err(display->drm, "%s HDCP signalling failed (%d)\n", |
41919042 | 1551 | enable ? "Enable" : "Disable", ret); |
2320175f SP |
1552 | return ret; |
1553 | } | |
7412826c R |
1554 | |
1555 | /* | |
1556 | * WA: To fix incorrect positioning of the window of | |
1557 | * opportunity and enc_en signalling in KABYLAKE. | |
1558 | */ | |
4a3506d1 | 1559 | if (display->platform.kabylake && enable) |
0b9c9290 SP |
1560 | return kbl_repositioning_enc_en_signal(connector, |
1561 | cpu_transcoder); | |
7412826c | 1562 | |
2320175f SP |
1563 | return 0; |
1564 | } | |
1565 | ||
1566 | static | |
038bac89 SP |
1567 | bool intel_hdmi_hdcp_check_link_once(struct intel_digital_port *dig_port, |
1568 | struct intel_connector *connector) | |
2320175f | 1569 | { |
1138137c | 1570 | struct intel_display *display = to_intel_display(dig_port); |
7801f3b7 | 1571 | enum port port = dig_port->base.port; |
69205931 | 1572 | enum transcoder cpu_transcoder = connector->hdcp.cpu_transcoder; |
2320175f SP |
1573 | int ret; |
1574 | union { | |
1575 | u32 reg; | |
1576 | u8 shim[DRM_HDCP_RI_LEN]; | |
1577 | } ri; | |
1578 | ||
7801f3b7 | 1579 | ret = intel_hdmi_hdcp_read_ri_prime(dig_port, ri.shim); |
2320175f SP |
1580 | if (ret) |
1581 | return false; | |
1582 | ||
07260855 | 1583 | intel_de_write(display, HDCP_RPRIME(display, cpu_transcoder, port), ri.reg); |
2320175f SP |
1584 | |
1585 | /* Wait for Ri prime match */ | |
07260855 | 1586 | if (wait_for((intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, port)) & |
3ffaf56e | 1587 | (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC)) == |
2320175f | 1588 | (HDCP_STATUS_RI_MATCH | HDCP_STATUS_ENC), 1)) { |
1138137c | 1589 | drm_dbg_kms(display->drm, "Ri' mismatch detected (%x)\n", |
07260855 JN |
1590 | intel_de_read(display, HDCP_STATUS(display, cpu_transcoder, |
1591 | port))); | |
2320175f SP |
1592 | return false; |
1593 | } | |
1594 | return true; | |
1595 | } | |
1596 | ||
b08239b2 | 1597 | static |
038bac89 SP |
1598 | bool intel_hdmi_hdcp_check_link(struct intel_digital_port *dig_port, |
1599 | struct intel_connector *connector) | |
b08239b2 | 1600 | { |
b08239b2 OB |
1601 | int retry; |
1602 | ||
1603 | for (retry = 0; retry < 3; retry++) | |
038bac89 | 1604 | if (intel_hdmi_hdcp_check_link_once(dig_port, connector)) |
b08239b2 OB |
1605 | return true; |
1606 | ||
b08239b2 OB |
1607 | return false; |
1608 | } | |
1609 | ||
67fdd8ea | 1610 | struct hdcp2_hdmi_msg_timeout { |
2d4254e5 | 1611 | u8 msg_id; |
0b7b6966 | 1612 | u16 timeout; |
032048db JN |
1613 | }; |
1614 | ||
67fdd8ea | 1615 | static const struct hdcp2_hdmi_msg_timeout hdcp2_msg_timeout[] = { |
eac03efd VS |
1616 | { HDCP_2_2_AKE_SEND_CERT, HDCP_2_2_CERT_TIMEOUT_MS, }, |
1617 | { HDCP_2_2_AKE_SEND_PAIRING_INFO, HDCP_2_2_PAIRING_TIMEOUT_MS, }, | |
1618 | { HDCP_2_2_LC_SEND_LPRIME, HDCP_2_2_HDMI_LPRIME_TIMEOUT_MS, }, | |
1619 | { HDCP_2_2_REP_SEND_RECVID_LIST, HDCP_2_2_RECVID_LIST_TIMEOUT_MS, }, | |
1620 | { HDCP_2_2_REP_STREAM_READY, HDCP_2_2_STREAM_READY_TIMEOUT_MS, }, | |
032048db | 1621 | }; |
2d4254e5 R |
1622 | |
1623 | static | |
7801f3b7 | 1624 | int intel_hdmi_hdcp2_read_rx_status(struct intel_digital_port *dig_port, |
126d0a94 | 1625 | u8 *rx_status) |
2d4254e5 | 1626 | { |
7801f3b7 | 1627 | return intel_hdmi_hdcp_read(dig_port, |
2d4254e5 R |
1628 | HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET, |
1629 | rx_status, | |
1630 | HDCP_2_2_HDMI_RXSTATUS_LEN); | |
1631 | } | |
1632 | ||
1633 | static int get_hdcp2_msg_timeout(u8 msg_id, bool is_paired) | |
1634 | { | |
1635 | int i; | |
1636 | ||
eac03efd VS |
1637 | if (msg_id == HDCP_2_2_AKE_SEND_HPRIME) { |
1638 | if (is_paired) | |
1639 | return HDCP_2_2_HPRIME_PAIRED_TIMEOUT_MS; | |
1640 | else | |
1641 | return HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT_MS; | |
1642 | } | |
1643 | ||
1644 | for (i = 0; i < ARRAY_SIZE(hdcp2_msg_timeout); i++) { | |
1645 | if (hdcp2_msg_timeout[i].msg_id == msg_id) | |
67fdd8ea | 1646 | return hdcp2_msg_timeout[i].timeout; |
eac03efd | 1647 | } |
2d4254e5 R |
1648 | |
1649 | return -EINVAL; | |
1650 | } | |
1651 | ||
81b55ef1 | 1652 | static int |
7801f3b7 | 1653 | hdcp2_detect_msg_availability(struct intel_digital_port *dig_port, |
81b55ef1 JN |
1654 | u8 msg_id, bool *msg_ready, |
1655 | ssize_t *msg_sz) | |
2d4254e5 | 1656 | { |
1138137c | 1657 | struct intel_display *display = to_intel_display(dig_port); |
2d4254e5 R |
1658 | u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN]; |
1659 | int ret; | |
1660 | ||
7801f3b7 | 1661 | ret = intel_hdmi_hdcp2_read_rx_status(dig_port, rx_status); |
2d4254e5 | 1662 | if (ret < 0) { |
1138137c | 1663 | drm_dbg_kms(display->drm, "rx_status read failed. Err %d\n", |
41919042 | 1664 | ret); |
2d4254e5 R |
1665 | return ret; |
1666 | } | |
1667 | ||
1668 | *msg_sz = ((HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(rx_status[1]) << 8) | | |
1669 | rx_status[0]); | |
1670 | ||
1671 | if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) | |
1672 | *msg_ready = (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1]) && | |
1673 | *msg_sz); | |
1674 | else | |
1675 | *msg_ready = *msg_sz; | |
1676 | ||
1677 | return 0; | |
1678 | } | |
1679 | ||
1680 | static ssize_t | |
7801f3b7 | 1681 | intel_hdmi_hdcp2_wait_for_msg(struct intel_digital_port *dig_port, |
2d4254e5 R |
1682 | u8 msg_id, bool paired) |
1683 | { | |
1138137c | 1684 | struct intel_display *display = to_intel_display(dig_port); |
2d4254e5 R |
1685 | bool msg_ready = false; |
1686 | int timeout, ret; | |
1687 | ssize_t msg_sz = 0; | |
1688 | ||
1689 | timeout = get_hdcp2_msg_timeout(msg_id, paired); | |
1690 | if (timeout < 0) | |
1691 | return timeout; | |
1692 | ||
7801f3b7 | 1693 | ret = __wait_for(ret = hdcp2_detect_msg_availability(dig_port, |
2d4254e5 R |
1694 | msg_id, &msg_ready, |
1695 | &msg_sz), | |
1696 | !ret && msg_ready && msg_sz, timeout * 1000, | |
1697 | 1000, 5 * 1000); | |
1698 | if (ret) | |
1138137c JN |
1699 | drm_dbg_kms(display->drm, |
1700 | "msg_id: %d, ret: %d, timeout: %d\n", | |
41919042 | 1701 | msg_id, ret, timeout); |
2d4254e5 R |
1702 | |
1703 | return ret ? ret : msg_sz; | |
1704 | } | |
1705 | ||
1706 | static | |
51152acf | 1707 | int intel_hdmi_hdcp2_write_msg(struct intel_connector *connector, |
2d4254e5 R |
1708 | void *buf, size_t size) |
1709 | { | |
51152acf | 1710 | struct intel_digital_port *dig_port = intel_attached_dig_port(connector); |
2d4254e5 R |
1711 | unsigned int offset; |
1712 | ||
1713 | offset = HDCP_2_2_HDMI_REG_WR_MSG_OFFSET; | |
7801f3b7 | 1714 | return intel_hdmi_hdcp_write(dig_port, offset, buf, size); |
2d4254e5 R |
1715 | } |
1716 | ||
1717 | static | |
51152acf | 1718 | int intel_hdmi_hdcp2_read_msg(struct intel_connector *connector, |
2d4254e5 R |
1719 | u8 msg_id, void *buf, size_t size) |
1720 | { | |
1138137c | 1721 | struct intel_display *display = to_intel_display(connector); |
51152acf | 1722 | struct intel_digital_port *dig_port = intel_attached_dig_port(connector); |
7801f3b7 | 1723 | struct intel_hdmi *hdmi = &dig_port->hdmi; |
2d4254e5 R |
1724 | struct intel_hdcp *hdcp = &hdmi->attached_connector->hdcp; |
1725 | unsigned int offset; | |
1726 | ssize_t ret; | |
1727 | ||
7801f3b7 | 1728 | ret = intel_hdmi_hdcp2_wait_for_msg(dig_port, msg_id, |
2d4254e5 R |
1729 | hdcp->is_paired); |
1730 | if (ret < 0) | |
1731 | return ret; | |
1732 | ||
1733 | /* | |
1734 | * Available msg size should be equal to or lesser than the | |
1735 | * available buffer. | |
1736 | */ | |
1737 | if (ret > size) { | |
1138137c | 1738 | drm_dbg_kms(display->drm, |
41919042 JN |
1739 | "msg_sz(%zd) is more than exp size(%zu)\n", |
1740 | ret, size); | |
0743019d | 1741 | return -EINVAL; |
2d4254e5 R |
1742 | } |
1743 | ||
1744 | offset = HDCP_2_2_HDMI_REG_RD_MSG_OFFSET; | |
7801f3b7 | 1745 | ret = intel_hdmi_hdcp_read(dig_port, offset, buf, ret); |
2d4254e5 | 1746 | if (ret) |
1138137c | 1747 | drm_dbg_kms(display->drm, "Failed to read msg_id: %d(%zd)\n", |
41919042 | 1748 | msg_id, ret); |
2d4254e5 R |
1749 | |
1750 | return ret; | |
1751 | } | |
1752 | ||
1753 | static | |
5bd29e32 AG |
1754 | int intel_hdmi_hdcp2_check_link(struct intel_digital_port *dig_port, |
1755 | struct intel_connector *connector) | |
2d4254e5 R |
1756 | { |
1757 | u8 rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN]; | |
1758 | int ret; | |
1759 | ||
7801f3b7 | 1760 | ret = intel_hdmi_hdcp2_read_rx_status(dig_port, rx_status); |
2d4254e5 R |
1761 | if (ret) |
1762 | return ret; | |
1763 | ||
1764 | /* | |
1765 | * Re-auth request and Link Integrity Failures are represented by | |
1766 | * same bit. i.e reauth_req. | |
1767 | */ | |
1768 | if (HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(rx_status[1])) | |
1769 | ret = HDCP_REAUTH_REQUEST; | |
1770 | else if (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1])) | |
1771 | ret = HDCP_TOPOLOGY_CHANGE; | |
1772 | ||
1773 | return ret; | |
1774 | } | |
1775 | ||
1776 | static | |
8e754d9e SK |
1777 | int intel_hdmi_hdcp2_get_capability(struct intel_connector *connector, |
1778 | bool *capable) | |
2d4254e5 | 1779 | { |
130849f8 | 1780 | struct intel_digital_port *dig_port = intel_attached_dig_port(connector); |
2d4254e5 R |
1781 | u8 hdcp2_version; |
1782 | int ret; | |
1783 | ||
1784 | *capable = false; | |
7801f3b7 | 1785 | ret = intel_hdmi_hdcp_read(dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET, |
2d4254e5 R |
1786 | &hdcp2_version, sizeof(hdcp2_version)); |
1787 | if (!ret && hdcp2_version & HDCP_2_2_HDMI_SUPPORT_MASK) | |
1788 | *capable = true; | |
1789 | ||
1790 | return ret; | |
1791 | } | |
1792 | ||
2320175f SP |
1793 | static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = { |
1794 | .write_an_aksv = intel_hdmi_hdcp_write_an_aksv, | |
1795 | .read_bksv = intel_hdmi_hdcp_read_bksv, | |
1796 | .read_bstatus = intel_hdmi_hdcp_read_bstatus, | |
1797 | .repeater_present = intel_hdmi_hdcp_repeater_present, | |
1798 | .read_ri_prime = intel_hdmi_hdcp_read_ri_prime, | |
1799 | .read_ksv_ready = intel_hdmi_hdcp_read_ksv_ready, | |
1800 | .read_ksv_fifo = intel_hdmi_hdcp_read_ksv_fifo, | |
1801 | .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part, | |
1802 | .toggle_signalling = intel_hdmi_hdcp_toggle_signalling, | |
1803 | .check_link = intel_hdmi_hdcp_check_link, | |
2d4254e5 R |
1804 | .write_2_2_msg = intel_hdmi_hdcp2_write_msg, |
1805 | .read_2_2_msg = intel_hdmi_hdcp2_read_msg, | |
1806 | .check_2_2_link = intel_hdmi_hdcp2_check_link, | |
8e754d9e | 1807 | .hdcp_2_2_get_capability = intel_hdmi_hdcp2_get_capability, |
2d4254e5 | 1808 | .protocol = HDCP_PROTOCOL_HDMI, |
2320175f SP |
1809 | }; |
1810 | ||
d6038611 | 1811 | static int intel_hdmi_source_max_tmds_clock(struct intel_encoder *encoder) |
7d148ef5 | 1812 | { |
1138137c | 1813 | struct intel_display *display = to_intel_display(encoder); |
d9ee2111 | 1814 | int max_tmds_clock, vbt_max_tmds_clock; |
d6038611 | 1815 | |
4a3506d1 | 1816 | if (DISPLAY_VER(display) >= 13 || display->platform.alderlake_s) |
2689390b | 1817 | max_tmds_clock = 600000; |
1138137c | 1818 | else if (DISPLAY_VER(display) >= 10) |
d6038611 | 1819 | max_tmds_clock = 594000; |
4a3506d1 | 1820 | else if (DISPLAY_VER(display) >= 8 || display->platform.haswell) |
d6038611 | 1821 | max_tmds_clock = 300000; |
1138137c | 1822 | else if (DISPLAY_VER(display) >= 5) |
d6038611 | 1823 | max_tmds_clock = 225000; |
7d148ef5 | 1824 | else |
d6038611 VS |
1825 | max_tmds_clock = 165000; |
1826 | ||
02107ef1 | 1827 | vbt_max_tmds_clock = intel_bios_hdmi_max_tmds_clock(encoder->devdata); |
d9ee2111 JN |
1828 | if (vbt_max_tmds_clock) |
1829 | max_tmds_clock = min(max_tmds_clock, vbt_max_tmds_clock); | |
d6038611 VS |
1830 | |
1831 | return max_tmds_clock; | |
7d148ef5 DV |
1832 | } |
1833 | ||
b1040461 VS |
1834 | static bool intel_has_hdmi_sink(struct intel_hdmi *hdmi, |
1835 | const struct drm_connector_state *conn_state) | |
1836 | { | |
7c1000aa JN |
1837 | struct intel_connector *connector = hdmi->attached_connector; |
1838 | ||
1839 | return connector->base.display_info.is_hdmi && | |
b1040461 VS |
1840 | READ_ONCE(to_intel_digital_connector_state(conn_state)->force_audio) != HDMI_AUDIO_OFF_DVI; |
1841 | } | |
1842 | ||
bb115220 VS |
1843 | static bool intel_hdmi_is_ycbcr420(const struct intel_crtc_state *crtc_state) |
1844 | { | |
1845 | return crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR420; | |
1846 | } | |
1847 | ||
b1ba124d | 1848 | static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, |
7a5ca19f | 1849 | bool respect_downstream_limits, |
b1040461 | 1850 | bool has_hdmi_sink) |
b1ba124d | 1851 | { |
d6038611 VS |
1852 | struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base; |
1853 | int max_tmds_clock = intel_hdmi_source_max_tmds_clock(encoder); | |
b1ba124d VS |
1854 | |
1855 | if (respect_downstream_limits) { | |
8cadab0a VS |
1856 | struct intel_connector *connector = hdmi->attached_connector; |
1857 | const struct drm_display_info *info = &connector->base.display_info; | |
1858 | ||
b1ba124d VS |
1859 | if (hdmi->dp_dual_mode.max_tmds_clock) |
1860 | max_tmds_clock = min(max_tmds_clock, | |
1861 | hdmi->dp_dual_mode.max_tmds_clock); | |
8cadab0a VS |
1862 | |
1863 | if (info->max_tmds_clock) | |
1864 | max_tmds_clock = min(max_tmds_clock, | |
1865 | info->max_tmds_clock); | |
b1040461 | 1866 | else if (!has_hdmi_sink) |
b1ba124d VS |
1867 | max_tmds_clock = min(max_tmds_clock, 165000); |
1868 | } | |
1869 | ||
1870 | return max_tmds_clock; | |
1871 | } | |
1872 | ||
e64e739e VS |
1873 | static enum drm_mode_status |
1874 | hdmi_port_clock_valid(struct intel_hdmi *hdmi, | |
7a5ca19f | 1875 | int clock, bool respect_downstream_limits, |
b1040461 | 1876 | bool has_hdmi_sink) |
e64e739e | 1877 | { |
1138137c | 1878 | struct intel_display *display = to_intel_display(hdmi); |
7fcf7558 | 1879 | struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base; |
e64e739e VS |
1880 | |
1881 | if (clock < 25000) | |
1882 | return MODE_CLOCK_LOW; | |
b1040461 VS |
1883 | if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits, |
1884 | has_hdmi_sink)) | |
e64e739e VS |
1885 | return MODE_CLOCK_HIGH; |
1886 | ||
41751b3e | 1887 | /* GLK DPLL can't generate 446-480 MHz */ |
4a3506d1 | 1888 | if (display->platform.geminilake && clock > 446666 && clock < 480000) |
41751b3e VS |
1889 | return MODE_CLOCK_RANGE; |
1890 | ||
1891 | /* BXT/GLK DPLL can't generate 223-240 MHz */ | |
4a3506d1 | 1892 | if ((display->platform.geminilake || display->platform.broxton) && |
2446e1d6 | 1893 | clock > 223333 && clock < 240000) |
5e6ccc0b VS |
1894 | return MODE_CLOCK_RANGE; |
1895 | ||
1896 | /* CHV DPLL can't generate 216-240 MHz */ | |
4a3506d1 | 1897 | if (display->platform.cherryview && clock > 216000 && clock < 240000) |
e64e739e VS |
1898 | return MODE_CLOCK_RANGE; |
1899 | ||
e5086cb3 | 1900 | /* ICL+ combo PHY PLL can't generate 500-533.2 MHz */ |
7fcf7558 | 1901 | if (intel_encoder_is_combo(encoder) && clock > 500000 && clock < 533200) |
e5086cb3 VS |
1902 | return MODE_CLOCK_RANGE; |
1903 | ||
1904 | /* ICL+ TC PHY PLL can't generate 500-532.8 MHz */ | |
7fcf7558 | 1905 | if (intel_encoder_is_tc(encoder) && clock > 500000 && clock < 532800) |
e5086cb3 VS |
1906 | return MODE_CLOCK_RANGE; |
1907 | ||
e64e739e VS |
1908 | return MODE_OK; |
1909 | } | |
1910 | ||
52315679 AN |
1911 | int intel_hdmi_tmds_clock(int clock, int bpc, |
1912 | enum intel_output_format sink_format) | |
3c4442aa | 1913 | { |
59908256 | 1914 | /* YCBCR420 TMDS rate requirement is half the pixel clock */ |
52315679 | 1915 | if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420) |
59908256 VS |
1916 | clock /= 2; |
1917 | ||
3c4442aa VS |
1918 | /* |
1919 | * Need to adjust the port link by: | |
1920 | * 1.5x for 12bpc | |
1921 | * 1.25x for 10bpc | |
1922 | */ | |
f2c9df10 | 1923 | return DIV_ROUND_CLOSEST(clock * bpc, 8); |
3c4442aa VS |
1924 | } |
1925 | ||
1138137c | 1926 | static bool intel_hdmi_source_bpc_possible(struct intel_display *display, int bpc) |
3cf460bd VS |
1927 | { |
1928 | switch (bpc) { | |
1929 | case 12: | |
1138137c | 1930 | return !HAS_GMCH(display); |
3cf460bd | 1931 | case 10: |
1138137c | 1932 | return DISPLAY_VER(display) >= 11; |
3cf460bd VS |
1933 | case 8: |
1934 | return true; | |
1935 | default: | |
1936 | MISSING_CASE(bpc); | |
1937 | return false; | |
1938 | } | |
1939 | } | |
1940 | ||
506f254e | 1941 | static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector, |
52315679 AN |
1942 | int bpc, bool has_hdmi_sink, |
1943 | enum intel_output_format sink_format) | |
06e0df24 | 1944 | { |
506f254e ID |
1945 | struct intel_connector *connector = to_intel_connector(_connector); |
1946 | const struct drm_display_info *info = &connector->base.display_info; | |
06e0df24 VS |
1947 | const struct drm_hdmi_info *hdmi = &info->hdmi; |
1948 | ||
1949 | switch (bpc) { | |
1950 | case 12: | |
f02e6c85 VS |
1951 | if (!has_hdmi_sink) |
1952 | return false; | |
1953 | ||
52315679 | 1954 | if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420) |
06e0df24 VS |
1955 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36; |
1956 | else | |
4adc33f3 | 1957 | return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36; |
06e0df24 | 1958 | case 10: |
f02e6c85 VS |
1959 | if (!has_hdmi_sink) |
1960 | return false; | |
1961 | ||
52315679 | 1962 | if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420) |
06e0df24 VS |
1963 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30; |
1964 | else | |
4adc33f3 | 1965 | return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30; |
06e0df24 VS |
1966 | case 8: |
1967 | return true; | |
1968 | default: | |
1969 | MISSING_CASE(bpc); | |
1970 | return false; | |
1971 | } | |
1972 | } | |
1973 | ||
eacba74d | 1974 | static enum drm_mode_status |
506f254e | 1975 | intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock, |
52315679 AN |
1976 | bool has_hdmi_sink, |
1977 | enum intel_output_format sink_format) | |
eacba74d | 1978 | { |
506f254e ID |
1979 | struct intel_connector *connector = to_intel_connector(_connector); |
1980 | struct intel_display *display = to_intel_display(connector); | |
1981 | struct intel_hdmi *hdmi = intel_attached_hdmi(connector); | |
5d488786 VS |
1982 | enum drm_mode_status status = MODE_OK; |
1983 | int bpc; | |
1984 | ||
1985 | /* | |
1986 | * Try all color depths since valid port clock range | |
1987 | * can have holes. Any mode that can be used with at | |
1988 | * least one color depth is accepted. | |
1989 | */ | |
1990 | for (bpc = 12; bpc >= 8; bpc -= 2) { | |
52315679 | 1991 | int tmds_clock = intel_hdmi_tmds_clock(clock, bpc, sink_format); |
5d488786 | 1992 | |
1138137c | 1993 | if (!intel_hdmi_source_bpc_possible(display, bpc)) |
5d488786 VS |
1994 | continue; |
1995 | ||
506f254e ID |
1996 | if (!intel_hdmi_sink_bpc_possible(&connector->base, bpc, has_hdmi_sink, |
1997 | sink_format)) | |
5d488786 VS |
1998 | continue; |
1999 | ||
2000 | status = hdmi_port_clock_valid(hdmi, tmds_clock, true, has_hdmi_sink); | |
2001 | if (status == MODE_OK) | |
2002 | return MODE_OK; | |
2003 | } | |
eacba74d | 2004 | |
5d488786 | 2005 | /* can never happen */ |
1138137c | 2006 | drm_WARN_ON(display->drm, status == MODE_OK); |
eacba74d WS |
2007 | |
2008 | return status; | |
2009 | } | |
2010 | ||
c19de8eb | 2011 | static enum drm_mode_status |
506f254e | 2012 | intel_hdmi_mode_valid(struct drm_connector *_connector, |
26d6fd81 | 2013 | const struct drm_display_mode *mode) |
7d57382e | 2014 | { |
506f254e ID |
2015 | struct intel_connector *connector = to_intel_connector(_connector); |
2016 | struct intel_display *display = to_intel_display(connector); | |
2017 | struct intel_hdmi *hdmi = intel_attached_hdmi(connector); | |
e64e739e | 2018 | enum drm_mode_status status; |
b1040461 | 2019 | int clock = mode->clock; |
506f254e ID |
2020 | int max_dotclk = display->cdclk.max_dotclk_freq; |
2021 | bool has_hdmi_sink = intel_has_hdmi_sink(hdmi, connector->base.state); | |
388b8635 | 2022 | bool ycbcr_420_only; |
52315679 | 2023 | enum intel_output_format sink_format; |
e64e739e | 2024 | |
a580ed17 | 2025 | status = intel_cpu_transcoder_mode_valid(display, mode); |
e0ef2daa VS |
2026 | if (status != MODE_OK) |
2027 | return status; | |
2028 | ||
587bf496 MK |
2029 | if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) |
2030 | clock *= 2; | |
2031 | ||
2032 | if (clock > max_dotclk) | |
2033 | return MODE_CLOCK_HIGH; | |
2034 | ||
c35ad314 VS |
2035 | if (mode->flags & DRM_MODE_FLAG_DBLCLK) { |
2036 | if (!has_hdmi_sink) | |
2037 | return MODE_CLOCK_LOW; | |
697c4078 | 2038 | clock *= 2; |
c35ad314 | 2039 | } |
697c4078 | 2040 | |
3565c721 AN |
2041 | /* |
2042 | * HDMI2.1 requires higher resolution modes like 8k60, 4K120 to be | |
2043 | * enumerated only if FRL is supported. Current platforms do not support | |
2044 | * FRL so prune the higher resolution modes that require doctclock more | |
2045 | * than 600MHz. | |
2046 | */ | |
2047 | if (clock > 600000) | |
2048 | return MODE_CLOCK_HIGH; | |
2049 | ||
506f254e | 2050 | ycbcr_420_only = drm_mode_is_420_only(&connector->base.display_info, mode); |
b22ca995 | 2051 | |
52315679 AN |
2052 | if (ycbcr_420_only) |
2053 | sink_format = INTEL_OUTPUT_FORMAT_YCBCR420; | |
2054 | else | |
2055 | sink_format = INTEL_OUTPUT_FORMAT_RGB; | |
2056 | ||
506f254e | 2057 | status = intel_hdmi_mode_clock_valid(&connector->base, clock, has_hdmi_sink, sink_format); |
388b8635 WS |
2058 | if (status != MODE_OK) { |
2059 | if (ycbcr_420_only || | |
506f254e ID |
2060 | !connector->base.ycbcr_420_allowed || |
2061 | !drm_mode_is_420_also(&connector->base.display_info, mode)) | |
388b8635 | 2062 | return status; |
7d57382e | 2063 | |
52315679 | 2064 | sink_format = INTEL_OUTPUT_FORMAT_YCBCR420; |
506f254e ID |
2065 | status = intel_hdmi_mode_clock_valid(&connector->base, clock, has_hdmi_sink, |
2066 | sink_format); | |
388b8635 WS |
2067 | if (status != MODE_OK) |
2068 | return status; | |
cd9e11a8 | 2069 | } |
7d57382e | 2070 | |
010d150a | 2071 | return intel_mode_valid_max_plane_size(display, mode, 1); |
7d57382e EA |
2072 | } |
2073 | ||
b4d77577 | 2074 | bool intel_hdmi_bpc_possible(const struct intel_crtc_state *crtc_state, |
52315679 | 2075 | int bpc, bool has_hdmi_sink) |
71800632 | 2076 | { |
506f254e ID |
2077 | struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state); |
2078 | struct intel_digital_connector_state *connector_state; | |
2079 | struct intel_connector *connector; | |
c750bdd3 | 2080 | int i; |
71800632 | 2081 | |
506f254e ID |
2082 | for_each_new_intel_connector_in_state(state, connector, connector_state, i) { |
2083 | if (connector_state->base.crtc != crtc_state->uapi.crtc) | |
c750bdd3 VS |
2084 | continue; |
2085 | ||
506f254e | 2086 | if (!intel_hdmi_sink_bpc_possible(&connector->base, bpc, has_hdmi_sink, |
52315679 | 2087 | crtc_state->sink_format)) |
06e0df24 | 2088 | return false; |
c750bdd3 VS |
2089 | } |
2090 | ||
bc7ca6a6 VS |
2091 | return true; |
2092 | } | |
2093 | ||
b4d77577 | 2094 | static bool hdmi_bpc_possible(const struct intel_crtc_state *crtc_state, int bpc) |
bc7ca6a6 | 2095 | { |
1138137c | 2096 | struct intel_display *display = to_intel_display(crtc_state); |
bc7ca6a6 VS |
2097 | const struct drm_display_mode *adjusted_mode = |
2098 | &crtc_state->hw.adjusted_mode; | |
2099 | ||
1138137c | 2100 | if (!intel_hdmi_source_bpc_possible(display, bpc)) |
3cf460bd VS |
2101 | return false; |
2102 | ||
1c5fad61 | 2103 | /* Display Wa_1405510057:icl,ehl */ |
bb115220 | 2104 | if (intel_hdmi_is_ycbcr420(crtc_state) && |
1138137c | 2105 | bpc == 10 && DISPLAY_VER(display) == 11 && |
22dae8a0 RS |
2106 | (adjusted_mode->crtc_hblank_end - |
2107 | adjusted_mode->crtc_hblank_start) % 8 == 2) | |
46649d8b ACO |
2108 | return false; |
2109 | ||
52315679 | 2110 | return intel_hdmi_bpc_possible(crtc_state, bpc, crtc_state->has_hdmi_sink); |
71800632 VS |
2111 | } |
2112 | ||
9e362992 VS |
2113 | static int intel_hdmi_compute_bpc(struct intel_encoder *encoder, |
2114 | struct intel_crtc_state *crtc_state, | |
b4d77577 | 2115 | int clock, bool respect_downstream_limits) |
9e362992 | 2116 | { |
b7d02c3a | 2117 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
9e362992 VS |
2118 | int bpc; |
2119 | ||
b4d77577 VS |
2120 | /* |
2121 | * pipe_bpp could already be below 8bpc due to FDI | |
2122 | * bandwidth constraints. HDMI minimum is 8bpc however. | |
2123 | */ | |
2124 | bpc = max(crtc_state->pipe_bpp / 3, 8); | |
2125 | ||
2126 | /* | |
2127 | * We will never exceed downstream TMDS clock limits while | |
2128 | * attempting deep color. If the user insists on forcing an | |
2129 | * out of spec mode they will have to be satisfied with 8bpc. | |
2130 | */ | |
2131 | if (!respect_downstream_limits) | |
2132 | bpc = 8; | |
2133 | ||
2134 | for (; bpc >= 8; bpc -= 2) { | |
52315679 AN |
2135 | int tmds_clock = intel_hdmi_tmds_clock(clock, bpc, |
2136 | crtc_state->sink_format); | |
b4d77577 VS |
2137 | |
2138 | if (hdmi_bpc_possible(crtc_state, bpc) && | |
2139 | hdmi_port_clock_valid(intel_hdmi, tmds_clock, | |
2140 | respect_downstream_limits, | |
2141 | crtc_state->has_hdmi_sink) == MODE_OK) | |
9e362992 VS |
2142 | return bpc; |
2143 | } | |
2144 | ||
b4d77577 | 2145 | return -EINVAL; |
9e362992 VS |
2146 | } |
2147 | ||
2148 | static int intel_hdmi_compute_clock(struct intel_encoder *encoder, | |
b4d77577 VS |
2149 | struct intel_crtc_state *crtc_state, |
2150 | bool respect_downstream_limits) | |
9e362992 | 2151 | { |
1138137c | 2152 | struct intel_display *display = to_intel_display(encoder); |
9e362992 | 2153 | const struct drm_display_mode *adjusted_mode = |
1326a92c | 2154 | &crtc_state->hw.adjusted_mode; |
9e362992 VS |
2155 | int bpc, clock = adjusted_mode->crtc_clock; |
2156 | ||
2157 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) | |
2158 | clock *= 2; | |
2159 | ||
b4d77577 VS |
2160 | bpc = intel_hdmi_compute_bpc(encoder, crtc_state, clock, |
2161 | respect_downstream_limits); | |
2162 | if (bpc < 0) | |
2163 | return bpc; | |
9e362992 | 2164 | |
b4d77577 | 2165 | crtc_state->port_clock = |
52315679 | 2166 | intel_hdmi_tmds_clock(clock, bpc, crtc_state->sink_format); |
9e362992 VS |
2167 | |
2168 | /* | |
2169 | * pipe_bpp could already be below 8bpc due to | |
2170 | * FDI bandwidth constraints. We shouldn't bump it | |
b4d77577 | 2171 | * back up to the HDMI minimum 8bpc in that case. |
9e362992 | 2172 | */ |
b4d77577 | 2173 | crtc_state->pipe_bpp = min(crtc_state->pipe_bpp, bpc * 3); |
9e362992 | 2174 | |
1138137c | 2175 | drm_dbg_kms(display->drm, |
41919042 JN |
2176 | "picking %d bpc for HDMI output (pipe bpp: %d)\n", |
2177 | bpc, crtc_state->pipe_bpp); | |
9e362992 | 2178 | |
9e362992 VS |
2179 | return 0; |
2180 | } | |
2181 | ||
90f8ed85 VS |
2182 | bool intel_hdmi_limited_color_range(const struct intel_crtc_state *crtc_state, |
2183 | const struct drm_connector_state *conn_state) | |
ba2d08c2 VS |
2184 | { |
2185 | const struct intel_digital_connector_state *intel_conn_state = | |
2186 | to_intel_digital_connector_state(conn_state); | |
2187 | const struct drm_display_mode *adjusted_mode = | |
1326a92c | 2188 | &crtc_state->hw.adjusted_mode; |
ba2d08c2 | 2189 | |
cae154fc VS |
2190 | /* |
2191 | * Our YCbCr output is always limited range. | |
2192 | * crtc_state->limited_color_range only applies to RGB, | |
2193 | * and it must never be set for YCbCr or we risk setting | |
3eb08ea5 | 2194 | * some conflicting bits in TRANSCONF which will mess up |
cae154fc VS |
2195 | * the colors on the monitor. |
2196 | */ | |
2197 | if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) | |
2198 | return false; | |
2199 | ||
ba2d08c2 VS |
2200 | if (intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_AUTO) { |
2201 | /* See CEA-861-E - 5.1 Default Encoding Parameters */ | |
2202 | return crtc_state->has_hdmi_sink && | |
2203 | drm_default_rgb_quant_range(adjusted_mode) == | |
2204 | HDMI_QUANTIZATION_RANGE_LIMITED; | |
2205 | } else { | |
2206 | return intel_conn_state->broadcast_rgb == INTEL_BROADCAST_RGB_LIMITED; | |
2207 | } | |
2208 | } | |
2209 | ||
04e18e01 VS |
2210 | static bool intel_hdmi_has_audio(struct intel_encoder *encoder, |
2211 | const struct intel_crtc_state *crtc_state, | |
2212 | const struct drm_connector_state *conn_state) | |
2213 | { | |
506f254e | 2214 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
04e18e01 VS |
2215 | const struct intel_digital_connector_state *intel_conn_state = |
2216 | to_intel_digital_connector_state(conn_state); | |
2217 | ||
2218 | if (!crtc_state->has_hdmi_sink) | |
2219 | return false; | |
2220 | ||
2221 | if (intel_conn_state->force_audio == HDMI_AUDIO_AUTO) | |
506f254e | 2222 | return connector->base.display_info.has_audio; |
04e18e01 VS |
2223 | else |
2224 | return intel_conn_state->force_audio == HDMI_AUDIO_ON; | |
2225 | } | |
2226 | ||
81148c26 | 2227 | static enum intel_output_format |
a04d27cd AN |
2228 | intel_hdmi_sink_format(const struct intel_crtc_state *crtc_state, |
2229 | struct intel_connector *connector, | |
2230 | bool ycbcr_420_output) | |
81148c26 | 2231 | { |
390a7d30 VS |
2232 | if (!crtc_state->has_hdmi_sink) |
2233 | return INTEL_OUTPUT_FORMAT_RGB; | |
2234 | ||
81148c26 VS |
2235 | if (connector->base.ycbcr_420_allowed && ycbcr_420_output) |
2236 | return INTEL_OUTPUT_FORMAT_YCBCR420; | |
2237 | else | |
2238 | return INTEL_OUTPUT_FORMAT_RGB; | |
2239 | } | |
2240 | ||
a04d27cd AN |
2241 | static enum intel_output_format |
2242 | intel_hdmi_output_format(const struct intel_crtc_state *crtc_state) | |
2243 | { | |
2244 | return crtc_state->sink_format; | |
2245 | } | |
2246 | ||
84d95f77 WS |
2247 | static int intel_hdmi_compute_output_format(struct intel_encoder *encoder, |
2248 | struct intel_crtc_state *crtc_state, | |
b4d77577 VS |
2249 | const struct drm_connector_state *conn_state, |
2250 | bool respect_downstream_limits) | |
84d95f77 | 2251 | { |
1138137c | 2252 | struct intel_display *display = to_intel_display(encoder); |
81148c26 | 2253 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
84d95f77 | 2254 | const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; |
81148c26 | 2255 | const struct drm_display_info *info = &connector->base.display_info; |
81148c26 | 2256 | bool ycbcr_420_only = drm_mode_is_420_only(info, adjusted_mode); |
84d95f77 | 2257 | int ret; |
84d95f77 | 2258 | |
a04d27cd AN |
2259 | crtc_state->sink_format = |
2260 | intel_hdmi_sink_format(crtc_state, connector, ycbcr_420_only); | |
81148c26 | 2261 | |
a04d27cd | 2262 | if (ycbcr_420_only && crtc_state->sink_format != INTEL_OUTPUT_FORMAT_YCBCR420) { |
1138137c | 2263 | drm_dbg_kms(display->drm, |
81148c26 | 2264 | "YCbCr 4:2:0 mode but YCbCr 4:2:0 output not possible. Falling back to RGB.\n"); |
a04d27cd | 2265 | crtc_state->sink_format = INTEL_OUTPUT_FORMAT_RGB; |
84d95f77 WS |
2266 | } |
2267 | ||
a04d27cd | 2268 | crtc_state->output_format = intel_hdmi_output_format(crtc_state); |
b4d77577 | 2269 | ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits); |
388b8635 | 2270 | if (ret) { |
a04d27cd AN |
2271 | if (crtc_state->sink_format == INTEL_OUTPUT_FORMAT_YCBCR420 || |
2272 | !crtc_state->has_hdmi_sink || | |
81148c26 VS |
2273 | !connector->base.ycbcr_420_allowed || |
2274 | !drm_mode_is_420_also(info, adjusted_mode)) | |
f4fdf376 VS |
2275 | return ret; |
2276 | ||
a04d27cd AN |
2277 | crtc_state->sink_format = INTEL_OUTPUT_FORMAT_YCBCR420; |
2278 | crtc_state->output_format = intel_hdmi_output_format(crtc_state); | |
b4d77577 | 2279 | ret = intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits); |
388b8635 | 2280 | } |
84d95f77 WS |
2281 | |
2282 | return ret; | |
2283 | } | |
2284 | ||
d6c4f950 VS |
2285 | static bool intel_hdmi_is_cloned(const struct intel_crtc_state *crtc_state) |
2286 | { | |
2287 | return crtc_state->uapi.encoder_mask && | |
2288 | !is_power_of_2(crtc_state->uapi.encoder_mask); | |
2289 | } | |
2290 | ||
9c608cf3 AN |
2291 | static bool source_supports_scrambling(struct intel_encoder *encoder) |
2292 | { | |
2293 | /* | |
2294 | * Gen 10+ support HDMI 2.0 : the max tmds clock is 594MHz, and | |
2295 | * scrambling is supported. | |
2296 | * But there seem to be cases where certain platforms that support | |
2297 | * HDMI 2.0, have an HDMI1.4 retimer chip, and the max tmds clock is | |
2298 | * capped by VBT to less than 340MHz. | |
2299 | * | |
2300 | * In such cases when an HDMI2.0 sink is connected, it creates a | |
2301 | * problem : the platform and the sink both support scrambling but the | |
2302 | * HDMI 1.4 retimer chip doesn't. | |
2303 | * | |
2304 | * So go for scrambling, based on the max tmds clock taking into account, | |
2305 | * restrictions coming from VBT. | |
2306 | */ | |
2307 | return intel_hdmi_source_max_tmds_clock(encoder) > 340000; | |
2308 | } | |
2309 | ||
34682d60 VS |
2310 | bool intel_hdmi_compute_has_hdmi_sink(struct intel_encoder *encoder, |
2311 | const struct intel_crtc_state *crtc_state, | |
2312 | const struct drm_connector_state *conn_state) | |
2313 | { | |
2314 | struct intel_hdmi *hdmi = enc_to_intel_hdmi(encoder); | |
2315 | ||
2316 | return intel_has_hdmi_sink(hdmi, conn_state) && | |
2317 | !intel_hdmi_is_cloned(crtc_state); | |
2318 | } | |
2319 | ||
204474a6 LP |
2320 | int intel_hdmi_compute_config(struct intel_encoder *encoder, |
2321 | struct intel_crtc_state *pipe_config, | |
2322 | struct drm_connector_state *conn_state) | |
7d57382e | 2323 | { |
1138137c | 2324 | struct intel_display *display = to_intel_display(encoder); |
1326a92c | 2325 | struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; |
506f254e ID |
2326 | struct intel_connector *connector = to_intel_connector(conn_state->connector); |
2327 | struct drm_scdc *scdc = &connector->base.display_info.hdmi.scdc; | |
9e362992 | 2328 | int ret; |
3685a8f3 | 2329 | |
e4dd27aa | 2330 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) |
204474a6 | 2331 | return -EINVAL; |
e4dd27aa | 2332 | |
506f254e | 2333 | if (!connector->base.interlace_allowed && |
f71c9b7b AN |
2334 | adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) |
2335 | return -EINVAL; | |
2336 | ||
d9facae6 | 2337 | pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; |
6897b4b5 | 2338 | |
e43823ec JB |
2339 | if (pipe_config->has_hdmi_sink) |
2340 | pipe_config->has_infoframe = true; | |
2341 | ||
9e362992 | 2342 | if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) |
697c4078 | 2343 | pipe_config->pixel_multiplier = 2; |
697c4078 | 2344 | |
04e18e01 | 2345 | pipe_config->has_audio = |
5d986635 VS |
2346 | intel_hdmi_has_audio(encoder, pipe_config, conn_state) && |
2347 | intel_audio_compute_config(encoder, pipe_config, conn_state); | |
9ed109a7 | 2348 | |
b4d77577 VS |
2349 | /* |
2350 | * Try to respect downstream TMDS clock limits first, if | |
2351 | * that fails assume the user might know something we don't. | |
2352 | */ | |
2353 | ret = intel_hdmi_compute_output_format(encoder, pipe_config, conn_state, true); | |
9e362992 | 2354 | if (ret) |
b4d77577 VS |
2355 | ret = intel_hdmi_compute_output_format(encoder, pipe_config, conn_state, false); |
2356 | if (ret) { | |
1138137c | 2357 | drm_dbg_kms(display->drm, |
b4d77577 VS |
2358 | "unsupported HDMI clock (%d kHz), rejecting mode\n", |
2359 | pipe_config->hw.adjusted_mode.crtc_clock); | |
9e362992 | 2360 | return ret; |
b4d77577 | 2361 | } |
325b9d04 | 2362 | |
bb115220 | 2363 | if (intel_hdmi_is_ycbcr420(pipe_config)) { |
e6b6de16 | 2364 | ret = intel_pfit_compute_config(pipe_config, conn_state); |
84d95f77 WS |
2365 | if (ret) |
2366 | return ret; | |
2367 | } | |
2368 | ||
2369 | pipe_config->limited_color_range = | |
2370 | intel_hdmi_limited_color_range(pipe_config, conn_state); | |
2371 | ||
c504f4df VS |
2372 | if (conn_state->picture_aspect_ratio) |
2373 | adjusted_mode->picture_aspect_ratio = | |
2374 | conn_state->picture_aspect_ratio; | |
28b468a0 | 2375 | |
d4d6279a ACO |
2376 | pipe_config->lane_count = 4; |
2377 | ||
9c608cf3 | 2378 | if (scdc->scrambling.supported && source_supports_scrambling(encoder)) { |
15953637 SS |
2379 | if (scdc->scrambling.low_rates) |
2380 | pipe_config->hdmi_scrambling = true; | |
2381 | ||
2382 | if (pipe_config->port_clock > 340000) { | |
2383 | pipe_config->hdmi_scrambling = true; | |
2384 | pipe_config->hdmi_high_tmds_clock_ratio = true; | |
2385 | } | |
2386 | } | |
2387 | ||
635125e3 AN |
2388 | intel_vrr_compute_config(pipe_config, conn_state); |
2389 | ||
ede9771d VS |
2390 | intel_hdmi_compute_gcp_infoframe(encoder, pipe_config, |
2391 | conn_state); | |
fbf08556 VS |
2392 | |
2393 | if (!intel_hdmi_compute_avi_infoframe(encoder, pipe_config, conn_state)) { | |
1138137c | 2394 | drm_dbg_kms(display->drm, "bad AVI infoframe\n"); |
fbf08556 VS |
2395 | return -EINVAL; |
2396 | } | |
2397 | ||
2398 | if (!intel_hdmi_compute_spd_infoframe(encoder, pipe_config, conn_state)) { | |
1138137c | 2399 | drm_dbg_kms(display->drm, "bad SPD infoframe\n"); |
fbf08556 VS |
2400 | return -EINVAL; |
2401 | } | |
2402 | ||
2403 | if (!intel_hdmi_compute_hdmi_infoframe(encoder, pipe_config, conn_state)) { | |
1138137c | 2404 | drm_dbg_kms(display->drm, "bad HDMI infoframe\n"); |
fbf08556 VS |
2405 | return -EINVAL; |
2406 | } | |
2407 | ||
5a0200f6 | 2408 | if (!intel_hdmi_compute_drm_infoframe(encoder, pipe_config, conn_state)) { |
1138137c | 2409 | drm_dbg_kms(display->drm, "bad DRM infoframe\n"); |
5a0200f6 US |
2410 | return -EINVAL; |
2411 | } | |
2412 | ||
204474a6 | 2413 | return 0; |
7d57382e EA |
2414 | } |
2415 | ||
49c55f7b VS |
2416 | void intel_hdmi_encoder_shutdown(struct intel_encoder *encoder) |
2417 | { | |
2418 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | |
2419 | ||
2420 | /* | |
2421 | * Give a hand to buggy BIOSen which forget to turn | |
2422 | * the TMDS output buffers back on after a reboot. | |
2423 | */ | |
2424 | intel_dp_dual_mode_set_tmds_output(intel_hdmi, true); | |
2425 | } | |
2426 | ||
953ece69 | 2427 | static void |
506f254e | 2428 | intel_hdmi_unset_edid(struct drm_connector *_connector) |
9dff6af8 | 2429 | { |
506f254e ID |
2430 | struct intel_connector *connector = to_intel_connector(_connector); |
2431 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); | |
9dff6af8 | 2432 | |
b1ba124d VS |
2433 | intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE; |
2434 | intel_hdmi->dp_dual_mode.max_tmds_clock = 0; | |
2435 | ||
506f254e ID |
2436 | drm_edid_free(connector->detect_edid); |
2437 | connector->detect_edid = NULL; | |
953ece69 CW |
2438 | } |
2439 | ||
b1ba124d | 2440 | static void |
506f254e | 2441 | intel_hdmi_dp_dual_mode_detect(struct drm_connector *_connector) |
b1ba124d | 2442 | { |
506f254e ID |
2443 | struct intel_connector *connector = to_intel_connector(_connector); |
2444 | struct intel_display *display = to_intel_display(connector); | |
2445 | struct intel_hdmi *hdmi = intel_attached_hdmi(connector); | |
2bea1d7c | 2446 | struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base; |
506f254e | 2447 | struct i2c_adapter *ddc = connector->base.ddc; |
e046d156 VS |
2448 | enum drm_dp_dual_mode_type type; |
2449 | ||
1138137c | 2450 | type = drm_dp_dual_mode_detect(display->drm, ddc); |
b1ba124d | 2451 | |
d6199256 VS |
2452 | /* |
2453 | * Type 1 DVI adaptors are not required to implement any | |
2454 | * registers, so we can't always detect their presence. | |
2455 | * Ideally we should be able to check the state of the | |
2456 | * CONFIG1 pin, but no such luck on our hardware. | |
2457 | * | |
2458 | * The only method left to us is to check the VBT to see | |
6e0fff46 | 2459 | * if the port is a dual mode capable DP port. |
d6199256 VS |
2460 | */ |
2461 | if (type == DRM_DP_DUAL_MODE_UNKNOWN) { | |
506f254e | 2462 | if (!connector->base.force && |
2bea1d7c | 2463 | intel_bios_encoder_supports_dp_dual_mode(encoder->devdata)) { |
1138137c | 2464 | drm_dbg_kms(display->drm, |
41919042 | 2465 | "Assuming DP dual mode adaptor presence based on VBT\n"); |
d6199256 VS |
2466 | type = DRM_DP_DUAL_MODE_TYPE1_DVI; |
2467 | } else { | |
2468 | type = DRM_DP_DUAL_MODE_NONE; | |
2469 | } | |
2470 | } | |
2471 | ||
2472 | if (type == DRM_DP_DUAL_MODE_NONE) | |
b1ba124d VS |
2473 | return; |
2474 | ||
2475 | hdmi->dp_dual_mode.type = type; | |
2476 | hdmi->dp_dual_mode.max_tmds_clock = | |
1138137c | 2477 | drm_dp_dual_mode_max_tmds_clock(display->drm, type, ddc); |
b1ba124d | 2478 | |
1138137c | 2479 | drm_dbg_kms(display->drm, |
41919042 JN |
2480 | "DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n", |
2481 | drm_dp_get_dual_mode_type_name(type), | |
2482 | hdmi->dp_dual_mode.max_tmds_clock); | |
c2696280 VS |
2483 | |
2484 | /* Older VBTs are often buggy and can't be trusted :( Play it safe. */ | |
4a3506d1 | 2485 | if ((DISPLAY_VER(display) >= 8 || display->platform.haswell) && |
2bea1d7c | 2486 | !intel_bios_encoder_supports_dp_dual_mode(encoder->devdata)) { |
1138137c | 2487 | drm_dbg_kms(display->drm, |
c2696280 VS |
2488 | "Ignoring DP dual mode adaptor max TMDS clock for native HDMI port\n"); |
2489 | hdmi->dp_dual_mode.max_tmds_clock = 0; | |
2490 | } | |
b1ba124d VS |
2491 | } |
2492 | ||
953ece69 | 2493 | static bool |
506f254e | 2494 | intel_hdmi_set_edid(struct drm_connector *_connector) |
953ece69 | 2495 | { |
506f254e ID |
2496 | struct intel_connector *connector = to_intel_connector(_connector); |
2497 | struct intel_display *display = to_intel_display(connector); | |
2498 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); | |
2499 | struct i2c_adapter *ddc = connector->base.ddc; | |
0e6e0be4 | 2500 | intel_wakeref_t wakeref; |
25fa6b0f | 2501 | const struct drm_edid *drm_edid; |
953ece69 | 2502 | bool connected = false; |
164c8598 | 2503 | |
5dcfda5c | 2504 | wakeref = intel_display_power_get(display, POWER_DOMAIN_GMBUS); |
671dedd2 | 2505 | |
506f254e | 2506 | drm_edid = drm_edid_read_ddc(&connector->base, ddc); |
cfb926e1 | 2507 | |
30b98ecb | 2508 | if (!drm_edid && !intel_gmbus_is_forced_bit(ddc)) { |
1138137c | 2509 | drm_dbg_kms(display->drm, |
41919042 | 2510 | "HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n"); |
30b98ecb | 2511 | intel_gmbus_force_bit(ddc, true); |
506f254e | 2512 | drm_edid = drm_edid_read_ddc(&connector->base, ddc); |
30b98ecb | 2513 | intel_gmbus_force_bit(ddc, false); |
cfb926e1 | 2514 | } |
2ded9e27 | 2515 | |
25fa6b0f | 2516 | /* Below we depend on display info having been updated */ |
506f254e | 2517 | drm_edid_connector_update(&connector->base, drm_edid); |
25fa6b0f | 2518 | |
506f254e | 2519 | connector->detect_edid = drm_edid; |
25fa6b0f | 2520 | |
e1039cde | 2521 | if (drm_edid_is_digital(drm_edid)) { |
506f254e | 2522 | intel_hdmi_dp_dual_mode_detect(&connector->base); |
6e0fff46 | 2523 | |
953ece69 | 2524 | connected = true; |
55b7d6e8 CW |
2525 | } |
2526 | ||
5dcfda5c | 2527 | intel_display_power_put(display, POWER_DOMAIN_GMBUS, wakeref); |
6e0fff46 | 2528 | |
1bc73448 | 2529 | cec_notifier_set_phys_addr(intel_hdmi->cec_notifier, |
506f254e | 2530 | connector->base.display_info.source_physical_address); |
9c229127 | 2531 | |
953ece69 CW |
2532 | return connected; |
2533 | } | |
2534 | ||
8166fcea | 2535 | static enum drm_connector_status |
506f254e | 2536 | intel_hdmi_detect(struct drm_connector *_connector, bool force) |
953ece69 | 2537 | { |
506f254e ID |
2538 | struct intel_connector *connector = to_intel_connector(_connector); |
2539 | struct intel_display *display = to_intel_display(connector); | |
39d1e234 | 2540 | enum drm_connector_status status = connector_status_disconnected; |
506f254e | 2541 | struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); |
39d1e234 | 2542 | struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base; |
0e6e0be4 | 2543 | intel_wakeref_t wakeref; |
953ece69 | 2544 | |
1138137c | 2545 | drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s]\n", |
506f254e | 2546 | connector->base.base.id, connector->base.name); |
8166fcea | 2547 | |
1a6330df | 2548 | if (!intel_display_device_enabled(display)) |
b81dddb9 VS |
2549 | return connector_status_disconnected; |
2550 | ||
f5d38d4f | 2551 | if (!intel_display_driver_check_access(display)) |
506f254e | 2552 | return connector->base.status; |
bab87ef4 | 2553 | |
5dcfda5c | 2554 | wakeref = intel_display_power_get(display, POWER_DOMAIN_GMBUS); |
29bb94bb | 2555 | |
1138137c | 2556 | if (DISPLAY_VER(display) >= 11 && |
39d1e234 PZ |
2557 | !intel_digital_port_connected(encoder)) |
2558 | goto out; | |
2559 | ||
506f254e | 2560 | intel_hdmi_unset_edid(&connector->base); |
0b5e88dc | 2561 | |
506f254e | 2562 | if (intel_hdmi_set_edid(&connector->base)) |
953ece69 | 2563 | status = connector_status_connected; |
671dedd2 | 2564 | |
39d1e234 | 2565 | out: |
5dcfda5c | 2566 | intel_display_power_put(display, POWER_DOMAIN_GMBUS, wakeref); |
29bb94bb | 2567 | |
9c229127 NA |
2568 | if (status != connector_status_connected) |
2569 | cec_notifier_phys_addr_invalidate(intel_hdmi->cec_notifier); | |
2570 | ||
2ded9e27 | 2571 | return status; |
7d57382e EA |
2572 | } |
2573 | ||
953ece69 | 2574 | static void |
506f254e | 2575 | intel_hdmi_force(struct drm_connector *_connector) |
7d57382e | 2576 | { |
506f254e ID |
2577 | struct intel_connector *connector = to_intel_connector(_connector); |
2578 | struct intel_display *display = to_intel_display(connector); | |
41919042 | 2579 | |
1138137c | 2580 | drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s]\n", |
506f254e | 2581 | connector->base.base.id, connector->base.name); |
7d57382e | 2582 | |
f5d38d4f | 2583 | if (!intel_display_driver_check_access(display)) |
bab87ef4 ID |
2584 | return; |
2585 | ||
506f254e | 2586 | intel_hdmi_unset_edid(&connector->base); |
671dedd2 | 2587 | |
506f254e | 2588 | if (connector->base.status != connector_status_connected) |
953ece69 | 2589 | return; |
671dedd2 | 2590 | |
506f254e | 2591 | intel_hdmi_set_edid(&connector->base); |
953ece69 | 2592 | } |
671dedd2 | 2593 | |
506f254e | 2594 | static int intel_hdmi_get_modes(struct drm_connector *_connector) |
953ece69 | 2595 | { |
506f254e ID |
2596 | struct intel_connector *connector = to_intel_connector(_connector); |
2597 | ||
25fa6b0f | 2598 | /* drm_edid_connector_update() done in ->detect() or ->force() */ |
506f254e | 2599 | return drm_edid_connector_add_modes(&connector->base); |
7d57382e EA |
2600 | } |
2601 | ||
bdc93fe0 | 2602 | static int |
506f254e | 2603 | intel_hdmi_connector_register(struct drm_connector *_connector) |
bdc93fe0 | 2604 | { |
506f254e | 2605 | struct intel_connector *connector = to_intel_connector(_connector); |
bdc93fe0 R |
2606 | int ret; |
2607 | ||
506f254e | 2608 | ret = intel_connector_register(&connector->base); |
bdc93fe0 R |
2609 | if (ret) |
2610 | return ret; | |
2611 | ||
bdc93fe0 R |
2612 | return ret; |
2613 | } | |
2614 | ||
506f254e | 2615 | static void intel_hdmi_connector_unregister(struct drm_connector *_connector) |
7d57382e | 2616 | { |
506f254e ID |
2617 | struct intel_connector *connector = to_intel_connector(_connector); |
2618 | struct cec_notifier *n = intel_attached_hdmi(connector)->cec_notifier; | |
5558f3d5 DM |
2619 | |
2620 | cec_notifier_conn_unregister(n); | |
d4b26e4f | 2621 | |
506f254e | 2622 | intel_connector_unregister(&connector->base); |
7d09888e OV |
2623 | } |
2624 | ||
7d57382e | 2625 | static const struct drm_connector_funcs intel_hdmi_connector_funcs = { |
7d57382e | 2626 | .detect = intel_hdmi_detect, |
953ece69 | 2627 | .force = intel_hdmi_force, |
7d57382e | 2628 | .fill_modes = drm_helper_probe_single_connector_modes, |
7a5ca19f ML |
2629 | .atomic_get_property = intel_digital_connector_atomic_get_property, |
2630 | .atomic_set_property = intel_digital_connector_atomic_set_property, | |
bdc93fe0 | 2631 | .late_register = intel_hdmi_connector_register, |
7d09888e | 2632 | .early_unregister = intel_hdmi_connector_unregister, |
a581483b | 2633 | .destroy = intel_connector_destroy, |
c6f95f27 | 2634 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
7a5ca19f | 2635 | .atomic_duplicate_state = intel_digital_connector_duplicate_state, |
7d57382e EA |
2636 | }; |
2637 | ||
506f254e | 2638 | static int intel_hdmi_connector_atomic_check(struct drm_connector *_connector, |
dafa65d1 VS |
2639 | struct drm_atomic_state *state) |
2640 | { | |
506f254e ID |
2641 | struct intel_connector *connector = to_intel_connector(_connector); |
2642 | struct intel_display *display = to_intel_display(connector); | |
dafa65d1 | 2643 | |
1138137c | 2644 | if (HAS_DDI(display)) |
506f254e | 2645 | return intel_digital_connector_atomic_check(&connector->base, state); |
dafa65d1 | 2646 | else |
506f254e | 2647 | return g4x_hdmi_connector_atomic_check(&connector->base, state); |
dafa65d1 VS |
2648 | } |
2649 | ||
7d57382e EA |
2650 | static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = { |
2651 | .get_modes = intel_hdmi_get_modes, | |
2652 | .mode_valid = intel_hdmi_mode_valid, | |
dafa65d1 | 2653 | .atomic_check = intel_hdmi_connector_atomic_check, |
7d57382e EA |
2654 | }; |
2655 | ||
55b7d6e8 | 2656 | static void |
506f254e | 2657 | intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_connector) |
55b7d6e8 | 2658 | { |
506f254e | 2659 | struct intel_connector *connector = to_intel_connector(_connector); |
1138137c | 2660 | struct intel_display *display = to_intel_display(intel_hdmi); |
f1a12172 | 2661 | |
506f254e ID |
2662 | intel_attach_force_audio_property(&connector->base); |
2663 | intel_attach_broadcast_rgb_property(&connector->base); | |
2664 | intel_attach_aspect_ratio_property(&connector->base); | |
2f146b78 | 2665 | |
506f254e ID |
2666 | intel_attach_hdmi_colorspace_property(&connector->base); |
2667 | drm_connector_attach_content_type_property(&connector->base); | |
f1a12172 | 2668 | |
1138137c | 2669 | if (DISPLAY_VER(display) >= 10) |
506f254e | 2670 | drm_connector_attach_hdr_output_metadata_property(&connector->base); |
b7bedf31 | 2671 | |
1138137c | 2672 | if (!HAS_GMCH(display)) |
506f254e | 2673 | drm_connector_attach_max_bpc_property(&connector->base, 8, 12); |
55b7d6e8 CW |
2674 | } |
2675 | ||
15953637 SS |
2676 | /* |
2677 | * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup | |
2678 | * @encoder: intel_encoder | |
2679 | * @connector: drm_connector | |
2680 | * @high_tmds_clock_ratio = bool to indicate if the function needs to set | |
2681 | * or reset the high tmds clock ratio for scrambling | |
2682 | * @scrambling: bool to Indicate if the function needs to set or reset | |
2683 | * sink scrambling | |
2684 | * | |
2685 | * This function handles scrambling on HDMI 2.0 capable sinks. | |
2686 | * If required clock rate is > 340 Mhz && scrambling is supported by sink | |
2687 | * it enables scrambling. This should be called before enabling the HDMI | |
2688 | * 2.0 port, as the sink can choose to disable the scrambling if it doesn't | |
2689 | * detect a scrambled clock within 100 ms. | |
277ab5ab VS |
2690 | * |
2691 | * Returns: | |
2692 | * True on success, false on failure. | |
15953637 | 2693 | */ |
277ab5ab | 2694 | bool intel_hdmi_handle_sink_scrambling(struct intel_encoder *encoder, |
506f254e | 2695 | struct drm_connector *_connector, |
15953637 SS |
2696 | bool high_tmds_clock_ratio, |
2697 | bool scrambling) | |
2698 | { | |
506f254e | 2699 | struct intel_connector *connector = to_intel_connector(_connector); |
1138137c | 2700 | struct intel_display *display = to_intel_display(encoder); |
15953637 | 2701 | struct drm_scrambling *sink_scrambling = |
506f254e | 2702 | &connector->base.display_info.hdmi.scdc.scrambling; |
15953637 SS |
2703 | |
2704 | if (!sink_scrambling->supported) | |
277ab5ab | 2705 | return true; |
15953637 | 2706 | |
1138137c | 2707 | drm_dbg_kms(display->drm, |
41919042 | 2708 | "[CONNECTOR:%d:%s] scrambling=%s, TMDS bit clock ratio=1/%d\n", |
506f254e | 2709 | connector->base.base.id, connector->base.name, |
01fabda8 | 2710 | str_yes_no(scrambling), high_tmds_clock_ratio ? 40 : 10); |
15953637 | 2711 | |
277ab5ab | 2712 | /* Set TMDS bit clock ratio to 1/40 or 1/10, and enable/disable scrambling */ |
506f254e ID |
2713 | return drm_scdc_set_high_tmds_clock_ratio(&connector->base, high_tmds_clock_ratio) && |
2714 | drm_scdc_set_scrambling(&connector->base, scrambling); | |
15953637 SS |
2715 | } |
2716 | ||
65ea19a6 | 2717 | static u8 chv_encoder_to_ddc_pin(struct intel_encoder *encoder) |
e4ab73a1 | 2718 | { |
65ea19a6 | 2719 | enum port port = encoder->port; |
e4ab73a1 VS |
2720 | u8 ddc_pin; |
2721 | ||
cec3bb01 AS |
2722 | switch (port) { |
2723 | case PORT_B: | |
2724 | ddc_pin = GMBUS_PIN_DPB; | |
2725 | break; | |
2726 | case PORT_C: | |
2727 | ddc_pin = GMBUS_PIN_DPC; | |
2728 | break; | |
2729 | case PORT_D: | |
2730 | ddc_pin = GMBUS_PIN_DPD_CHV; | |
2731 | break; | |
2732 | default: | |
2733 | MISSING_CASE(port); | |
2734 | ddc_pin = GMBUS_PIN_DPB; | |
2735 | break; | |
e4ab73a1 | 2736 | } |
cec3bb01 AS |
2737 | return ddc_pin; |
2738 | } | |
2739 | ||
65ea19a6 | 2740 | static u8 bxt_encoder_to_ddc_pin(struct intel_encoder *encoder) |
cec3bb01 | 2741 | { |
65ea19a6 | 2742 | enum port port = encoder->port; |
cec3bb01 | 2743 | u8 ddc_pin; |
e4ab73a1 VS |
2744 | |
2745 | switch (port) { | |
2746 | case PORT_B: | |
cec3bb01 | 2747 | ddc_pin = GMBUS_PIN_1_BXT; |
e4ab73a1 VS |
2748 | break; |
2749 | case PORT_C: | |
cec3bb01 AS |
2750 | ddc_pin = GMBUS_PIN_2_BXT; |
2751 | break; | |
2752 | default: | |
2753 | MISSING_CASE(port); | |
2754 | ddc_pin = GMBUS_PIN_1_BXT; | |
2755 | break; | |
2756 | } | |
2757 | return ddc_pin; | |
2758 | } | |
2759 | ||
65ea19a6 | 2760 | static u8 cnp_encoder_to_ddc_pin(struct intel_encoder *encoder) |
cec3bb01 | 2761 | { |
65ea19a6 | 2762 | enum port port = encoder->port; |
cec3bb01 AS |
2763 | u8 ddc_pin; |
2764 | ||
2765 | switch (port) { | |
2766 | case PORT_B: | |
2767 | ddc_pin = GMBUS_PIN_1_BXT; | |
2768 | break; | |
2769 | case PORT_C: | |
2770 | ddc_pin = GMBUS_PIN_2_BXT; | |
e4ab73a1 VS |
2771 | break; |
2772 | case PORT_D: | |
cec3bb01 AS |
2773 | ddc_pin = GMBUS_PIN_4_CNP; |
2774 | break; | |
3a2a59cc RV |
2775 | case PORT_F: |
2776 | ddc_pin = GMBUS_PIN_3_BXT; | |
2777 | break; | |
cec3bb01 AS |
2778 | default: |
2779 | MISSING_CASE(port); | |
2780 | ddc_pin = GMBUS_PIN_1_BXT; | |
2781 | break; | |
2782 | } | |
2783 | return ddc_pin; | |
2784 | } | |
2785 | ||
65ea19a6 | 2786 | static u8 icl_encoder_to_ddc_pin(struct intel_encoder *encoder) |
5c749c52 | 2787 | { |
1138137c | 2788 | struct intel_display *display = to_intel_display(encoder); |
65ea19a6 | 2789 | enum port port = encoder->port; |
5c749c52 | 2790 | |
7fcf7558 | 2791 | if (intel_encoder_is_combo(encoder)) |
fb81cbe4 | 2792 | return GMBUS_PIN_1_BXT + port; |
7fcf7558 JN |
2793 | else if (intel_encoder_is_tc(encoder)) |
2794 | return GMBUS_PIN_9_TC1_ICP + intel_encoder_to_tc(encoder); | |
fb81cbe4 | 2795 | |
1138137c | 2796 | drm_WARN(display->drm, 1, "Unknown port:%c\n", port_name(port)); |
fb81cbe4 | 2797 | return GMBUS_PIN_2_BXT; |
5c749c52 AS |
2798 | } |
2799 | ||
65ea19a6 | 2800 | static u8 mcc_encoder_to_ddc_pin(struct intel_encoder *encoder) |
c6f7acb8 | 2801 | { |
7fcf7558 | 2802 | enum phy phy = intel_encoder_to_phy(encoder); |
c6f7acb8 MR |
2803 | u8 ddc_pin; |
2804 | ||
48cf0a1e MR |
2805 | switch (phy) { |
2806 | case PHY_A: | |
c6f7acb8 MR |
2807 | ddc_pin = GMBUS_PIN_1_BXT; |
2808 | break; | |
48cf0a1e | 2809 | case PHY_B: |
c6f7acb8 MR |
2810 | ddc_pin = GMBUS_PIN_2_BXT; |
2811 | break; | |
48cf0a1e | 2812 | case PHY_C: |
c6f7acb8 MR |
2813 | ddc_pin = GMBUS_PIN_9_TC1_ICP; |
2814 | break; | |
2815 | default: | |
48cf0a1e | 2816 | MISSING_CASE(phy); |
c6f7acb8 MR |
2817 | ddc_pin = GMBUS_PIN_1_BXT; |
2818 | break; | |
2819 | } | |
2820 | return ddc_pin; | |
2821 | } | |
2822 | ||
65ea19a6 | 2823 | static u8 rkl_encoder_to_ddc_pin(struct intel_encoder *encoder) |
cd0a8952 | 2824 | { |
4e9b0ac1 | 2825 | struct intel_display *display = to_intel_display(encoder); |
7fcf7558 | 2826 | enum phy phy = intel_encoder_to_phy(encoder); |
cd0a8952 | 2827 | |
7fcf7558 | 2828 | WARN_ON(encoder->port == PORT_C); |
cd0a8952 MR |
2829 | |
2830 | /* | |
2831 | * Pin mapping for RKL depends on which PCH is present. With TGP, the | |
2832 | * final two outputs use type-c pins, even though they're actually | |
2833 | * combo outputs. With CMP, the traditional DDI A-D pins are used for | |
2834 | * all outputs. | |
2835 | */ | |
4e9b0ac1 | 2836 | if (INTEL_PCH_TYPE(display) >= PCH_TGP && phy >= PHY_C) |
cd0a8952 MR |
2837 | return GMBUS_PIN_9_TC1_ICP + phy - PHY_C; |
2838 | ||
2839 | return GMBUS_PIN_1_BXT + phy; | |
2840 | } | |
2841 | ||
65ea19a6 | 2842 | static u8 gen9bc_tgp_encoder_to_ddc_pin(struct intel_encoder *encoder) |
d2063080 | 2843 | { |
1138137c | 2844 | struct intel_display *display = to_intel_display(encoder); |
7fcf7558 | 2845 | enum phy phy = intel_encoder_to_phy(encoder); |
d2063080 | 2846 | |
1138137c | 2847 | drm_WARN_ON(display->drm, encoder->port == PORT_A); |
d2063080 LP |
2848 | |
2849 | /* | |
2850 | * Pin mapping for GEN9 BC depends on which PCH is present. With TGP, | |
2851 | * final two outputs use type-c pins, even though they're actually | |
2852 | * combo outputs. With CMP, the traditional DDI A-D pins are used for | |
2853 | * all outputs. | |
2854 | */ | |
4e9b0ac1 | 2855 | if (INTEL_PCH_TYPE(display) >= PCH_TGP && phy >= PHY_C) |
d2063080 LP |
2856 | return GMBUS_PIN_9_TC1_ICP + phy - PHY_C; |
2857 | ||
2858 | return GMBUS_PIN_1_BXT + phy; | |
2859 | } | |
2860 | ||
65ea19a6 | 2861 | static u8 dg1_encoder_to_ddc_pin(struct intel_encoder *encoder) |
fb7318c3 | 2862 | { |
7fcf7558 | 2863 | return intel_encoder_to_phy(encoder) + 1; |
fb7318c3 LDM |
2864 | } |
2865 | ||
65ea19a6 | 2866 | static u8 adls_encoder_to_ddc_pin(struct intel_encoder *encoder) |
7dc1f92f | 2867 | { |
7fcf7558 | 2868 | enum phy phy = intel_encoder_to_phy(encoder); |
7dc1f92f | 2869 | |
7fcf7558 | 2870 | WARN_ON(encoder->port == PORT_B || encoder->port == PORT_C); |
7dc1f92f AS |
2871 | |
2872 | /* | |
2873 | * Pin mapping for ADL-S requires TC pins for all combo phy outputs | |
2874 | * except first combo output. | |
2875 | */ | |
2876 | if (phy == PHY_A) | |
2877 | return GMBUS_PIN_1_BXT; | |
2878 | ||
2879 | return GMBUS_PIN_9_TC1_ICP + phy - PHY_B; | |
2880 | } | |
2881 | ||
65ea19a6 | 2882 | static u8 g4x_encoder_to_ddc_pin(struct intel_encoder *encoder) |
cec3bb01 | 2883 | { |
65ea19a6 | 2884 | enum port port = encoder->port; |
cec3bb01 AS |
2885 | u8 ddc_pin; |
2886 | ||
2887 | switch (port) { | |
2888 | case PORT_B: | |
2889 | ddc_pin = GMBUS_PIN_DPB; | |
2890 | break; | |
2891 | case PORT_C: | |
2892 | ddc_pin = GMBUS_PIN_DPC; | |
2893 | break; | |
2894 | case PORT_D: | |
2895 | ddc_pin = GMBUS_PIN_DPD; | |
e4ab73a1 VS |
2896 | break; |
2897 | default: | |
2898 | MISSING_CASE(port); | |
2899 | ddc_pin = GMBUS_PIN_DPB; | |
2900 | break; | |
2901 | } | |
cec3bb01 AS |
2902 | return ddc_pin; |
2903 | } | |
2904 | ||
49d4648b | 2905 | static u8 intel_hdmi_default_ddc_pin(struct intel_encoder *encoder) |
cec3bb01 | 2906 | { |
1138137c | 2907 | struct intel_display *display = to_intel_display(encoder); |
cec3bb01 AS |
2908 | u8 ddc_pin; |
2909 | ||
4a3506d1 | 2910 | if (display->platform.alderlake_s) |
65ea19a6 | 2911 | ddc_pin = adls_encoder_to_ddc_pin(encoder); |
4e9b0ac1 | 2912 | else if (INTEL_PCH_TYPE(display) >= PCH_DG1) |
65ea19a6 | 2913 | ddc_pin = dg1_encoder_to_ddc_pin(encoder); |
4a3506d1 | 2914 | else if (display->platform.rocketlake) |
65ea19a6 | 2915 | ddc_pin = rkl_encoder_to_ddc_pin(encoder); |
4e9b0ac1 | 2916 | else if (DISPLAY_VER(display) == 9 && HAS_PCH_TGP(display)) |
65ea19a6 | 2917 | ddc_pin = gen9bc_tgp_encoder_to_ddc_pin(encoder); |
4a3506d1 | 2918 | else if ((display->platform.jasperlake || display->platform.elkhartlake) && |
4e9b0ac1 | 2919 | HAS_PCH_TGP(display)) |
65ea19a6 | 2920 | ddc_pin = mcc_encoder_to_ddc_pin(encoder); |
4e9b0ac1 | 2921 | else if (INTEL_PCH_TYPE(display) >= PCH_ICP) |
65ea19a6 | 2922 | ddc_pin = icl_encoder_to_ddc_pin(encoder); |
4e9b0ac1 | 2923 | else if (HAS_PCH_CNP(display)) |
65ea19a6 | 2924 | ddc_pin = cnp_encoder_to_ddc_pin(encoder); |
4a3506d1 | 2925 | else if (display->platform.geminilake || display->platform.broxton) |
65ea19a6 | 2926 | ddc_pin = bxt_encoder_to_ddc_pin(encoder); |
4a3506d1 | 2927 | else if (display->platform.cherryview) |
65ea19a6 | 2928 | ddc_pin = chv_encoder_to_ddc_pin(encoder); |
cec3bb01 | 2929 | else |
65ea19a6 | 2930 | ddc_pin = g4x_encoder_to_ddc_pin(encoder); |
e4ab73a1 | 2931 | |
49d4648b VS |
2932 | return ddc_pin; |
2933 | } | |
2934 | ||
2935 | static struct intel_encoder * | |
2936 | get_encoder_by_ddc_pin(struct intel_encoder *encoder, u8 ddc_pin) | |
2937 | { | |
1138137c | 2938 | struct intel_display *display = to_intel_display(encoder); |
49d4648b VS |
2939 | struct intel_encoder *other; |
2940 | ||
1138137c | 2941 | for_each_intel_encoder(display->drm, other) { |
ac6dcb63 VS |
2942 | struct intel_connector *connector; |
2943 | ||
49d4648b VS |
2944 | if (other == encoder) |
2945 | continue; | |
2946 | ||
2947 | if (!intel_encoder_is_dig_port(other)) | |
2948 | continue; | |
2949 | ||
ac6dcb63 VS |
2950 | connector = enc_to_dig_port(other)->hdmi.attached_connector; |
2951 | ||
fdc38738 | 2952 | if (connector && connector->base.ddc == intel_gmbus_get_adapter(display, ddc_pin)) |
49d4648b VS |
2953 | return other; |
2954 | } | |
2955 | ||
2956 | return NULL; | |
2957 | } | |
2958 | ||
2959 | static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder) | |
2960 | { | |
1138137c | 2961 | struct intel_display *display = to_intel_display(encoder); |
49d4648b VS |
2962 | struct intel_encoder *other; |
2963 | const char *source; | |
2964 | u8 ddc_pin; | |
2965 | ||
2966 | ddc_pin = intel_bios_hdmi_ddc_pin(encoder->devdata); | |
2967 | source = "VBT"; | |
2968 | ||
2969 | if (!ddc_pin) { | |
2970 | ddc_pin = intel_hdmi_default_ddc_pin(encoder); | |
2971 | source = "platform default"; | |
2972 | } | |
2973 | ||
fdc38738 | 2974 | if (!intel_gmbus_is_valid_pin(display, ddc_pin)) { |
1138137c JN |
2975 | drm_dbg_kms(display->drm, |
2976 | "[ENCODER:%d:%s] Invalid DDC pin %d\n", | |
49d4648b VS |
2977 | encoder->base.base.id, encoder->base.name, ddc_pin); |
2978 | return 0; | |
2979 | } | |
2980 | ||
2981 | other = get_encoder_by_ddc_pin(encoder, ddc_pin); | |
2982 | if (other) { | |
1138137c JN |
2983 | drm_dbg_kms(display->drm, |
2984 | "[ENCODER:%d:%s] DDC pin %d already claimed by [ENCODER:%d:%s]\n", | |
49d4648b VS |
2985 | encoder->base.base.id, encoder->base.name, ddc_pin, |
2986 | other->base.base.id, other->base.name); | |
2987 | return 0; | |
2988 | } | |
2989 | ||
1138137c | 2990 | drm_dbg_kms(display->drm, |
49d4648b | 2991 | "[ENCODER:%d:%s] Using DDC pin 0x%x (%s)\n", |
fce187ca | 2992 | encoder->base.base.id, encoder->base.name, |
49d4648b | 2993 | ddc_pin, source); |
e4ab73a1 VS |
2994 | |
2995 | return ddc_pin; | |
2996 | } | |
2997 | ||
7801f3b7 | 2998 | void intel_infoframe_init(struct intel_digital_port *dig_port) |
385e4de0 | 2999 | { |
1138137c | 3000 | struct intel_display *display = to_intel_display(dig_port); |
385e4de0 | 3001 | |
4a3506d1 | 3002 | if (display->platform.valleyview || display->platform.cherryview) { |
7801f3b7 LDM |
3003 | dig_port->write_infoframe = vlv_write_infoframe; |
3004 | dig_port->read_infoframe = vlv_read_infoframe; | |
3005 | dig_port->set_infoframes = vlv_set_infoframes; | |
3006 | dig_port->infoframes_enabled = vlv_infoframes_enabled; | |
4a3506d1 | 3007 | } else if (display->platform.g4x) { |
7801f3b7 LDM |
3008 | dig_port->write_infoframe = g4x_write_infoframe; |
3009 | dig_port->read_infoframe = g4x_read_infoframe; | |
3010 | dig_port->set_infoframes = g4x_set_infoframes; | |
3011 | dig_port->infoframes_enabled = g4x_infoframes_enabled; | |
1138137c | 3012 | } else if (HAS_DDI(display)) { |
db5d650f | 3013 | if (intel_bios_encoder_is_lspcon(dig_port->base.devdata)) { |
7801f3b7 LDM |
3014 | dig_port->write_infoframe = lspcon_write_infoframe; |
3015 | dig_port->read_infoframe = lspcon_read_infoframe; | |
3016 | dig_port->set_infoframes = lspcon_set_infoframes; | |
3017 | dig_port->infoframes_enabled = lspcon_infoframes_enabled; | |
06c812d7 | 3018 | } else { |
7801f3b7 LDM |
3019 | dig_port->write_infoframe = hsw_write_infoframe; |
3020 | dig_port->read_infoframe = hsw_read_infoframe; | |
3021 | dig_port->set_infoframes = hsw_set_infoframes; | |
3022 | dig_port->infoframes_enabled = hsw_infoframes_enabled; | |
06c812d7 | 3023 | } |
4e9b0ac1 | 3024 | } else if (HAS_PCH_IBX(display)) { |
7801f3b7 LDM |
3025 | dig_port->write_infoframe = ibx_write_infoframe; |
3026 | dig_port->read_infoframe = ibx_read_infoframe; | |
3027 | dig_port->set_infoframes = ibx_set_infoframes; | |
3028 | dig_port->infoframes_enabled = ibx_infoframes_enabled; | |
385e4de0 | 3029 | } else { |
7801f3b7 LDM |
3030 | dig_port->write_infoframe = cpt_write_infoframe; |
3031 | dig_port->read_infoframe = cpt_read_infoframe; | |
3032 | dig_port->set_infoframes = cpt_set_infoframes; | |
3033 | dig_port->infoframes_enabled = cpt_infoframes_enabled; | |
385e4de0 VS |
3034 | } |
3035 | } | |
3036 | ||
7fb56536 | 3037 | bool intel_hdmi_init_connector(struct intel_digital_port *dig_port, |
00c09d70 | 3038 | struct intel_connector *intel_connector) |
7d57382e | 3039 | { |
1138137c | 3040 | struct intel_display *display = to_intel_display(dig_port); |
b9cb234c | 3041 | struct drm_connector *connector = &intel_connector->base; |
7801f3b7 LDM |
3042 | struct intel_hdmi *intel_hdmi = &dig_port->hdmi; |
3043 | struct intel_encoder *intel_encoder = &dig_port->base; | |
b9cb234c | 3044 | struct drm_device *dev = intel_encoder->base.dev; |
8f4f2797 | 3045 | enum port port = intel_encoder->port; |
5558f3d5 | 3046 | struct cec_connector_info conn_info; |
ac6dcb63 | 3047 | u8 ddc_pin; |
373a3cf7 | 3048 | |
1138137c | 3049 | drm_dbg_kms(display->drm, |
41919042 JN |
3050 | "Adding HDMI connector on [ENCODER:%d:%s]\n", |
3051 | intel_encoder->base.base.id, intel_encoder->base.name); | |
22f35042 | 3052 | |
1138137c | 3053 | if (DISPLAY_VER(display) < 12 && drm_WARN_ON(dev, port == PORT_A)) |
7fb56536 | 3054 | return false; |
d6707194 | 3055 | |
7801f3b7 | 3056 | if (drm_WARN(dev, dig_port->max_lanes < 4, |
10d4e146 | 3057 | "Not enough lanes (%d) for HDMI on [ENCODER:%d:%s]\n", |
7801f3b7 | 3058 | dig_port->max_lanes, intel_encoder->base.base.id, |
10d4e146 | 3059 | intel_encoder->base.name)) |
7fb56536 | 3060 | return false; |
ccb1a831 | 3061 | |
ac6dcb63 VS |
3062 | ddc_pin = intel_hdmi_ddc_pin(intel_encoder); |
3063 | if (!ddc_pin) | |
7fb56536 | 3064 | return false; |
49d4648b | 3065 | |
c360824a AP |
3066 | drm_connector_init_with_ddc(dev, connector, |
3067 | &intel_hdmi_connector_funcs, | |
3068 | DRM_MODE_CONNECTOR_HDMIA, | |
fdc38738 | 3069 | intel_gmbus_get_adapter(display, ddc_pin)); |
e046d156 | 3070 | |
7d57382e EA |
3071 | drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); |
3072 | ||
1138137c | 3073 | if (DISPLAY_VER(display) < 12) |
f71c9b7b AN |
3074 | connector->interlace_allowed = true; |
3075 | ||
8648c604 | 3076 | connector->stereo_allowed = true; |
66a9278e | 3077 | |
1138137c | 3078 | if (DISPLAY_VER(display) >= 10) |
eadc2e51 SS |
3079 | connector->ycbcr_420_allowed = true; |
3080 | ||
5fb908eb | 3081 | intel_connector->polled = DRM_CONNECTOR_POLL_HPD; |
289d4180 | 3082 | intel_connector->base.polled = intel_connector->polled; |
7d57382e | 3083 | |
1138137c | 3084 | if (HAS_DDI(display)) |
bcbc889b PZ |
3085 | intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; |
3086 | else | |
3087 | intel_connector->get_hw_state = intel_connector_get_hw_state; | |
b9cb234c PZ |
3088 | |
3089 | intel_hdmi_add_properties(intel_hdmi, connector); | |
3090 | ||
04707f97 R |
3091 | intel_connector_attach_encoder(intel_connector, intel_encoder); |
3092 | intel_hdmi->attached_connector = intel_connector; | |
3093 | ||
c214fc98 | 3094 | if (is_hdcp_supported(display, port)) { |
29b283a4 | 3095 | int ret = intel_hdcp_init(intel_connector, dig_port, |
2320175f SP |
3096 | &intel_hdmi_hdcp_shim); |
3097 | if (ret) | |
1138137c | 3098 | drm_dbg_kms(display->drm, |
41919042 | 3099 | "HDCP init failed, skipping.\n"); |
2320175f SP |
3100 | } |
3101 | ||
5558f3d5 DM |
3102 | cec_fill_conn_info_from_drm(&conn_info, connector); |
3103 | ||
3104 | intel_hdmi->cec_notifier = | |
3105 | cec_notifier_conn_register(dev->dev, port_identifier(port), | |
3106 | &conn_info); | |
9c229127 | 3107 | if (!intel_hdmi->cec_notifier) |
1138137c | 3108 | drm_dbg_kms(display->drm, "CEC notifier get failed\n"); |
7fb56536 JN |
3109 | |
3110 | return true; | |
b9cb234c PZ |
3111 | } |
3112 | ||
6e6cb758 AN |
3113 | /* |
3114 | * intel_hdmi_dsc_get_slice_height - get the dsc slice_height | |
3115 | * @vactive: Vactive of a display mode | |
3116 | * | |
3117 | * @return: appropriate dsc slice height for a given mode. | |
3118 | */ | |
3119 | int intel_hdmi_dsc_get_slice_height(int vactive) | |
3120 | { | |
3121 | int slice_height; | |
3122 | ||
3123 | /* | |
3124 | * Slice Height determination : HDMI2.1 Section 7.7.5.2 | |
3125 | * Select smallest slice height >=96, that results in a valid PPS and | |
3126 | * requires minimum padding lines required for final slice. | |
3127 | * | |
3128 | * Assumption : Vactive is even. | |
3129 | */ | |
3130 | for (slice_height = 96; slice_height <= vactive; slice_height += 2) | |
3131 | if (vactive % slice_height == 0) | |
3132 | return slice_height; | |
3133 | ||
3134 | return 0; | |
3135 | } | |
3136 | ||
3137 | /* | |
3138 | * intel_hdmi_dsc_get_num_slices - get no. of dsc slices based on dsc encoder | |
3139 | * and dsc decoder capabilities | |
3140 | * | |
3141 | * @crtc_state: intel crtc_state | |
3142 | * @src_max_slices: maximum slices supported by the DSC encoder | |
3143 | * @src_max_slice_width: maximum slice width supported by DSC encoder | |
3144 | * @hdmi_max_slices: maximum slices supported by sink DSC decoder | |
3145 | * @hdmi_throughput: maximum clock per slice (MHz) supported by HDMI sink | |
3146 | * | |
3147 | * @return: num of dsc slices that can be supported by the dsc encoder | |
3148 | * and decoder. | |
3149 | */ | |
3150 | int | |
3151 | intel_hdmi_dsc_get_num_slices(const struct intel_crtc_state *crtc_state, | |
3152 | int src_max_slices, int src_max_slice_width, | |
3153 | int hdmi_max_slices, int hdmi_throughput) | |
3154 | { | |
3155 | /* Pixel rates in KPixels/sec */ | |
3156 | #define HDMI_DSC_PEAK_PIXEL_RATE 2720000 | |
3157 | /* | |
3158 | * Rates at which the source and sink are required to process pixels in each | |
3159 | * slice, can be two levels: either atleast 340000KHz or atleast 40000KHz. | |
3160 | */ | |
3161 | #define HDMI_DSC_MAX_ENC_THROUGHPUT_0 340000 | |
3162 | #define HDMI_DSC_MAX_ENC_THROUGHPUT_1 400000 | |
3163 | ||
3164 | /* Spec limits the slice width to 2720 pixels */ | |
3165 | #define MAX_HDMI_SLICE_WIDTH 2720 | |
3166 | int kslice_adjust; | |
3167 | int adjusted_clk_khz; | |
3168 | int min_slices; | |
3169 | int target_slices; | |
3170 | int max_throughput; /* max clock freq. in khz per slice */ | |
3171 | int max_slice_width; | |
3172 | int slice_width; | |
3173 | int pixel_clock = crtc_state->hw.adjusted_mode.crtc_clock; | |
3174 | ||
3175 | if (!hdmi_throughput) | |
3176 | return 0; | |
3177 | ||
3178 | /* | |
3179 | * Slice Width determination : HDMI2.1 Section 7.7.5.1 | |
3180 | * kslice_adjust factor for 4:2:0, and 4:2:2 formats is 0.5, where as | |
3181 | * for 4:4:4 is 1.0. Multiplying these factors by 10 and later | |
3182 | * dividing adjusted clock value by 10. | |
3183 | */ | |
3184 | if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444 || | |
3185 | crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB) | |
3186 | kslice_adjust = 10; | |
3187 | else | |
3188 | kslice_adjust = 5; | |
3189 | ||
3190 | /* | |
3191 | * As per spec, the rate at which the source and the sink process | |
3192 | * the pixels per slice are at two levels: atleast 340Mhz or 400Mhz. | |
3193 | * This depends upon the pixel clock rate and output formats | |
3194 | * (kslice adjust). | |
3195 | * If pixel clock * kslice adjust >= 2720MHz slices can be processed | |
3196 | * at max 340MHz, otherwise they can be processed at max 400MHz. | |
3197 | */ | |
3198 | ||
3199 | adjusted_clk_khz = DIV_ROUND_UP(kslice_adjust * pixel_clock, 10); | |
3200 | ||
3201 | if (adjusted_clk_khz <= HDMI_DSC_PEAK_PIXEL_RATE) | |
3202 | max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_0; | |
3203 | else | |
3204 | max_throughput = HDMI_DSC_MAX_ENC_THROUGHPUT_1; | |
3205 | ||
3206 | /* | |
3207 | * Taking into account the sink's capability for maximum | |
3208 | * clock per slice (in MHz) as read from HF-VSDB. | |
3209 | */ | |
3210 | max_throughput = min(max_throughput, hdmi_throughput * 1000); | |
3211 | ||
3212 | min_slices = DIV_ROUND_UP(adjusted_clk_khz, max_throughput); | |
3213 | max_slice_width = min(MAX_HDMI_SLICE_WIDTH, src_max_slice_width); | |
3214 | ||
3215 | /* | |
3216 | * Keep on increasing the num of slices/line, starting from min_slices | |
3217 | * per line till we get such a number, for which the slice_width is | |
3218 | * just less than max_slice_width. The slices/line selected should be | |
3219 | * less than or equal to the max horizontal slices that the combination | |
3220 | * of PCON encoder and HDMI decoder can support. | |
3221 | */ | |
3222 | slice_width = max_slice_width; | |
3223 | ||
3224 | do { | |
3225 | if (min_slices <= 1 && src_max_slices >= 1 && hdmi_max_slices >= 1) | |
3226 | target_slices = 1; | |
3227 | else if (min_slices <= 2 && src_max_slices >= 2 && hdmi_max_slices >= 2) | |
3228 | target_slices = 2; | |
3229 | else if (min_slices <= 4 && src_max_slices >= 4 && hdmi_max_slices >= 4) | |
3230 | target_slices = 4; | |
3231 | else if (min_slices <= 8 && src_max_slices >= 8 && hdmi_max_slices >= 8) | |
3232 | target_slices = 8; | |
3233 | else if (min_slices <= 12 && src_max_slices >= 12 && hdmi_max_slices >= 12) | |
3234 | target_slices = 12; | |
3235 | else if (min_slices <= 16 && src_max_slices >= 16 && hdmi_max_slices >= 16) | |
3236 | target_slices = 16; | |
3237 | else | |
3238 | return 0; | |
3239 | ||
3240 | slice_width = DIV_ROUND_UP(crtc_state->hw.adjusted_mode.hdisplay, target_slices); | |
3241 | if (slice_width >= max_slice_width) | |
3242 | min_slices = target_slices + 1; | |
3243 | } while (slice_width >= max_slice_width); | |
3244 | ||
3245 | return target_slices; | |
3246 | } | |
3247 | ||
3248 | /* | |
3249 | * intel_hdmi_dsc_get_bpp - get the appropriate compressed bits_per_pixel based on | |
3250 | * source and sink capabilities. | |
3251 | * | |
3252 | * @src_fraction_bpp: fractional bpp supported by the source | |
3253 | * @slice_width: dsc slice width supported by the source and sink | |
3254 | * @num_slices: num of slices supported by the source and sink | |
3255 | * @output_format: video output format | |
3256 | * @hdmi_all_bpp: sink supports decoding of 1/16th bpp setting | |
3257 | * @hdmi_max_chunk_bytes: max bytes in a line of chunks supported by sink | |
3258 | * | |
3259 | * @return: compressed bits_per_pixel in step of 1/16 of bits_per_pixel | |
3260 | */ | |
3261 | int | |
3262 | intel_hdmi_dsc_get_bpp(int src_fractional_bpp, int slice_width, int num_slices, | |
3263 | int output_format, bool hdmi_all_bpp, | |
3264 | int hdmi_max_chunk_bytes) | |
3265 | { | |
3266 | int max_dsc_bpp, min_dsc_bpp; | |
3267 | int target_bytes; | |
3268 | bool bpp_found = false; | |
3269 | int bpp_decrement_x16; | |
3270 | int bpp_target; | |
3271 | int bpp_target_x16; | |
3272 | ||
3273 | /* | |
3274 | * Get min bpp and max bpp as per Table 7.23, in HDMI2.1 spec | |
3275 | * Start with the max bpp and keep on decrementing with | |
3276 | * fractional bpp, if supported by PCON DSC encoder | |
3277 | * | |
3278 | * for each bpp we check if no of bytes can be supported by HDMI sink | |
3279 | */ | |
3280 | ||
3281 | /* Assuming: bpc as 8*/ | |
3282 | if (output_format == INTEL_OUTPUT_FORMAT_YCBCR420) { | |
3283 | min_dsc_bpp = 6; | |
3284 | max_dsc_bpp = 3 * 4; /* 3*bpc/2 */ | |
3285 | } else if (output_format == INTEL_OUTPUT_FORMAT_YCBCR444 || | |
3286 | output_format == INTEL_OUTPUT_FORMAT_RGB) { | |
3287 | min_dsc_bpp = 8; | |
3288 | max_dsc_bpp = 3 * 8; /* 3*bpc */ | |
3289 | } else { | |
3290 | /* Assuming 4:2:2 encoding */ | |
3291 | min_dsc_bpp = 7; | |
3292 | max_dsc_bpp = 2 * 8; /* 2*bpc */ | |
3293 | } | |
3294 | ||
3295 | /* | |
3296 | * Taking into account if all dsc_all_bpp supported by HDMI2.1 sink | |
3297 | * Section 7.7.34 : Source shall not enable compressed Video | |
3298 | * Transport with bpp_target settings above 12 bpp unless | |
3299 | * DSC_all_bpp is set to 1. | |
3300 | */ | |
3301 | if (!hdmi_all_bpp) | |
3302 | max_dsc_bpp = min(max_dsc_bpp, 12); | |
3303 | ||
3304 | /* | |
3305 | * The Sink has a limit of compressed data in bytes for a scanline, | |
3306 | * as described in max_chunk_bytes field in HFVSDB block of edid. | |
3307 | * The no. of bytes depend on the target bits per pixel that the | |
3308 | * source configures. So we start with the max_bpp and calculate | |
3309 | * the target_chunk_bytes. We keep on decrementing the target_bpp, | |
3310 | * till we get the target_chunk_bytes just less than what the sink's | |
3311 | * max_chunk_bytes, or else till we reach the min_dsc_bpp. | |
3312 | * | |
3313 | * The decrement is according to the fractional support from PCON DSC | |
3314 | * encoder. For fractional BPP we use bpp_target as a multiple of 16. | |
3315 | * | |
3316 | * bpp_target_x16 = bpp_target * 16 | |
3317 | * So we need to decrement by {1, 2, 4, 8, 16} for fractional bpps | |
3318 | * {1/16, 1/8, 1/4, 1/2, 1} respectively. | |
3319 | */ | |
3320 | ||
3321 | bpp_target = max_dsc_bpp; | |
3322 | ||
3323 | /* src does not support fractional bpp implies decrement by 16 for bppx16 */ | |
3324 | if (!src_fractional_bpp) | |
3325 | src_fractional_bpp = 1; | |
3326 | bpp_decrement_x16 = DIV_ROUND_UP(16, src_fractional_bpp); | |
3327 | bpp_target_x16 = (bpp_target * 16) - bpp_decrement_x16; | |
3328 | ||
3329 | while (bpp_target_x16 > (min_dsc_bpp * 16)) { | |
3330 | int bpp; | |
3331 | ||
3332 | bpp = DIV_ROUND_UP(bpp_target_x16, 16); | |
3333 | target_bytes = DIV_ROUND_UP((num_slices * slice_width * bpp), 8); | |
3334 | if (target_bytes <= hdmi_max_chunk_bytes) { | |
3335 | bpp_found = true; | |
3336 | break; | |
3337 | } | |
3338 | bpp_target_x16 -= bpp_decrement_x16; | |
3339 | } | |
3340 | if (bpp_found) | |
3341 | return bpp_target_x16; | |
3342 | ||
3343 | return 0; | |
3344 | } |