File Index
Files and directories
Sign in
FILE

intel_lspcon.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/i915/display/intel_lspcon.c C
  1/*
  2 * Copyright © 2016 Intel Corporation
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice (including the next
 12 * paragraph) shall be included in all copies or substantial portions of the
 13 * Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 21 * DEALINGS IN THE SOFTWARE.
 22 *
 23 *
 24 */
 25
 26#include <linux/iopoll.h>
 27
 28#include <drm/display/drm_dp_dual_mode_helper.h>
 29#include <drm/display/drm_hdmi_helper.h>
 30#include <drm/drm_atomic_helper.h>
 31#include <drm/drm_edid.h>
 32#include <drm/drm_print.h>
 33
 34#include "intel_de.h"
 35#include "intel_display_regs.h"
 36#include "intel_display_types.h"
 37#include "intel_display_utils.h"
 38#include "intel_dp.h"
 39#include "intel_hdmi.h"
 40#include "intel_lspcon.h"
 41
 42/* LSPCON OUI Vendor ID(signatures) */
 43#define LSPCON_VENDOR_PARADE_OUI 0x001CF8
 44#define LSPCON_VENDOR_MCA_OUI 0x0060AD
 45
 46#define DPCD_MCA_LSPCON_HDR_STATUS	0x70003
 47#define DPCD_PARADE_LSPCON_HDR_STATUS	0x00511
 48
 49/* AUX addresses to write MCA AVI IF */
 50#define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
 51#define LSPCON_MCA_AVI_IF_CTRL 0x5DF
 52#define  LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
 53#define  LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
 54
 55/* AUX addresses to write Parade AVI IF */
 56#define LSPCON_PARADE_AVI_IF_WRITE_OFFSET 0x516
 57#define LSPCON_PARADE_AVI_IF_CTRL 0x51E
 58#define  LSPCON_PARADE_AVI_IF_KICKOFF (1 << 7)
 59#define LSPCON_PARADE_AVI_IF_DATA_SIZE 32
 60
 61static struct intel_lspcon *enc_to_intel_lspcon(struct intel_encoder *encoder)
 62{
 63	return &enc_to_dig_port(encoder)->lspcon;
 64}
 65
 66static struct intel_dp *lspcon_to_intel_dp(struct intel_lspcon *lspcon)
 67{
 68	struct intel_digital_port *dig_port =
 69		container_of(lspcon, struct intel_digital_port, lspcon);
 70
 71	return &dig_port->dp;
 72}
 73
 74static const char *lspcon_mode_name(enum drm_lspcon_mode mode)
 75{
 76	switch (mode) {
 77	case DRM_LSPCON_MODE_PCON:
 78		return "PCON";
 79	case DRM_LSPCON_MODE_LS:
 80		return "LS";
 81	case DRM_LSPCON_MODE_INVALID:
 82		return "INVALID";
 83	default:
 84		MISSING_CASE(mode);
 85		return "INVALID";
 86	}
 87}
 88
 89static bool lspcon_detect_vendor(struct intel_lspcon *lspcon)
 90{
 91	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
 92	struct intel_display *display = to_intel_display(intel_dp);
 93	struct drm_dp_dpcd_ident *ident;
 94	u32 vendor_oui;
 95
 96	if (drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc, drm_dp_is_branch(intel_dp->dpcd))) {
 97		drm_err(display->drm, "Can't read description\n");
 98		return false;
 99	}
