Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2016 Intel Corporation
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0020  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0021  * DEALINGS IN THE SOFTWARE.
0022  *
0023  *
0024  */
0025 
0026 #include <drm/display/drm_dp_dual_mode_helper.h>
0027 #include <drm/display/drm_hdmi_helper.h>
0028 #include <drm/drm_atomic_helper.h>
0029 #include <drm/drm_edid.h>
0030 
0031 #include "intel_de.h"
0032 #include "intel_display_types.h"
0033 #include "intel_dp.h"
0034 #include "intel_lspcon.h"
0035 #include "intel_hdmi.h"
0036 
0037 /* LSPCON OUI Vendor ID(signatures) */
0038 #define LSPCON_VENDOR_PARADE_OUI 0x001CF8
0039 #define LSPCON_VENDOR_MCA_OUI 0x0060AD
0040 
0041 #define DPCD_MCA_LSPCON_HDR_STATUS  0x70003
0042 #define DPCD_PARADE_LSPCON_HDR_STATUS   0x00511
0043 
0044 /* AUX addresses to write MCA AVI IF */
0045 #define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
0046 #define LSPCON_MCA_AVI_IF_CTRL 0x5DF
0047 #define  LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
0048 #define  LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
0049 
0050 /* AUX addresses to write Parade AVI IF */
0051 #define LSPCON_PARADE_AVI_IF_WRITE_OFFSET 0x516
0052 #define LSPCON_PARADE_AVI_IF_CTRL 0x51E
0053 #define  LSPCON_PARADE_AVI_IF_KICKOFF (1 << 7)
0054 #define LSPCON_PARADE_AVI_IF_DATA_SIZE 32
0055 
0056 static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
0057 {
0058     struct intel_digital_port *dig_port =
0059         container_of(lspcon, struct intel_digital_port, lspcon);
0060 
0061     return &dig_port->dp;
0062 }
0063 
0064 static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
0065 {
0066     switch (mode) {
0067     case DRM_LSPCON_MODE_PCON:
0068         return "PCON";
0069     case DRM_LSPCON_MODE_LS:
0070         return "LS";
0071     case DRM_LSPCON_MODE_INVALID:
0072         return "INVALID";
0073     default:
0074         MISSING_CASE(mode);
0075         return "INVALID";
0076     }
0077 }
0078 
0079 static bool lspcon_detect_vendor(struct intel_lspcon *lspcon)
0080 {
0081     struct intel_dp *dp = lspcon_to_intel_dp(lspcon);
0082     struct drm_i915_private *i915 = dp_to_i915(dp);
0083     struct drm_dp_dpcd_ident *ident;
0084     u32 vendor_oui;
0085 
0086     if (drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd))) {
0087         drm_err(&i915->drm, "Can't read description\n");
0088         return false;
0089     }
0090 
0091     ident = &dp->desc.ident;
0092     vendor_oui = (ident->oui[0] << 16) | (ident->oui[1] << 8) |
0093               ident->oui[2];
0094 
0095     switch (vendor_oui) {
0096     case LSPCON_VENDOR_MCA_OUI:
0097         lspcon->vendor = LSPCON_VENDOR_MCA;
0098         drm_dbg_kms(&i915->drm, "Vendor: Mega Chips\n");
0099         break;
0100 
0101     case LSPCON_VENDOR_PARADE_OUI:
0102         lspcon->vendor = LSPCON_VENDOR_PARADE;
0103         drm_dbg_kms(&i915->drm, "Vendor: Parade Tech\n");
0104         break;
0105 
0106     default:
0107         drm_err(&i915->drm, "Invalid/Unknown vendor OUI\n");
0108         return false;
0109     }
0110 
0111     return true;
0112 }
0113 
0114 static u32 get_hdr_status_reg(struct intel_lspcon *lspcon)
0115 {
0116     if (lspcon->vendor == LSPCON_VENDOR_MCA)
0117         return DPCD_MCA_LSPCON_HDR_STATUS;
0118     else
0119         return DPCD_PARADE_LSPCON_HDR_STATUS;
0120 }
0121 
0122 void lspcon_detect_hdr_capability(struct intel_lspcon *lspcon)
0123 {
0124     struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
0125     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0126     u8 hdr_caps;
0127     int ret;
0128 
0129     ret = drm_dp_dpcd_read(&intel_dp->aux, get_hdr_status_reg(lspcon),
0130                    &hdr_caps, 1);
0131 
0132     if (ret < 0) {
0133         drm_dbg_kms(&i915->drm, "HDR capability detection failed\n");
0134         lspcon->hdr_supported = false;
0135     } else if (hdr_caps & 0x1) {
0136         drm_dbg_kms(&i915->drm, "LSPCON capable of HDR\n");
0137         lspcon->hdr_supported = true;
0138     }
0139 }
0140 
0141 static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
0142 {
0143     struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
0144     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0145     enum drm_lspcon_mode current_mode;
0146     struct i2c_adapter *adapter = &intel_dp->aux.ddc;
0147 
0148     if (drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, &current_mode)) {
0149         drm_dbg_kms(&i915->drm, "Error reading LSPCON mode\n");
0150         return DRM_LSPCON_MODE_INVALID;
0151     }
0152     return current_mode;
0153 }
0154 
0155 static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon,
0156                          enum drm_lspcon_mode mode)
0157 {
0158     struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
0159     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0160     enum drm_lspcon_mode current_mode;
0161 
0162     current_mode = lspcon_get_current_mode(lspcon);
0163     if (current_mode == mode)
0164         goto out;
0165 
0166     drm_dbg_kms(&i915->drm, "Waiting for LSPCON mode %s to settle\n",
0167             lspcon_mode_name(mode));
0168 
0169     wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, 400);
0170     if (current_mode != mode)
0171         drm_err(&i915->drm, "LSPCON mode hasn't settled\n");
0172 
0173 out:
0174     drm_dbg_kms(&i915->drm, "Current LSPCON mode %s\n",
0175             lspcon_mode_name(current_mode));
0176 
0177     return current_mode;
0178 }
0179 
0180 static int lspcon_change_mode(struct intel_lspcon *lspcon,
0181                   enum drm_lspcon_mode mode)
0182 {
0183     struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
0184     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0185     int err;
0186     enum drm_lspcon_mode current_mode;
0187     struct i2c_adapter *adapter = &intel_dp->aux.ddc;
0188 
0189     err = drm_lspcon_get_mode(intel_dp->aux.drm_dev, adapter, &current_mode);
0190     if (err) {
0191         drm_err(&i915->drm, "Error reading LSPCON mode\n");
0192         return err;
0193     }
0194 
0195     if (current_mode == mode) {
0196         drm_dbg_kms(&i915->drm, "Current mode = desired LSPCON mode\n");
0197         return 0;
0198     }
0199 
0200     err = drm_lspcon_set_mode(intel_dp->aux.drm_dev, adapter, mode);
0201     if (err < 0) {
0202         drm_err(&i915->drm, "LSPCON mode change failed\n");
0203         return err;
0204     }
0205 
0206     lspcon->mode = mode;
0207     drm_dbg_kms(&i915->drm, "LSPCON mode changed done\n");
0208     return 0;
0209 }
0210 
0211 static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
0212 {
0213     struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
0214     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0215     u8 rev;
0216 
0217     if (drm_dp_dpcd_readb(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV,
0218                   &rev) != 1) {
0219         drm_dbg_kms(&i915->drm, "Native AUX CH down\n");
0220         return false;
0221     }
0222 
0223     drm_dbg_kms(&i915->drm, "Native AUX CH up, DPCD version: %d.%d\n",
0224             rev >> 4, rev & 0xf);
0225 
0226     return true;
0227 }
0228 
0229 static bool lspcon_probe(struct intel_lspcon *lspcon)
0230 {
0231     int retry;
0232     enum drm_dp_dual_mode_type adaptor_type;
0233     struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
0234     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0235     struct i2c_adapter *adapter = &intel_dp->aux.ddc;
0236     enum drm_lspcon_mode expected_mode;
0237 
0238     expected_mode = lspcon_wake_native_aux_ch(lspcon) ?
0239             DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS;
0240 
0241     /* Lets probe the adaptor and check its type */
0242     for (retry = 0; retry < 6; retry++) {
0243         if (retry)
0244             usleep_range(500, 1000);
0245 
0246         adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, adapter);
0247         if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON)
0248             break;
0249     }
0250 
0251     if (adaptor_type != DRM_DP_DUAL_MODE_LSPCON) {
0252         drm_dbg_kms(&i915->drm, "No LSPCON detected, found %s\n",
0253                 drm_dp_get_dual_mode_type_name(adaptor_type));
0254         return false;
0255     }
0256 
0257     /* Yay ... got a LSPCON device */
0258     drm_dbg_kms(&i915->drm, "LSPCON detected\n");
0259     lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
0260 
0261     /*
0262      * In the SW state machine, lets Put LSPCON in PCON mode only.
0263      * In this way, it will work with both HDMI 1.4 sinks as well as HDMI
0264      * 2.0 sinks.
0265      */
0266     if (lspcon->mode != DRM_LSPCON_MODE_PCON) {
0267         if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
0268             drm_err(&i915->drm, "LSPCON mode change to PCON failed\n");
0269             return false;
0270         }
0271     }
0272     return true;
0273 }
0274 
0275 static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
0276 {
0277     struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
0278     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0279     struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
0280     unsigned long start = jiffies;
0281 
0282     while (1) {
0283         if (intel_digital_port_connected(&dig_port->base)) {
0284             drm_dbg_kms(&i915->drm, "LSPCON recovering in PCON mode after %u ms\n",
0285                     jiffies_to_msecs(jiffies - start));
0286             return;
0287         }
0288 
0289         if (time_after(jiffies, start + msecs_to_jiffies(1000)))
0290             break;
0291 
0292         usleep_range(10000, 15000);
0293     }
0294 
0295     drm_dbg_kms(&i915->drm, "LSPCON DP descriptor mismatch after resume\n");
0296 }
0297 
0298 static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux)
0299 {
0300     u8 avi_if_ctrl;
0301     u8 retry;
0302     ssize_t ret;
0303 
0304     /* Check if LSPCON FW is ready for data */
0305     for (retry = 0; retry < 5; retry++) {
0306         if (retry)
0307             usleep_range(200, 300);
0308 
0309         ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
0310                        &avi_if_ctrl, 1);
0311         if (ret < 0) {
0312             drm_err(aux->drm_dev, "Failed to read AVI IF control\n");
0313             return false;
0314         }
0315 
0316         if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0)
0317             return true;
0318     }
0319 
0320     drm_err(aux->drm_dev, "Parade FW not ready to accept AVI IF\n");
0321     return false;
0322 }
0323 
0324 static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
0325                           u8 *avi_buf)
0326 {
0327     u8 avi_if_ctrl;
0328     u8 block_count = 0;
0329     u8 *data;
0330     u16 reg;
0331     ssize_t ret;
0332 
0333     while (block_count < 4) {
0334         if (!lspcon_parade_fw_ready(aux)) {
0335             drm_dbg_kms(aux->drm_dev, "LSPCON FW not ready, block %d\n",
0336                     block_count);
0337             return false;
0338         }
0339 
0340         reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
0341         data = avi_buf + block_count * 8;
0342         ret = drm_dp_dpcd_write(aux, reg, data, 8);
0343         if (ret < 0) {
0344             drm_err(aux->drm_dev, "Failed to write AVI IF block %d\n",
0345                 block_count);
0346             return false;
0347         }
0348 
0349         /*
0350          * Once a block of data is written, we have to inform the FW
0351          * about this by writing into avi infoframe control register:
0352          * - set the kickoff bit[7] to 1
0353          * - write the block no. to bits[1:0]
0354          */
0355         reg = LSPCON_PARADE_AVI_IF_CTRL;
0356         avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
0357         ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1);
0358         if (ret < 0) {
0359             drm_err(aux->drm_dev, "Failed to update (0x%x), block %d\n",
0360                 reg, block_count);
0361             return false;
0362         }
0363 
0364         block_count++;
0365     }
0366 
0367     drm_dbg_kms(aux->drm_dev, "Wrote AVI IF blocks successfully\n");
0368     return true;
0369 }
0370 
0371 static bool _lspcon_write_avi_infoframe_parade(struct drm_dp_aux *aux,
0372                            const u8 *frame,
0373                            ssize_t len)
0374 {
0375     u8 avi_if[LSPCON_PARADE_AVI_IF_DATA_SIZE] = {1, };
0376 
0377     /*
0378      * Parade's frames contains 32 bytes of data, divided
0379      * into 4 frames:
0380      *  Token byte (first byte of first frame, must be non-zero)
0381      *  HB0 to HB2   from AVI IF (3 bytes header)
0382      *  PB0 to PB27 from AVI IF (28 bytes data)
0383      * So it should look like this
0384      *  first block: | <token> <HB0-HB2> <DB0-DB3> |
0385      *  next 3 blocks: |<DB4-DB11>|<DB12-DB19>|<DB20-DB28>|
0386      */
0387 
0388     if (len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1) {
0389         drm_err(aux->drm_dev, "Invalid length of infoframes\n");
0390         return false;
0391     }
0392 
0393     memcpy(&avi_if[1], frame, len);
0394 
0395     if (!_lspcon_parade_write_infoframe_blocks(aux, avi_if)) {
0396         drm_dbg_kms(aux->drm_dev, "Failed to write infoframe blocks\n");
0397         return false;
0398     }
0399 
0400     return true;
0401 }
0402 
0403 static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
0404                         const u8 *buffer, ssize_t len)
0405 {
0406     int ret;
0407     u32 val = 0;
0408     u32 retry;
0409     u16 reg;
0410     const u8 *data = buffer;
0411 
0412     reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
0413     while (val < len) {
0414         /* DPCD write for AVI IF can fail on a slow FW day, so retry */
0415         for (retry = 0; retry < 5; retry++) {
0416             ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1);
0417             if (ret == 1) {
0418                 break;
0419             } else if (retry < 4) {
0420                 mdelay(50);
0421                 continue;
0422             } else {
0423                 drm_err(aux->drm_dev, "DPCD write failed at:0x%x\n", reg);
0424                 return false;
0425             }
0426         }
0427         val++; reg++; data++;
0428     }
0429 
0430     val = 0;
0431     reg = LSPCON_MCA_AVI_IF_CTRL;
0432     ret = drm_dp_dpcd_read(aux, reg, &val, 1);
0433     if (ret < 0) {
0434         drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
0435         return false;
0436     }
0437 
0438     /* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
0439     val &= ~LSPCON_MCA_AVI_IF_HANDLED;
0440     val |= LSPCON_MCA_AVI_IF_KICKOFF;
0441 
0442     ret = drm_dp_dpcd_write(aux, reg, &val, 1);
0443     if (ret < 0) {
0444         drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
0445         return false;
0446     }
0447 
0448     val = 0;
0449     ret = drm_dp_dpcd_read(aux, reg, &val, 1);
0450     if (ret < 0) {
0451         drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
0452         return false;
0453     }
0454 
0455     if (val == LSPCON_MCA_AVI_IF_HANDLED)
0456         drm_dbg_kms(aux->drm_dev, "AVI IF handled by FW\n");
0457 
0458     return true;
0459 }
0460 
0461 void lspcon_write_infoframe(struct intel_encoder *encoder,
0462                 const struct intel_crtc_state *crtc_state,
0463                 unsigned int type,
0464                 const void *frame, ssize_t len)
0465 {
0466     bool ret = true;
0467     struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
0468     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0469     struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder);
0470 
0471     switch (type) {
0472     case HDMI_INFOFRAME_TYPE_AVI:
0473         if (lspcon->vendor == LSPCON_VENDOR_MCA)
0474             ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
0475                                   frame, len);
0476         else
0477             ret = _lspcon_write_avi_infoframe_parade(&intel_dp->aux,
0478                                  frame, len);
0479         break;
0480     case HDMI_PACKET_TYPE_GAMUT_METADATA:
0481         drm_dbg_kms(&i915->drm, "Update HDR metadata for lspcon\n");
0482         /* It uses the legacy hsw implementation for the same */
0483         hsw_write_infoframe(encoder, crtc_state, type, frame, len);
0484         break;
0485     default:
0486         return;
0487     }
0488 
0489     if (!ret) {
0490         drm_err(&i915->drm, "Failed to write infoframes\n");
0491         return;
0492     }
0493 }
0494 
0495 void lspcon_read_infoframe(struct intel_encoder *encoder,
0496                const struct intel_crtc_state *crtc_state,
0497                unsigned int type,
0498                void *frame, ssize_t len)
0499 {
0500     /* FIXME implement for AVI Infoframe as well */
0501     if (type == HDMI_PACKET_TYPE_GAMUT_METADATA)
0502         hsw_read_infoframe(encoder, crtc_state, type,
0503                    frame, len);
0504 }
0505 
0506 void lspcon_set_infoframes(struct intel_encoder *encoder,
0507                bool enable,
0508                const struct intel_crtc_state *crtc_state,
0509                const struct drm_connector_state *conn_state)
0510 {
0511     ssize_t ret;
0512     union hdmi_infoframe frame;
0513     u8 buf[VIDEO_DIP_DATA_SIZE];
0514     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
0515     struct intel_lspcon *lspcon = &dig_port->lspcon;
0516     struct drm_i915_private *i915 = to_i915(encoder->base.dev);
0517     const struct drm_display_mode *adjusted_mode =
0518         &crtc_state->hw.adjusted_mode;
0519 
0520     if (!lspcon->active) {
0521         drm_err(&i915->drm, "Writing infoframes while LSPCON disabled ?\n");
0522         return;
0523     }
0524 
0525     /* FIXME precompute infoframes */
0526 
0527     ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
0528                                conn_state->connector,
0529                                adjusted_mode);
0530     if (ret < 0) {
0531         drm_err(&i915->drm, "couldn't fill AVI infoframe\n");
0532         return;
0533     }
0534 
0535     /*
0536      * Currently there is no interface defined to
0537      * check user preference between RGB/YCBCR444
0538      * or YCBCR420. So the only possible case for
0539      * YCBCR444 usage is driving YCBCR420 output
0540      * with LSPCON, when pipe is configured for
0541      * YCBCR444 output and LSPCON takes care of
0542      * downsampling it.
0543      */
0544     if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
0545         frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
0546     else
0547         frame.avi.colorspace = HDMI_COLORSPACE_RGB;
0548 
0549     /* Set the Colorspace as per the HDMI spec */
0550     drm_hdmi_avi_infoframe_colorimetry(&frame.avi, conn_state);
0551 
0552     /* nonsense combination */
0553     drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range &&
0554             crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB);
0555 
0556     if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB) {
0557         drm_hdmi_avi_infoframe_quant_range(&frame.avi,
0558                            conn_state->connector,
0559                            adjusted_mode,
0560                            crtc_state->limited_color_range ?
0561                            HDMI_QUANTIZATION_RANGE_LIMITED :
0562                            HDMI_QUANTIZATION_RANGE_FULL);
0563     } else {
0564         frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
0565         frame.avi.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
0566     }
0567 
0568     drm_hdmi_avi_infoframe_content_type(&frame.avi, conn_state);
0569 
0570     ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf));
0571     if (ret < 0) {
0572         drm_err(&i915->drm, "Failed to pack AVI IF\n");
0573         return;
0574     }
0575 
0576     dig_port->write_infoframe(encoder, crtc_state, HDMI_INFOFRAME_TYPE_AVI,
0577                   buf, ret);
0578 }
0579 
0580 static bool _lspcon_read_avi_infoframe_enabled_mca(struct drm_dp_aux *aux)
0581 {
0582     int ret;
0583     u32 val = 0;
0584     u16 reg = LSPCON_MCA_AVI_IF_CTRL;
0585 
0586     ret = drm_dp_dpcd_read(aux, reg, &val, 1);
0587     if (ret < 0) {
0588         drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
0589         return false;
0590     }
0591 
0592     return val & LSPCON_MCA_AVI_IF_KICKOFF;
0593 }
0594 
0595 static bool _lspcon_read_avi_infoframe_enabled_parade(struct drm_dp_aux *aux)
0596 {
0597     int ret;
0598     u32 val = 0;
0599     u16 reg = LSPCON_PARADE_AVI_IF_CTRL;
0600 
0601     ret = drm_dp_dpcd_read(aux, reg, &val, 1);
0602     if (ret < 0) {
0603         drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
0604         return false;
0605     }
0606 
0607     return val & LSPCON_PARADE_AVI_IF_KICKOFF;
0608 }
0609 
0610 u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
0611                   const struct intel_crtc_state *pipe_config)
0612 {
0613     struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
0614     struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder);
0615     struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
0616     bool infoframes_enabled;
0617     u32 val = 0;
0618     u32 mask, tmp;
0619 
0620     if (lspcon->vendor == LSPCON_VENDOR_MCA)
0621         infoframes_enabled = _lspcon_read_avi_infoframe_enabled_mca(&intel_dp->aux);
0622     else
0623         infoframes_enabled = _lspcon_read_avi_infoframe_enabled_parade(&intel_dp->aux);
0624 
0625     if (infoframes_enabled)
0626         val |= intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
0627 
0628     if (lspcon->hdr_supported) {
0629         tmp = intel_de_read(dev_priv,
0630                     HSW_TVIDEO_DIP_CTL(pipe_config->cpu_transcoder));
0631         mask = VIDEO_DIP_ENABLE_GMP_HSW;
0632 
0633         if (tmp & mask)
0634             val |= intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
0635     }
0636 
0637     return val;
0638 }
0639 
0640 void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
0641 {
0642     lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
0643 }
0644 
0645 bool lspcon_init(struct intel_digital_port *dig_port)
0646 {
0647     struct intel_dp *intel_dp = &dig_port->dp;
0648     struct intel_lspcon *lspcon = &dig_port->lspcon;
0649     struct drm_i915_private *i915 = dp_to_i915(intel_dp);
0650     struct drm_connector *connector = &intel_dp->attached_connector->base;
0651 
0652     lspcon->active = false;
0653     lspcon->mode = DRM_LSPCON_MODE_INVALID;
0654 
0655     if (!lspcon_probe(lspcon)) {
0656         drm_err(&i915->drm, "Failed to probe lspcon\n");
0657         return false;
0658     }
0659 
0660     if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd) != 0) {
0661         drm_err(&i915->drm, "LSPCON DPCD read failed\n");
0662         return false;
0663     }
0664 
0665     if (!lspcon_detect_vendor(lspcon)) {
0666         drm_err(&i915->drm, "LSPCON vendor detection failed\n");
0667         return false;
0668     }
0669 
0670     connector->ycbcr_420_allowed = true;
0671     lspcon->active = true;
0672     drm_dbg_kms(&i915->drm, "Success: LSPCON init\n");
0673     return true;
0674 }
0675 
0676 u32 intel_lspcon_infoframes_enabled(struct intel_encoder *encoder,
0677                     const struct intel_crtc_state *pipe_config)
0678 {
0679     struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
0680 
0681     return dig_port->infoframes_enabled(encoder, pipe_config);
0682 }
0683 
0684 void lspcon_resume(struct intel_digital_port *dig_port)
0685 {
0686     struct intel_lspcon *lspcon = &dig_port->lspcon;
0687     struct drm_device *dev = dig_port->base.base.dev;
0688     struct drm_i915_private *i915 = to_i915(dev);
0689     enum drm_lspcon_mode expected_mode;
0690 
0691     if (!intel_bios_is_lspcon_present(i915, dig_port->base.port))
0692         return;
0693 
0694     if (!lspcon->active) {
0695         if (!lspcon_init(dig_port)) {
0696             drm_err(&i915->drm, "LSPCON init failed on port %c\n",
0697                 port_name(dig_port->base.port));
0698             return;
0699         }
0700     }
0701 
0702     if (lspcon_wake_native_aux_ch(lspcon)) {
0703         expected_mode = DRM_LSPCON_MODE_PCON;
0704         lspcon_resume_in_pcon_wa(lspcon);
0705     } else {
0706         expected_mode = DRM_LSPCON_MODE_LS;
0707     }
0708 
0709     if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
0710         return;
0711 
0712     if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
0713         drm_err(&i915->drm, "LSPCON resume failed\n");
0714     else
0715         drm_dbg_kms(&i915->drm, "LSPCON resume success\n");
0716 }