Home | History | Annotate | Line # | Download | only in display
      1  1.3  riastrad /*	$NetBSD: intel_lspcon.c,v 1.3 2021/12/19 11:47:33 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /*
      4  1.1  riastrad  * Copyright  2016 Intel Corporation
      5  1.1  riastrad  *
      6  1.1  riastrad  * Permission is hereby granted, free of charge, to any person obtaining a
      7  1.1  riastrad  * copy of this software and associated documentation files (the "Software"),
      8  1.1  riastrad  * to deal in the Software without restriction, including without limitation
      9  1.1  riastrad  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  1.1  riastrad  * and/or sell copies of the Software, and to permit persons to whom the
     11  1.1  riastrad  * Software is furnished to do so, subject to the following conditions:
     12  1.1  riastrad  *
     13  1.1  riastrad  * The above copyright notice and this permission notice (including the next
     14  1.1  riastrad  * paragraph) shall be included in all copies or substantial portions of the
     15  1.1  riastrad  * Software.
     16  1.1  riastrad  *
     17  1.1  riastrad  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  1.1  riastrad  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  1.1  riastrad  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  1.1  riastrad  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  1.1  riastrad  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22  1.1  riastrad  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     23  1.1  riastrad  * DEALINGS IN THE SOFTWARE.
     24  1.1  riastrad  *
     25  1.1  riastrad  *
     26  1.1  riastrad  */
     27  1.1  riastrad 
     28  1.1  riastrad #include <sys/cdefs.h>
     29  1.3  riastrad __KERNEL_RCSID(0, "$NetBSD: intel_lspcon.c,v 1.3 2021/12/19 11:47:33 riastradh Exp $");
     30  1.1  riastrad 
     31  1.1  riastrad #include <drm/drm_atomic_helper.h>
     32  1.1  riastrad #include <drm/drm_dp_dual_mode_helper.h>
     33  1.1  riastrad #include <drm/drm_edid.h>
     34  1.1  riastrad 
     35  1.1  riastrad #include "intel_display_types.h"
     36  1.1  riastrad #include "intel_dp.h"
     37  1.1  riastrad #include "intel_lspcon.h"
     38  1.1  riastrad 
     39  1.1  riastrad /* LSPCON OUI Vendor ID(signatures) */
     40  1.1  riastrad #define LSPCON_VENDOR_PARADE_OUI 0x001CF8
     41  1.1  riastrad #define LSPCON_VENDOR_MCA_OUI 0x0060AD
     42  1.1  riastrad 
     43  1.1  riastrad /* AUX addresses to write MCA AVI IF */
     44  1.1  riastrad #define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
     45  1.1  riastrad #define LSPCON_MCA_AVI_IF_CTRL 0x5DF
     46  1.1  riastrad #define  LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
     47  1.1  riastrad #define  LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
     48  1.1  riastrad 
     49  1.1  riastrad /* AUX addresses to write Parade AVI IF */
     50  1.1  riastrad #define LSPCON_PARADE_AVI_IF_WRITE_OFFSET 0x516
     51  1.1  riastrad #define LSPCON_PARADE_AVI_IF_CTRL 0x51E
     52  1.1  riastrad #define  LSPCON_PARADE_AVI_IF_KICKOFF (1 << 7)
     53  1.1  riastrad #define LSPCON_PARADE_AVI_IF_DATA_SIZE 32
     54  1.1  riastrad 
     55  1.1  riastrad static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
     56  1.1  riastrad {
     57  1.1  riastrad 	struct intel_digital_port *dig_port =
     58  1.1  riastrad 		container_of(lspcon, struct intel_digital_port, lspcon);
     59  1.1  riastrad 
     60  1.1  riastrad 	return &dig_port->dp;
     61  1.1  riastrad }
     62  1.1  riastrad 
     63  1.1  riastrad static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
     64  1.1  riastrad {
     65  1.1  riastrad 	switch (mode) {
     66  1.1  riastrad 	case DRM_LSPCON_MODE_PCON:
     67  1.1  riastrad 		return "PCON";
     68  1.1  riastrad 	case DRM_LSPCON_MODE_LS:
     69  1.1  riastrad 		return "LS";
     70  1.1  riastrad 	case DRM_LSPCON_MODE_INVALID:
     71  1.1  riastrad 		return "INVALID";
     72  1.1  riastrad 	default:
     73  1.1  riastrad 		MISSING_CASE(mode);
     74  1.1  riastrad 		return "INVALID";
     75  1.1  riastrad 	}
     76  1.1  riastrad }
     77  1.1  riastrad 
     78  1.1  riastrad static bool lspcon_detect_vendor(struct intel_lspcon *lspcon)
     79  1.1  riastrad {
     80  1.1  riastrad 	struct intel_dp *dp = lspcon_to_intel_dp(lspcon);
     81  1.1  riastrad 	struct drm_dp_dpcd_ident *ident;
     82  1.1  riastrad 	u32 vendor_oui;
     83  1.1  riastrad 
     84  1.1  riastrad 	if (drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd))) {
     85  1.1  riastrad 		DRM_ERROR("Can't read description\n");
     86  1.1  riastrad 		return false;
     87  1.1  riastrad 	}
     88  1.1  riastrad 
     89  1.1  riastrad 	ident = &dp->desc.ident;
     90  1.1  riastrad 	vendor_oui = (ident->oui[0] << 16) | (ident->oui[1] << 8) |
     91  1.1  riastrad 		      ident->oui[2];
     92  1.1  riastrad 
     93  1.1  riastrad 	switch (vendor_oui) {
     94  1.1  riastrad 	case LSPCON_VENDOR_MCA_OUI:
     95  1.1  riastrad 		lspcon->vendor = LSPCON_VENDOR_MCA;
     96  1.1  riastrad 		DRM_DEBUG_KMS("Vendor: Mega Chips\n");
     97  1.1  riastrad 		break;
     98  1.1  riastrad 
     99  1.1  riastrad 	case LSPCON_VENDOR_PARADE_OUI:
    100  1.1  riastrad 		lspcon->vendor = LSPCON_VENDOR_PARADE;
    101  1.1  riastrad 		DRM_DEBUG_KMS("Vendor: Parade Tech\n");
    102  1.1  riastrad 		break;
    103  1.1  riastrad 
    104  1.1  riastrad 	default:
    105  1.1  riastrad 		DRM_ERROR("Invalid/Unknown vendor OUI\n");
    106  1.1  riastrad 		return false;
    107  1.1  riastrad 	}
    108  1.1  riastrad 
    109  1.1  riastrad 	return true;
    110  1.1  riastrad }
    111  1.1  riastrad 
    112  1.1  riastrad static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
    113  1.1  riastrad {
    114  1.1  riastrad 	enum drm_lspcon_mode current_mode;
    115  1.1  riastrad 	struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
    116  1.1  riastrad 
    117  1.1  riastrad 	if (drm_lspcon_get_mode(adapter, &current_mode)) {
    118  1.1  riastrad 		DRM_DEBUG_KMS("Error reading LSPCON mode\n");
    119  1.1  riastrad 		return DRM_LSPCON_MODE_INVALID;
    120  1.1  riastrad 	}
    121  1.1  riastrad 	return current_mode;
    122  1.1  riastrad }
    123  1.1  riastrad 
    124  1.1  riastrad static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon,
    125  1.1  riastrad 					     enum drm_lspcon_mode mode)
    126  1.1  riastrad {
    127  1.1  riastrad 	enum drm_lspcon_mode current_mode;
    128  1.1  riastrad 
    129  1.1  riastrad 	current_mode = lspcon_get_current_mode(lspcon);
    130  1.1  riastrad 	if (current_mode == mode)
    131  1.1  riastrad 		goto out;
    132  1.1  riastrad 
    133  1.1  riastrad 	DRM_DEBUG_KMS("Waiting for LSPCON mode %s to settle\n",
    134  1.1  riastrad 		      lspcon_mode_name(mode));
    135  1.1  riastrad 
    136  1.1  riastrad 	wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode, 400);
    137  1.1  riastrad 	if (current_mode != mode)
    138  1.1  riastrad 		DRM_ERROR("LSPCON mode hasn't settled\n");
    139  1.1  riastrad 
    140  1.1  riastrad out:
    141  1.1  riastrad 	DRM_DEBUG_KMS("Current LSPCON mode %s\n",
    142  1.1  riastrad 		      lspcon_mode_name(current_mode));
    143  1.1  riastrad 
    144  1.1  riastrad 	return current_mode;
    145  1.1  riastrad }
    146  1.1  riastrad 
    147  1.1  riastrad static int lspcon_change_mode(struct intel_lspcon *lspcon,
    148  1.1  riastrad 			      enum drm_lspcon_mode mode)
    149  1.1  riastrad {
    150  1.1  riastrad 	int err;
    151  1.1  riastrad 	enum drm_lspcon_mode current_mode;
    152  1.1  riastrad 	struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
    153  1.1  riastrad 
    154  1.1  riastrad 	err = drm_lspcon_get_mode(adapter, &current_mode);
    155  1.1  riastrad 	if (err) {
    156  1.1  riastrad 		DRM_ERROR("Error reading LSPCON mode\n");
    157  1.1  riastrad 		return err;
    158  1.1  riastrad 	}
    159  1.1  riastrad 
    160  1.1  riastrad 	if (current_mode == mode) {
    161  1.1  riastrad 		DRM_DEBUG_KMS("Current mode = desired LSPCON mode\n");
    162  1.1  riastrad 		return 0;
    163  1.1  riastrad 	}
    164  1.1  riastrad 
    165  1.1  riastrad 	err = drm_lspcon_set_mode(adapter, mode);
    166  1.1  riastrad 	if (err < 0) {
    167  1.1  riastrad 		DRM_ERROR("LSPCON mode change failed\n");
    168  1.1  riastrad 		return err;
    169  1.1  riastrad 	}
    170  1.1  riastrad 
    171  1.1  riastrad 	lspcon->mode = mode;
    172  1.1  riastrad 	DRM_DEBUG_KMS("LSPCON mode changed done\n");
    173  1.1  riastrad 	return 0;
    174  1.1  riastrad }
    175  1.1  riastrad 
    176  1.1  riastrad static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
    177  1.1  riastrad {
    178  1.1  riastrad 	u8 rev;
    179  1.1  riastrad 
    180  1.1  riastrad 	if (drm_dp_dpcd_readb(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV,
    181  1.1  riastrad 			      &rev) != 1) {
    182  1.1  riastrad 		DRM_DEBUG_KMS("Native AUX CH down\n");
    183  1.1  riastrad 		return false;
    184  1.1  riastrad 	}
    185  1.1  riastrad 
    186  1.1  riastrad 	DRM_DEBUG_KMS("Native AUX CH up, DPCD version: %d.%d\n",
    187  1.1  riastrad 		      rev >> 4, rev & 0xf);
    188  1.1  riastrad 
    189  1.1  riastrad 	return true;
    190  1.1  riastrad }
    191  1.1  riastrad 
    192  1.1  riastrad void lspcon_ycbcr420_config(struct drm_connector *connector,
    193  1.1  riastrad 			    struct intel_crtc_state *crtc_state)
    194  1.1  riastrad {
    195  1.1  riastrad 	const struct drm_display_info *info = &connector->display_info;
    196  1.1  riastrad 	const struct drm_display_mode *adjusted_mode =
    197  1.1  riastrad 					&crtc_state->hw.adjusted_mode;
    198  1.1  riastrad 
    199  1.1  riastrad 	if (drm_mode_is_420_only(info, adjusted_mode) &&
    200  1.1  riastrad 	    connector->ycbcr_420_allowed) {
    201  1.1  riastrad 		crtc_state->port_clock /= 2;
    202  1.1  riastrad 		crtc_state->output_format = INTEL_OUTPUT_FORMAT_YCBCR444;
    203  1.1  riastrad 		crtc_state->lspcon_downsampling = true;
    204  1.1  riastrad 	}
    205  1.1  riastrad }
    206  1.1  riastrad 
    207  1.1  riastrad static bool lspcon_probe(struct intel_lspcon *lspcon)
    208  1.1  riastrad {
    209  1.1  riastrad 	int retry;
    210  1.1  riastrad 	enum drm_dp_dual_mode_type adaptor_type;
    211  1.1  riastrad 	struct i2c_adapter *adapter = &lspcon_to_intel_dp(lspcon)->aux.ddc;
    212  1.1  riastrad 	enum drm_lspcon_mode expected_mode;
    213  1.1  riastrad 
    214  1.1  riastrad 	expected_mode = lspcon_wake_native_aux_ch(lspcon) ?
    215  1.1  riastrad 			DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS;
    216  1.1  riastrad 
    217  1.1  riastrad 	/* Lets probe the adaptor and check its type */
    218  1.1  riastrad 	for (retry = 0; retry < 6; retry++) {
    219  1.1  riastrad 		if (retry)
    220  1.1  riastrad 			usleep_range(500, 1000);
    221  1.1  riastrad 
    222  1.1  riastrad 		adaptor_type = drm_dp_dual_mode_detect(adapter);
    223  1.1  riastrad 		if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON)
    224  1.1  riastrad 			break;
    225  1.1  riastrad 	}
    226  1.1  riastrad 
    227  1.1  riastrad 	if (adaptor_type != DRM_DP_DUAL_MODE_LSPCON) {
    228  1.1  riastrad 		DRM_DEBUG_KMS("No LSPCON detected, found %s\n",
    229  1.1  riastrad 			       drm_dp_get_dual_mode_type_name(adaptor_type));
    230  1.1  riastrad 		return false;
    231  1.1  riastrad 	}
    232  1.1  riastrad 
    233  1.1  riastrad 	/* Yay ... got a LSPCON device */
    234  1.1  riastrad 	DRM_DEBUG_KMS("LSPCON detected\n");
    235  1.1  riastrad 	lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
    236  1.1  riastrad 
    237  1.1  riastrad 	/*
    238  1.1  riastrad 	 * In the SW state machine, lets Put LSPCON in PCON mode only.
    239  1.1  riastrad 	 * In this way, it will work with both HDMI 1.4 sinks as well as HDMI
    240  1.1  riastrad 	 * 2.0 sinks.
    241  1.1  riastrad 	 */
    242  1.1  riastrad 	if (lspcon->mode != DRM_LSPCON_MODE_PCON) {
    243  1.1  riastrad 		if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
    244  1.1  riastrad 			DRM_ERROR("LSPCON mode change to PCON failed\n");
    245  1.1  riastrad 			return false;
    246  1.1  riastrad 		}
    247  1.1  riastrad 	}
    248  1.1  riastrad 	return true;
    249  1.1  riastrad }
    250  1.1  riastrad 
    251  1.1  riastrad static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
    252  1.1  riastrad {
    253  1.1  riastrad 	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
    254  1.1  riastrad 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
    255  1.1  riastrad 	unsigned long start = jiffies;
    256  1.1  riastrad 
    257  1.1  riastrad 	while (1) {
    258  1.1  riastrad 		if (intel_digital_port_connected(&dig_port->base)) {
    259  1.1  riastrad 			DRM_DEBUG_KMS("LSPCON recovering in PCON mode after %u ms\n",
    260  1.1  riastrad 				      jiffies_to_msecs(jiffies - start));
    261  1.1  riastrad 			return;
    262  1.1  riastrad 		}
    263  1.1  riastrad 
    264  1.1  riastrad 		if (time_after(jiffies, start + msecs_to_jiffies(1000)))
    265  1.1  riastrad 			break;
    266  1.1  riastrad 
    267  1.1  riastrad 		usleep_range(10000, 15000);
    268  1.1  riastrad 	}
    269  1.1  riastrad 
    270  1.1  riastrad 	DRM_DEBUG_KMS("LSPCON DP descriptor mismatch after resume\n");
    271  1.1  riastrad }
    272  1.1  riastrad 
    273  1.1  riastrad static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux)
    274  1.1  riastrad {
    275  1.1  riastrad 	u8 avi_if_ctrl;
    276  1.1  riastrad 	u8 retry;
    277  1.1  riastrad 	ssize_t ret;
    278  1.1  riastrad 
    279  1.1  riastrad 	/* Check if LSPCON FW is ready for data */
    280  1.1  riastrad 	for (retry = 0; retry < 5; retry++) {
    281  1.1  riastrad 		if (retry)
    282  1.1  riastrad 			usleep_range(200, 300);
    283  1.1  riastrad 
    284  1.1  riastrad 		ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
    285  1.1  riastrad 				       &avi_if_ctrl, 1);
    286  1.1  riastrad 		if (ret < 0) {
    287  1.1  riastrad 			DRM_ERROR("Failed to read AVI IF control\n");
    288  1.1  riastrad 			return false;
    289  1.1  riastrad 		}
    290  1.1  riastrad 
    291  1.1  riastrad 		if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0)
    292  1.1  riastrad 			return true;
    293  1.1  riastrad 	}
    294  1.1  riastrad 
    295  1.1  riastrad 	DRM_ERROR("Parade FW not ready to accept AVI IF\n");
    296  1.1  riastrad 	return false;
    297  1.1  riastrad }
    298  1.1  riastrad 
    299  1.1  riastrad static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
    300  1.1  riastrad 						  u8 *avi_buf)
    301  1.1  riastrad {
    302  1.1  riastrad 	u8 avi_if_ctrl;
    303  1.1  riastrad 	u8 block_count = 0;
    304  1.1  riastrad 	u8 *data;
    305  1.1  riastrad 	u16 reg;
    306  1.1  riastrad 	ssize_t ret;
    307  1.1  riastrad 
    308  1.1  riastrad 	while (block_count < 4) {
    309  1.1  riastrad 		if (!lspcon_parade_fw_ready(aux)) {
    310  1.1  riastrad 			DRM_DEBUG_KMS("LSPCON FW not ready, block %d\n",
    311  1.1  riastrad 				      block_count);
    312  1.1  riastrad 			return false;
    313  1.1  riastrad 		}
    314  1.1  riastrad 
    315  1.1  riastrad 		reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
    316  1.1  riastrad 		data = avi_buf + block_count * 8;
    317  1.1  riastrad 		ret = drm_dp_dpcd_write(aux, reg, data, 8);
    318  1.1  riastrad 		if (ret < 0) {
    319  1.1  riastrad 			DRM_ERROR("Failed to write AVI IF block %d\n",
    320  1.1  riastrad 				  block_count);
    321  1.1  riastrad 			return false;
    322  1.1  riastrad 		}
    323  1.1  riastrad 
    324  1.1  riastrad 		/*
    325  1.1  riastrad 		 * Once a block of data is written, we have to inform the FW
    326  1.1  riastrad 		 * about this by writing into avi infoframe control register:
    327  1.1  riastrad 		 * - set the kickoff bit[7] to 1
    328  1.1  riastrad 		 * - write the block no. to bits[1:0]
    329  1.1  riastrad 		 */
    330  1.1  riastrad 		reg = LSPCON_PARADE_AVI_IF_CTRL;
    331  1.1  riastrad 		avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
    332  1.1  riastrad 		ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1);
    333  1.1  riastrad 		if (ret < 0) {
    334  1.1  riastrad 			DRM_ERROR("Failed to update (0x%x), block %d\n",
    335  1.1  riastrad 				  reg, block_count);
    336  1.1  riastrad 			return false;
    337  1.1  riastrad 		}
    338  1.1  riastrad 
    339  1.1  riastrad 		block_count++;
    340  1.1  riastrad 	}
    341  1.1  riastrad 
    342  1.1  riastrad 	DRM_DEBUG_KMS("Wrote AVI IF blocks successfully\n");
    343  1.1  riastrad 	return true;
    344  1.1  riastrad }
    345  1.1  riastrad 
    346  1.1  riastrad static bool _lspcon_write_avi_infoframe_parade(struct drm_dp_aux *aux,
    347  1.1  riastrad 					       const u8 *frame,
    348  1.1  riastrad 					       ssize_t len)
    349  1.1  riastrad {
    350  1.1  riastrad 	u8 avi_if[LSPCON_PARADE_AVI_IF_DATA_SIZE] = {1, };
    351  1.1  riastrad 
    352  1.1  riastrad 	/*
    353  1.1  riastrad 	 * Parade's frames contains 32 bytes of data, divided
    354  1.1  riastrad 	 * into 4 frames:
    355  1.1  riastrad 	 *	Token byte (first byte of first frame, must be non-zero)
    356  1.1  riastrad 	 *	HB0 to HB2	 from AVI IF (3 bytes header)
    357  1.1  riastrad 	 *	PB0 to PB27 from AVI IF (28 bytes data)
    358  1.1  riastrad 	 * So it should look like this
    359  1.1  riastrad 	 *	first block: | <token> <HB0-HB2> <DB0-DB3> |
    360  1.1  riastrad 	 *	next 3 blocks: |<DB4-DB11>|<DB12-DB19>|<DB20-DB28>|
    361  1.1  riastrad 	 */
    362  1.1  riastrad 
    363  1.1  riastrad 	if (len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1) {
    364  1.1  riastrad 		DRM_ERROR("Invalid length of infoframes\n");
    365  1.1  riastrad 		return false;
    366  1.1  riastrad 	}
    367  1.1  riastrad 
    368  1.1  riastrad 	memcpy(&avi_if[1], frame, len);
    369  1.1  riastrad 
    370  1.1  riastrad 	if (!_lspcon_parade_write_infoframe_blocks(aux, avi_if)) {
    371  1.1  riastrad 		DRM_DEBUG_KMS("Failed to write infoframe blocks\n");
    372  1.1  riastrad 		return false;
    373  1.1  riastrad 	}
    374  1.1  riastrad 
    375  1.1  riastrad 	return true;
    376  1.1  riastrad }
    377  1.1  riastrad 
    378  1.1  riastrad static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
    379  1.1  riastrad 					    const u8 *buffer, ssize_t len)
    380  1.1  riastrad {
    381  1.1  riastrad 	int ret;
    382  1.1  riastrad 	u32 val = 0;
    383  1.1  riastrad 	u32 retry;
    384  1.1  riastrad 	u16 reg;
    385  1.1  riastrad 	const u8 *data = buffer;
    386  1.1  riastrad 
    387  1.1  riastrad 	reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
    388  1.1  riastrad 	while (val < len) {
    389  1.1  riastrad 		/* DPCD write for AVI IF can fail on a slow FW day, so retry */
    390  1.1  riastrad 		for (retry = 0; retry < 5; retry++) {
    391  1.3  riastrad 			ret = drm_dp_dpcd_write(aux, reg, (void *)__UNCONST(data), 1);
    392  1.1  riastrad 			if (ret == 1) {
    393  1.1  riastrad 				break;
    394  1.1  riastrad 			} else if (retry < 4) {
    395  1.1  riastrad 				mdelay(50);
    396  1.1  riastrad 				continue;
    397  1.1  riastrad 			} else {
    398  1.1  riastrad 				DRM_ERROR("DPCD write failed at:0x%x\n", reg);
    399  1.1  riastrad 				return false;
    400  1.1  riastrad 			}
    401  1.1  riastrad 		}
    402  1.1  riastrad 		val++; reg++; data++;
    403  1.1  riastrad 	}
    404  1.1  riastrad 
    405  1.1  riastrad 	val = 0;
    406  1.1  riastrad 	reg = LSPCON_MCA_AVI_IF_CTRL;
    407  1.1  riastrad 	ret = drm_dp_dpcd_read(aux, reg, &val, 1);
    408  1.1  riastrad 	if (ret < 0) {
    409  1.1  riastrad 		DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
    410  1.1  riastrad 		return false;
    411  1.1  riastrad 	}
    412  1.1  riastrad 
    413  1.1  riastrad 	/* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
    414  1.1  riastrad 	val &= ~LSPCON_MCA_AVI_IF_HANDLED;
    415  1.1  riastrad 	val |= LSPCON_MCA_AVI_IF_KICKOFF;
    416  1.1  riastrad 
    417  1.1  riastrad 	ret = drm_dp_dpcd_write(aux, reg, &val, 1);
    418  1.1  riastrad 	if (ret < 0) {
    419  1.1  riastrad 		DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
    420  1.1  riastrad 		return false;
    421  1.1  riastrad 	}
    422  1.1  riastrad 
    423  1.1  riastrad 	val = 0;
    424  1.1  riastrad 	ret = drm_dp_dpcd_read(aux, reg, &val, 1);
    425  1.1  riastrad 	if (ret < 0) {
    426  1.1  riastrad 		DRM_ERROR("DPCD read failed, address 0x%x\n", reg);
    427  1.1  riastrad 		return false;
    428  1.1  riastrad 	}
    429  1.1  riastrad 
    430  1.1  riastrad 	if (val == LSPCON_MCA_AVI_IF_HANDLED)
    431  1.1  riastrad 		DRM_DEBUG_KMS("AVI IF handled by FW\n");
    432  1.1  riastrad 
    433  1.1  riastrad 	return true;
    434  1.1  riastrad }
    435  1.1  riastrad 
    436  1.1  riastrad void lspcon_write_infoframe(struct intel_encoder *encoder,
    437  1.1  riastrad 			    const struct intel_crtc_state *crtc_state,
    438  1.1  riastrad 			    unsigned int type,
    439  1.1  riastrad 			    const void *frame, ssize_t len)
    440  1.1  riastrad {
    441  1.1  riastrad 	bool ret;
    442  1.1  riastrad 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
    443  1.1  riastrad 	struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder);
    444  1.1  riastrad 
    445  1.1  riastrad 	/* LSPCON only needs AVI IF */
    446  1.1  riastrad 	if (type != HDMI_INFOFRAME_TYPE_AVI)
    447  1.1  riastrad 		return;
    448  1.1  riastrad 
    449  1.1  riastrad 	if (lspcon->vendor == LSPCON_VENDOR_MCA)
    450  1.1  riastrad 		ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
    451  1.1  riastrad 						      frame, len);
    452  1.1  riastrad 	else
    453  1.1  riastrad 		ret = _lspcon_write_avi_infoframe_parade(&intel_dp->aux,
    454  1.1  riastrad 							 frame, len);
    455  1.1  riastrad 
    456  1.1  riastrad 	if (!ret) {
    457  1.1  riastrad 		DRM_ERROR("Failed to write AVI infoframes\n");
    458  1.1  riastrad 		return;
    459  1.1  riastrad 	}
    460  1.1  riastrad 
    461  1.1  riastrad 	DRM_DEBUG_DRIVER("AVI infoframes updated successfully\n");
    462  1.1  riastrad }
    463  1.1  riastrad 
    464  1.1  riastrad void lspcon_read_infoframe(struct intel_encoder *encoder,
    465  1.1  riastrad 			   const struct intel_crtc_state *crtc_state,
    466  1.1  riastrad 			   unsigned int type,
    467  1.1  riastrad 			   void *frame, ssize_t len)
    468  1.1  riastrad {
    469  1.1  riastrad 	/* FIXME implement this */
    470  1.1  riastrad }
    471  1.1  riastrad 
    472  1.1  riastrad void lspcon_set_infoframes(struct intel_encoder *encoder,
    473  1.1  riastrad 			   bool enable,
    474  1.1  riastrad 			   const struct intel_crtc_state *crtc_state,
    475  1.1  riastrad 			   const struct drm_connector_state *conn_state)
    476  1.1  riastrad {
    477  1.1  riastrad 	ssize_t ret;
    478  1.1  riastrad 	union hdmi_infoframe frame;
    479  1.1  riastrad 	u8 buf[VIDEO_DIP_DATA_SIZE];
    480  1.1  riastrad 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
    481  1.1  riastrad 	struct intel_lspcon *lspcon = &dig_port->lspcon;
    482  1.1  riastrad 	const struct drm_display_mode *adjusted_mode =
    483  1.1  riastrad 		&crtc_state->hw.adjusted_mode;
    484  1.1  riastrad 
    485  1.1  riastrad 	if (!lspcon->active) {
    486  1.1  riastrad 		DRM_ERROR("Writing infoframes while LSPCON disabled ?\n");
    487  1.1  riastrad 		return;
    488  1.1  riastrad 	}
    489  1.1  riastrad 
    490  1.1  riastrad 	/* FIXME precompute infoframes */
    491  1.1  riastrad 
    492  1.1  riastrad 	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
    493  1.1  riastrad 						       conn_state->connector,
    494  1.1  riastrad 						       adjusted_mode);
    495  1.1  riastrad 	if (ret < 0) {
    496  1.1  riastrad 		DRM_ERROR("couldn't fill AVI infoframe\n");
    497  1.1  riastrad 		return;
    498  1.1  riastrad 	}
    499  1.1  riastrad 
    500  1.1  riastrad 	if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444) {
    501  1.1  riastrad 		if (crtc_state->lspcon_downsampling)
    502  1.1  riastrad 			frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
    503  1.1  riastrad 		else
    504  1.1  riastrad 			frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
    505  1.1  riastrad 	} else {
    506  1.1  riastrad 		frame.avi.colorspace = HDMI_COLORSPACE_RGB;
    507  1.1  riastrad 	}
    508  1.1  riastrad 
    509  1.1  riastrad 	drm_hdmi_avi_infoframe_quant_range(&frame.avi,
    510  1.1  riastrad 					   conn_state->connector,
    511  1.1  riastrad 					   adjusted_mode,
    512  1.1  riastrad 					   crtc_state->limited_color_range ?
    513  1.1  riastrad 					   HDMI_QUANTIZATION_RANGE_LIMITED :
    514  1.1  riastrad 					   HDMI_QUANTIZATION_RANGE_FULL);
    515  1.1  riastrad 
    516  1.1  riastrad 	ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf));
    517  1.1  riastrad 	if (ret < 0) {
    518  1.1  riastrad 		DRM_ERROR("Failed to pack AVI IF\n");
    519  1.1  riastrad 		return;
    520  1.1  riastrad 	}
    521  1.1  riastrad 
    522  1.1  riastrad 	dig_port->write_infoframe(encoder, crtc_state, HDMI_INFOFRAME_TYPE_AVI,
    523  1.1  riastrad 				  buf, ret);
    524  1.1  riastrad }
    525  1.1  riastrad 
    526  1.1  riastrad u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
    527  1.1  riastrad 			      const struct intel_crtc_state *pipe_config)
    528  1.1  riastrad {
    529  1.1  riastrad 	/* FIXME actually read this from the hw */
    530  1.1  riastrad 	return enc_to_intel_lspcon(encoder)->active;
    531  1.1  riastrad }
    532  1.1  riastrad 
    533  1.1  riastrad void lspcon_resume(struct intel_lspcon *lspcon)
    534  1.1  riastrad {
    535  1.1  riastrad 	enum drm_lspcon_mode expected_mode;
    536  1.1  riastrad 
    537  1.1  riastrad 	if (lspcon_wake_native_aux_ch(lspcon)) {
    538  1.1  riastrad 		expected_mode = DRM_LSPCON_MODE_PCON;
    539  1.1  riastrad 		lspcon_resume_in_pcon_wa(lspcon);
    540  1.1  riastrad 	} else {
    541  1.1  riastrad 		expected_mode = DRM_LSPCON_MODE_LS;
    542  1.1  riastrad 	}
    543  1.1  riastrad 
    544  1.1  riastrad 	if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
    545  1.1  riastrad 		return;
    546  1.1  riastrad 
    547  1.1  riastrad 	if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
    548  1.1  riastrad 		DRM_ERROR("LSPCON resume failed\n");
    549  1.1  riastrad 	else
    550  1.1  riastrad 		DRM_DEBUG_KMS("LSPCON resume success\n");
    551  1.1  riastrad }
    552  1.1  riastrad 
    553  1.1  riastrad void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon)
    554  1.1  riastrad {
    555  1.1  riastrad 	lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
    556  1.1  riastrad }
    557  1.1  riastrad 
    558  1.1  riastrad bool lspcon_init(struct intel_digital_port *intel_dig_port)
    559  1.1  riastrad {
    560  1.1  riastrad 	struct intel_dp *dp = &intel_dig_port->dp;
    561  1.1  riastrad 	struct intel_lspcon *lspcon = &intel_dig_port->lspcon;
    562  1.1  riastrad 	struct drm_device *dev = intel_dig_port->base.base.dev;
    563  1.1  riastrad 	struct drm_i915_private *dev_priv = to_i915(dev);
    564  1.1  riastrad 	struct drm_connector *connector = &dp->attached_connector->base;
    565  1.1  riastrad 
    566  1.1  riastrad 	if (!HAS_LSPCON(dev_priv)) {
    567  1.1  riastrad 		DRM_ERROR("LSPCON is not supported on this platform\n");
    568  1.1  riastrad 		return false;
    569  1.1  riastrad 	}
    570  1.1  riastrad 
    571  1.1  riastrad 	lspcon->active = false;
    572  1.1  riastrad 	lspcon->mode = DRM_LSPCON_MODE_INVALID;
    573  1.1  riastrad 
    574  1.1  riastrad 	if (!lspcon_probe(lspcon)) {
    575  1.1  riastrad 		DRM_ERROR("Failed to probe lspcon\n");
    576  1.1  riastrad 		return false;
    577  1.1  riastrad 	}
    578  1.1  riastrad 
    579  1.1  riastrad 	if (!intel_dp_read_dpcd(dp)) {
    580  1.1  riastrad 		DRM_ERROR("LSPCON DPCD read failed\n");
    581  1.1  riastrad 		return false;
    582  1.1  riastrad 	}
    583  1.1  riastrad 
    584  1.1  riastrad 	if (!lspcon_detect_vendor(lspcon)) {
    585  1.1  riastrad 		DRM_ERROR("LSPCON vendor detection failed\n");
    586  1.1  riastrad 		return false;
    587  1.1  riastrad 	}
    588  1.1  riastrad 
    589  1.1  riastrad 	connector->ycbcr_420_allowed = true;
    590  1.1  riastrad 	lspcon->active = true;
    591  1.1  riastrad 	DRM_DEBUG_KMS("Success: LSPCON init\n");
    592  1.1  riastrad 	return true;
    593  1.1  riastrad }
    594