100
101	ident = &intel_dp->desc.ident;
102	vendor_oui = (ident->oui[0] << 16) | (ident->oui[1] << 8) |
103		      ident->oui[2];
104
105	switch (vendor_oui) {
106	case LSPCON_VENDOR_MCA_OUI:
107		lspcon->vendor = LSPCON_VENDOR_MCA;
108		drm_dbg_kms(display->drm, "Vendor: Mega Chips\n");
109		break;
110
111	case LSPCON_VENDOR_PARADE_OUI:
112		lspcon->vendor = LSPCON_VENDOR_PARADE;
113		drm_dbg_kms(display->drm, "Vendor: Parade Tech\n");
114		break;
115
116	default:
117		drm_err(display->drm, "Invalid/Unknown vendor OUI\n");
118		return false;
119	}
120
121	return true;
122}
123
124static u32 get_hdr_status_reg(struct intel_lspcon *lspcon)
125{
126	if (lspcon->vendor == LSPCON_VENDOR_MCA)
127		return DPCD_MCA_LSPCON_HDR_STATUS;
128	else
129		return DPCD_PARADE_LSPCON_HDR_STATUS;
130}
131
132bool intel_lspcon_detect_hdr_capability(struct intel_digital_port *dig_port)
133{
134	struct intel_lspcon *lspcon = &dig_port->lspcon;
135	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
136	struct intel_display *display = to_intel_display(intel_dp);
137	u8 hdr_caps;
138	int ret;
139
140	ret = drm_dp_dpcd_read(&intel_dp->aux, get_hdr_status_reg(lspcon),
141			       &hdr_caps, 1);
142
143	if (ret < 0) {
144		drm_dbg_kms(display->drm, "HDR capability detection failed\n");
145		lspcon->hdr_supported = false;
146	} else if (hdr_caps & 0x1) {
147		drm_dbg_kms(display->drm, "LSPCON capable of HDR\n");
148		lspcon->hdr_supported = true;
149	}
150
151	return lspcon->hdr_supported;
152}
153
154static enum drm_lspcon_mode lspcon_get_current_mode(struct intel_lspcon *lspcon)
155{
156	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
157	struct intel_display *display = to_intel_display(intel_dp);
158	enum drm_lspcon_mode current_mode;
159	struct i2c_adapter *ddc = &intel_dp->aux.ddc;
160
161	if (drm_lspcon_get_mode(intel_dp->aux.drm_dev, ddc, &current_mode)) {
162		drm_dbg_kms(display->drm, "Error reading LSPCON mode\n");
163		return DRM_LSPCON_MODE_INVALID;
164	}
165	return current_mode;
166}
167
168static int lspcon_get_mode_settle_timeout(struct intel_lspcon *lspcon)
169{
170	/*
171	 * On some CometLake-based device designs the Parade PS175 takes more
172	 * than 400ms to settle in PCON mode. 100 reboot trials on one device
173	 * resulted in a median settle time of 440ms and a maximum of 444ms.
174	 * Even after increasing the timeout to 500ms, 2% of devices still had
175	 * this error. So this sets the timeout to 800ms.
176	 */
177	return lspcon->vendor == LSPCON_VENDOR_PARADE ? 800 : 400;
178}
179
180static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon,
181					     enum drm_lspcon_mode mode)
182{
183	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
184	struct intel_display *display = to_intel_display(intel_dp);
185	enum drm_lspcon_mode current_mode;
186	int timeout_us;
187	int ret;
188
189	current_mode = lspcon_get_current_mode(lspcon);
190	if (current_mode == mode)
191		goto out;
192
193	drm_dbg_kms(display->drm, "Waiting for LSPCON mode %s to settle\n",
194		    lspcon_mode_name(mode));
195
196	timeout_us = lspcon_get_mode_settle_timeout(lspcon) * 1000;
197
198	ret = poll_timeout_us(current_mode = lspcon_get_current_mode(lspcon),
199			      current_mode == mode,
200			      5000, timeout_us, false);
201	if (ret)
202		drm_err(display->drm, "LSPCON mode hasn't settled\n");
203
204out:
205	drm_dbg_kms(display->drm, "Current LSPCON mode %s\n",
206		    lspcon_mode_name(current_mode));
207
208	return current_mode;
209}
210
211static int lspcon_change_mode(struct intel_lspcon *lspcon,
212			      enum drm_lspcon_mode mode)
213{
214	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
215	struct intel_display *display = to_intel_display(intel_dp);
216	int err;
217	enum drm_lspcon_mode current_mode;
218	struct i2c_adapter *ddc = &intel_dp->aux.ddc;
219
220	err = drm_lspcon_get_mode(intel_dp->aux.drm_dev, ddc, &current_mode);
221	if (err) {
222		drm_err(display->drm, "Error reading LSPCON mode\n");
223		return err;
224	}
225
226	if (current_mode == mode) {
227		drm_dbg_kms(display->drm, "Current mode = desired LSPCON mode\n");
228		return 0;
229	}
230
231	err = drm_lspcon_set_mode(intel_dp->aux.drm_dev, ddc, mode,
232				  lspcon_get_mode_settle_timeout(lspcon));
233	if (err < 0) {
234		drm_err(display->drm, "LSPCON mode change failed\n");
235		return err;
236	}
237
238	lspcon->mode = mode;
239	drm_dbg_kms(display->drm, "LSPCON mode changed done\n");
240	return 0;
241}
242
243static bool lspcon_wake_native_aux_ch(struct intel_lspcon *lspcon)
244{
245	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
246	struct intel_display *display = to_intel_display(intel_dp);
247	u8 rev;
248
249	if (drm_dp_dpcd_readb(&lspcon_to_intel_dp(lspcon)->aux, DP_DPCD_REV,
250			      &rev) != 1) {
251		drm_dbg_kms(display->drm, "Native AUX CH down\n");
252		return false;
253	}
254
255	drm_dbg_kms(display->drm, "Native AUX CH up, DPCD version: %d.%d\n",
256		    rev >> 4, rev & 0xf);
257
258	return true;
259}
260
261static bool lspcon_probe(struct intel_lspcon *lspcon)
262{
263	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
264	struct intel_display *display = to_intel_display(intel_dp);
265	struct i2c_adapter *ddc = &intel_dp->aux.ddc;
266	enum drm_dp_dual_mode_type adaptor_type;
267	enum drm_lspcon_mode expected_mode;
268	int retry;
269
270	expected_mode = lspcon_wake_native_aux_ch(lspcon) ?
271			DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS;
272
273	/* Lets probe the adaptor and check its type */
274	for (retry = 0; retry < 6; retry++) {
275		if (retry)
276			usleep_range(500, 1000);
277
278		adaptor_type = drm_dp_dual_mode_detect(intel_dp->aux.drm_dev, ddc);
279		if (adaptor_type == DRM_DP_DUAL_MODE_LSPCON)
280			break;
281	}
282
283	if (adaptor_type != DRM_DP_DUAL_MODE_LSPCON) {
284		drm_dbg_kms(display->drm, "No LSPCON detected, found %s\n",
285			    drm_dp_get_dual_mode_type_name(adaptor_type));
286		return false;
287	}
288
289	/* Yay ... got a LSPCON device */
290	drm_dbg_kms(display->drm, "LSPCON detected\n");
291	lspcon->mode = lspcon_wait_mode(lspcon, expected_mode);
292
293	/*
294	 * In the SW state machine, lets Put LSPCON in PCON mode only.
295	 * In this way, it will work with both HDMI 1.4 sinks as well as HDMI
296	 * 2.0 sinks.
297	 */
298	if (lspcon->mode != DRM_LSPCON_MODE_PCON) {
299		if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON) < 0) {
300			drm_err(display->drm, "LSPCON mode change to PCON failed\n");
301			return false;
302		}
303	}
304	return true;
305}
306
307static void lspcon_resume_in_pcon_wa(struct intel_lspcon *lspcon)
308{
309	struct intel_dp *intel_dp = lspcon_to_intel_dp(lspcon);
310	struct intel_display *display = to_intel_display(intel_dp);
311	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
312	unsigned long start = jiffies;
313
314	while (1) {
315		if (intel_digital_port_connected(&dig_port->base)) {
316			drm_dbg_kms(display->drm, "LSPCON recovering in PCON mode after %u ms\n",
317				    jiffies_to_msecs(jiffies - start));
318			return;
319		}
320
321		if (time_after(jiffies, start + msecs_to_jiffies(1000)))
322			break;
323
324		usleep_range(10000, 15000);
325	}
326
327	drm_dbg_kms(display->drm, "LSPCON DP descriptor mismatch after resume\n");
328}
329
330static bool lspcon_parade_fw_ready(struct drm_dp_aux *aux)
331{
332	u8 avi_if_ctrl;
333	u8 retry;
334	ssize_t ret;
335
336	/* Check if LSPCON FW is ready for data */
337	for (retry = 0; retry < 5; retry++) {
338		if (retry)
339			usleep_range(200, 300);
340
341		ret = drm_dp_dpcd_read(aux, LSPCON_PARADE_AVI_IF_CTRL,
342				       &avi_if_ctrl, 1);
343		if (ret < 0) {
344			drm_err(aux->drm_dev, "Failed to read AVI IF control\n");
345			return false;
346		}
347
348		if ((avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF) == 0)
349			return true;
350	}
351
352	drm_err(aux->drm_dev, "Parade FW not ready to accept AVI IF\n");
353	return false;
354}
355
356static bool _lspcon_parade_write_infoframe_blocks(struct drm_dp_aux *aux,
357						  u8 *avi_buf)
358{
359	u8 avi_if_ctrl;
360	u8 block_count = 0;
361	u8 *data;
362	u16 reg;
363	ssize_t ret;
364
365	while (block_count < 4) {
366		if (!lspcon_parade_fw_ready(aux)) {
367			drm_dbg_kms(aux->drm_dev, "LSPCON FW not ready, block %d\n",
368				    block_count);
369			return false;
370		}
371
372		reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET;
373		data = avi_buf + block_count * 8;
374		ret = drm_dp_dpcd_write(aux, reg, data, 8);
375		if (ret < 0) {
376			drm_err(aux->drm_dev, "Failed to write AVI IF block %d\n",
377				block_count);
378			return false;
379		}
380
381		/*
382		 * Once a block of data is written, we have to inform the FW
383		 * about this by writing into avi infoframe control register:
384		 * - set the kickoff bit[7] to 1
385		 * - write the block no. to bits[1:0]
386		 */
387		reg = LSPCON_PARADE_AVI_IF_CTRL;
388		avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count;
389		ret = drm_dp_dpcd_write(aux, reg, &avi_if_ctrl, 1);
390		if (ret < 0) {
391			drm_err(aux->drm_dev, "Failed to update (0x%x), block %d\n",
392				reg, block_count);
393			return false;
394		}
395
396		block_count++;
397	}
398
399	drm_dbg_kms(aux->drm_dev, "Wrote AVI IF blocks successfully\n");
400	return true;
401}
402
403static bool _lspcon_write_avi_infoframe_parade(struct drm_dp_aux *aux,
404					       const u8 *frame,
405					       ssize_t len)
406{
407	u8 avi_if[LSPCON_PARADE_AVI_IF_DATA_SIZE] = {1, };
408
409	/*
410	 * Parade's frames contains 32 bytes of data, divided
411	 * into 4 frames:
412	 *	Token byte (first byte of first frame, must be non-zero)
413	 *	HB0 to HB2	 from AVI IF (3 bytes header)
414	 *	PB0 to PB27 from AVI IF (28 bytes data)
415	 * So it should look like this
416	 *	first block: | <token> <HB0-HB2> <DB0-DB3> |
417	 *	next 3 blocks: |<DB4-DB11>|<DB12-DB19>|<DB20-DB28>|
418	 */
419
420	if (len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1) {
421		drm_err(aux->drm_dev, "Invalid length of infoframes\n");
422		return false;
423	}
424
425	memcpy(&avi_if[1], frame, len);
426
427	if (!_lspcon_parade_write_infoframe_blocks(aux, avi_if)) {
428		drm_dbg_kms(aux->drm_dev, "Failed to write infoframe blocks\n");
429		return false;
430	}
431
432	return true;
433}
434
435static bool _lspcon_write_avi_infoframe_mca(struct drm_dp_aux *aux,
436					    const u8 *buffer, ssize_t len)
437{
438	int ret;
439	u32 val = 0;
440	u32 retry;
441	u16 reg;
442	const u8 *data = buffer;
443
444	reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET;
445	while (val < len) {
446		/* DPCD write for AVI IF can fail on a slow FW day, so retry */
447		for (retry = 0; retry < 5; retry++) {
448			ret = drm_dp_dpcd_write(aux, reg, (void *)data, 1);
449			if (ret == 1) {
450				break;
451			} else if (retry < 4) {
452				mdelay(50);
453				continue;
454			} else {
455				drm_err(aux->drm_dev, "DPCD write failed at:0x%x\n", reg);
456				return false;
457			}
458		}
459		val++; reg++; data++;
460	}
461
462	val = 0;
463	reg = LSPCON_MCA_AVI_IF_CTRL;
464	ret = drm_dp_dpcd_read(aux, reg, &val, 1);
465	if (ret < 0) {
466		drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
467		return false;
468	}
469
470	/* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
471	val &= ~LSPCON_MCA_AVI_IF_HANDLED;
472	val |= LSPCON_MCA_AVI_IF_KICKOFF;
473
474	ret = drm_dp_dpcd_write(aux, reg, &val, 1);
475	if (ret < 0) {
476		drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
477		return false;
478	}
479
480	val = 0;
481	ret = drm_dp_dpcd_read(aux, reg, &val, 1);
482	if (ret < 0) {
483		drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
484		return false;
485	}
486
487	if (val == LSPCON_MCA_AVI_IF_HANDLED)
488		drm_dbg_kms(aux->drm_dev, "AVI IF handled by FW\n");
489
490	return true;
491}
492
493void lspcon_write_infoframe(struct intel_encoder *encoder,
494			    const struct intel_crtc_state *crtc_state,
495			    unsigned int type,
496			    const void *frame, ssize_t len)
497{
498	struct intel_display *display = to_intel_display(encoder);
499	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
500	struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder);
501	bool ret = true;
502
503	switch (type) {
504	case HDMI_INFOFRAME_TYPE_AVI:
505		if (lspcon->vendor == LSPCON_VENDOR_MCA)
506			ret = _lspcon_write_avi_infoframe_mca(&intel_dp->aux,
507							      frame, len);
508		else
509			ret = _lspcon_write_avi_infoframe_parade(&intel_dp->aux,
510								 frame, len);
511		break;
512	case HDMI_PACKET_TYPE_GAMUT_METADATA:
513		drm_dbg_kms(display->drm, "Update HDR metadata for lspcon\n");
514		/* It uses the legacy hsw implementation for the same */
515		hsw_write_infoframe(encoder, crtc_state, type, frame, len);
516		break;
517	default:
518		return;
519	}
520
521	if (!ret) {
522		drm_err(display->drm, "Failed to write infoframes\n");
523		return;
524	}
525}
526
527void lspcon_read_infoframe(struct intel_encoder *encoder,
528			   const struct intel_crtc_state *crtc_state,
529			   unsigned int type,
530			   void *frame, ssize_t len)
531{
532	/* FIXME implement for AVI Infoframe as well */
533	if (type == HDMI_PACKET_TYPE_GAMUT_METADATA)
534		hsw_read_infoframe(encoder, crtc_state, type,
535				   frame, len);
536}
537
538void lspcon_set_infoframes(struct intel_encoder *encoder,
539			   bool enable,
540			   const struct intel_crtc_state *crtc_state,
541			   const struct drm_connector_state *conn_state)
542{
543	struct intel_display *display = to_intel_display(encoder);
544	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
545	struct intel_lspcon *lspcon = &dig_port->lspcon;
546	const struct drm_display_mode *adjusted_mode =
547		&crtc_state->hw.adjusted_mode;
548	union hdmi_infoframe frame;
549	u8 buf[VIDEO_DIP_DATA_SIZE];
550	ssize_t ret;
551
552	if (!lspcon->active) {
553		drm_err(display->drm, "Writing infoframes while LSPCON disabled ?\n");
554		return;
555	}
556
557	/* FIXME precompute infoframes */
558
559	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
560						       conn_state->connector,
561						       adjusted_mode);
562	if (ret < 0) {
563		drm_err(display->drm, "couldn't fill AVI infoframe\n");
564		return;
565	}
566
567	/*
568	 * Currently there is no interface defined to
569	 * check user preference between RGB/YCBCR444
570	 * or YCBCR420. So the only possible case for
571	 * YCBCR444 usage is driving YCBCR420 output
572	 * with LSPCON, when pipe is configured for
573	 * YCBCR444 output and LSPCON takes care of
574	 * downsampling it.
575	 */
576	if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_YCBCR444)
577		frame.avi.colorspace = HDMI_COLORSPACE_YUV420;
578	else
579		frame.avi.colorspace = HDMI_COLORSPACE_RGB;
580
581	/* Set the Colorspace as per the HDMI spec */
582	drm_hdmi_avi_infoframe_colorimetry(&frame.avi, conn_state);
583
584	/* nonsense combination */
585	drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range &&
586		    crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB);
587
588	if (crtc_state->output_format == INTEL_OUTPUT_FORMAT_RGB) {
589		drm_hdmi_avi_infoframe_quant_range(&frame.avi,
590						   conn_state->connector,
591						   adjusted_mode,
592						   crtc_state->limited_color_range ?
593						   HDMI_QUANTIZATION_RANGE_LIMITED :
594						   HDMI_QUANTIZATION_RANGE_FULL);
595	} else {
596		frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
597		frame.avi.ycc_quantization_range = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
598	}
599
600	drm_hdmi_avi_infoframe_content_type(&frame.avi, conn_state);
601
602	ret = hdmi_infoframe_pack(&frame, buf, sizeof(buf));
603	if (ret < 0) {
604		drm_err(display->drm, "Failed to pack AVI IF\n");
605		return;
606	}
607
608	dig_port->write_infoframe(encoder, crtc_state, HDMI_INFOFRAME_TYPE_AVI,
609				  buf, ret);
610}
611
612static bool _lspcon_read_avi_infoframe_enabled_mca(struct drm_dp_aux *aux)
613{
614	int ret;
615	u32 val = 0;
616	u16 reg = LSPCON_MCA_AVI_IF_CTRL;
617
618	ret = drm_dp_dpcd_read(aux, reg, &val, 1);
619	if (ret < 0) {
620		drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
621		return false;
622	}
623
624	return val & LSPCON_MCA_AVI_IF_KICKOFF;
625}
626
627static bool _lspcon_read_avi_infoframe_enabled_parade(struct drm_dp_aux *aux)
628{
629	int ret;
630	u32 val = 0;
631	u16 reg = LSPCON_PARADE_AVI_IF_CTRL;
632
633	ret = drm_dp_dpcd_read(aux, reg, &val, 1);
634	if (ret < 0) {
635		drm_err(aux->drm_dev, "DPCD read failed, address 0x%x\n", reg);
636		return false;
637	}
638
639	return val & LSPCON_PARADE_AVI_IF_KICKOFF;
640}
641
642u32 lspcon_infoframes_enabled(struct intel_encoder *encoder,
643			      const struct intel_crtc_state *pipe_config)
644{
645	struct intel_display *display = to_intel_display(encoder);
646	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
647	struct intel_lspcon *lspcon = enc_to_intel_lspcon(encoder);
648	bool infoframes_enabled;
649	u32 val = 0;
650	u32 mask, tmp;
651
652	if (lspcon->vendor == LSPCON_VENDOR_MCA)
653		infoframes_enabled = _lspcon_read_avi_infoframe_enabled_mca(&intel_dp->aux);
654	else
655		infoframes_enabled = _lspcon_read_avi_infoframe_enabled_parade(&intel_dp->aux);
656
657	if (infoframes_enabled)
658		val |= intel_hdmi_infoframe_enable(HDMI_INFOFRAME_TYPE_AVI);
659
660	if (lspcon->hdr_supported) {
661		tmp = intel_de_read(display,
662				    HSW_TVIDEO_DIP_CTL(display, pipe_config->cpu_transcoder));
663		mask = VIDEO_DIP_ENABLE_GMP_HSW;
664
665		if (tmp & mask)
666			val |= intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
667	}
668
669	return val;
670}
671
672void intel_lspcon_wait_pcon_mode(struct intel_digital_port *dig_port)
673{
674	struct intel_lspcon *lspcon = &dig_port->lspcon;
675
676	lspcon_wait_mode(lspcon, DRM_LSPCON_MODE_PCON);
677}
678
679bool intel_lspcon_init(struct intel_digital_port *dig_port)
680{
681	struct intel_display *display = to_intel_display(dig_port);
682	struct intel_dp *intel_dp = &dig_port->dp;
683	struct intel_lspcon *lspcon = &dig_port->lspcon;
684	struct drm_connector *connector = &intel_dp->attached_connector->base;
685
686	lspcon->active = false;
687	lspcon->mode = DRM_LSPCON_MODE_INVALID;
688
689	if (!lspcon_probe(lspcon)) {
690		drm_err(display->drm, "Failed to probe lspcon\n");
691		return false;
692	}
693
694	if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd) != 0) {
695		drm_err(display->drm, "LSPCON DPCD read failed\n");
696		return false;
697	}
698
699	if (!lspcon_detect_vendor(lspcon)) {
700		drm_err(display->drm, "LSPCON vendor detection failed\n");
701		return false;
702	}
703
704	connector->ycbcr_420_allowed = true;
705	lspcon->active = true;
706	drm_dbg_kms(display->drm, "Success: LSPCON init\n");
707	return true;
708}
709
710bool intel_lspcon_active(struct intel_digital_port *dig_port)
711{
712	struct intel_lspcon *lspcon = &dig_port->lspcon;
713
714	return lspcon->active;
715}
716
717u32 intel_lspcon_infoframes_enabled(struct intel_encoder *encoder,
718				    const struct intel_crtc_state *pipe_config)
719{
720	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
721
722	return dig_port->infoframes_enabled(encoder, pipe_config);
723}
724
725void intel_lspcon_resume(struct intel_digital_port *dig_port)
726{
727	struct intel_display *display = to_intel_display(dig_port);
728	struct intel_lspcon *lspcon = &dig_port->lspcon;
729	enum drm_lspcon_mode expected_mode;
730
731	if (!intel_bios_encoder_is_lspcon(dig_port->base.devdata))
732		return;
733
734	if (!lspcon->active) {
735		if (!intel_lspcon_init(dig_port)) {
736			drm_err(display->drm, "LSPCON init failed on port %c\n",
737				port_name(dig_port->base.port));
738			return;
739		}
740	}
741
742	if (lspcon_wake_native_aux_ch(lspcon)) {
743		expected_mode = DRM_LSPCON_MODE_PCON;
744		lspcon_resume_in_pcon_wa(lspcon);
745	} else {
746		expected_mode = DRM_LSPCON_MODE_LS;
747	}
748
749	if (lspcon_wait_mode(lspcon, expected_mode) == DRM_LSPCON_MODE_PCON)
750		return;
751
752	if (lspcon_change_mode(lspcon, DRM_LSPCON_MODE_PCON))
753		drm_err(display->drm, "LSPCON resume failed\n");
754	else
755		drm_dbg_kms(display->drm, "LSPCON resume success\n");
756}
~/ Read-only file preview.