File Index
Files and directories
Sign in
FILE

intel_alpm.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/i915/display/intel_alpm.c C
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright 2024, Intel Corporation.
  4 */
  5
  6#include <linux/debugfs.h>
  7
  8#include <drm/drm_print.h>
  9
 10#include "intel_alpm.h"
 11#include "intel_crtc.h"
 12#include "intel_de.h"
 13#include "intel_display_types.h"
 14#include "intel_dp.h"
 15#include "intel_dp_aux.h"
 16#include "intel_psr.h"
 17#include "intel_psr_regs.h"
 18
 19#define SILENCE_PERIOD_MIN_TIME	80
 20#define SILENCE_PERIOD_MAX_TIME	180
 21#define SILENCE_PERIOD_TIME	(SILENCE_PERIOD_MIN_TIME +	\
 22				(SILENCE_PERIOD_MAX_TIME -	\
 23				 SILENCE_PERIOD_MIN_TIME) / 2)
 24
 25#define LFPS_CYCLE_COUNT 10
 26
 27bool intel_alpm_aux_wake_supported(struct intel_dp *intel_dp)
 28{
 29	return intel_dp->alpm_dpcd & DP_ALPM_CAP;
 30}
 31
 32bool intel_alpm_aux_less_wake_supported(struct intel_dp *intel_dp)
 33{
 34	return intel_dp->alpm_dpcd & DP_ALPM_AUX_LESS_CAP;
 35}
 36
 37bool intel_alpm_is_alpm_aux_less(struct intel_dp *intel_dp,
 38				 const struct intel_crtc_state *crtc_state)
 39{
 40	return intel_psr_needs_alpm_aux_less(intel_dp, crtc_state) ||
 41		(crtc_state->has_lobf && intel_alpm_aux_less_wake_supported(intel_dp));
 42}
 43
 44void intel_alpm_init(struct intel_dp *intel_dp)
 45{
 46	mutex_init(&intel_dp->alpm.lock);
 47}
 48
 49static int get_silence_period_symbols(const struct intel_crtc_state *crtc_state)
 50{
 51	return SILENCE_PERIOD_TIME * intel_dp_link_symbol_clock(crtc_state->port_clock) /
 52		1000 / 1000;
 53}
 54
 55static void get_lfps_cycle_min_max_time(const struct intel_crtc_state *crtc_state,
 56					int *min, int *max)
 57{
 58	if (crtc_state->port_clock < 540000) {
 59		*min = 65 * LFPS_CYCLE_COUNT;
 60		*max = 75 * LFPS_CYCLE_COUNT;
 61	} else {
 62		*min = 140;
 63		*max = 800;
 64	}
 65}
 66
 67static int get_lfps_cycle_time(const struct intel_crtc_state *crtc_state)
 68{
 69	int tlfps_cycle_min, tlfps_cycle_max;
 70
 71	get_lfps_cycle_min_max_time(crtc_state, &tlfps_cycle_min,
 72				    &tlfps_cycle_max);
 73
 74	return tlfps_cycle_min +  (tlfps_cycle_max - tlfps_cycle_min) / 2;
 75}
 76
 77static int get_lfps_half_cycle_clocks(const struct intel_crtc_state *crtc_state)
 78{
 79	return get_lfps_cycle_time(crtc_state) * crtc_state->port_clock / 1000 /
 80		1000 / (2 * LFPS_CYCLE_COUNT);
 81}
 82
 83/*
 84 * AUX-Less Wake Time = CEILING( ((PHY P2 to P0) + tLFPS_Period, Max+
 85 * tSilence, Max+ tPHY Establishment + tCDS) / tline)
 86 * For the "PHY P2 to P0" latency see the PHY Power Control page
 87 * (PHY P2 to P0) : https://gfxspecs.intel.com/Predator/Home/Index/68965
 88 * : 12 us
 89 * The tLFPS_Period, Max term is 800ns
 90 * The tSilence, Max term is 180ns
 91 * The tPHY Establishment (a.k.a. t1) term is 50us
 92 * The tCDS term is 1 or 2 times t2
 93 * t2 = Number ML_PHY_LOCK * tML_PHY_LOCK
 94 * Number ML_PHY_LOCK = ( 7 + CEILING( 6.5us / tML_PHY_LOCK ) + 1)
 95 * Rounding up the 6.5us padding to the next ML_PHY_LOCK boundary and
 96 * adding the "+ 1" term ensures all ML_PHY_LOCK sequences that start
 97 * within the CDS period complete within the CDS period regardless of
 98 * entry into the period
 99 * tML_PHY_LOCK = TPS4 Length * ( 10 / (Link Rate in MHz) )
100 * TPS4 Length = 252 Symbols
101 */
102static int _lnl_compute_aux_less_wake_time(const struct intel_crtc_state *crtc_state)
103{
104	int tphy2_p2_to_p0 = 12 * 1000;
105	int t1 = 50 * 1000;
106	int tps4 = 252;
107	/* port_clock is link rate in 10kbit/s units */
108	int tml_phy_lock = 1000 * 1000 * tps4 / crtc_state->port_clock;
109	int num_ml_phy_lock = 7 + DIV_ROUND_UP(6500, tml_phy_lock) + 1;
110	int t2 = num_ml_phy_lock * tml_phy_lock;
111	int tcds = 1 * t2;
112
113	return DIV_ROUND_UP(tphy2_p2_to_p0 + get_lfps_cycle_time(crtc_state) +
114			    SILENCE_PERIOD_TIME + t1 + tcds, 1000);
115}
116
117static int
118_lnl_compute_aux_less_alpm_params(struct intel_dp *intel_dp,
119				  struct intel_crtc_state *crtc_state)
120{
121	struct intel_display *display = to_intel_display(intel_dp);
122	int aux_less_wake_time, aux_less_wake_lines, silence_period,
123		lfps_half_cycle;
124
125	aux_less_wake_time =
126		_lnl_compute_aux_less_wake_time(crtc_state);
127	aux_less_wake_lines = intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode,
128						       aux_less_wake_time);
129	silence_period = get_silence_period_symbols(crtc_state);
130
131	lfps_half_cycle = get_lfps_half_cycle_clocks(crtc_state);
132
133	if (aux_less_wake_lines > ALPM_CTL_AUX_LESS_WAKE_TIME_MASK ||
134	    silence_period > PORT_ALPM_CTL_SILENCE_PERIOD_MASK ||
135	    lfps_half_cycle > PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION_MASK)
136		return false;
137
138	if (display->params.psr_safest_params)
139		aux_less_wake_lines = ALPM_CTL_AUX_LESS_WAKE_TIME_MASK;
140
141	crtc_state->alpm_state.aux_less_wake_lines = aux_less_wake_lines;
142	crtc_state->alpm_state.silence_period_sym_clocks = silence_period;
143	crtc_state->alpm_state.lfps_half_cycle_num_of_syms = lfps_half_cycle;
144
145	return true;
146}
147
148static bool _lnl_compute_alpm_params(struct intel_dp *intel_dp,
149				     struct intel_crtc_state *crtc_state)
150{
151	struct intel_display *display = to_intel_display(intel_dp);
152	int check_entry_lines;
153
154	if (DISPLAY_VER(display) < 20)
155		return true;
156
157	/* ALPM Entry Check = 2 + CEILING( 5us /tline ) */
158	check_entry_lines = 2 +
159		intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode, 5);
160
161	if (check_entry_lines > 15)
162		return false;
163
164	if (!_lnl_compute_aux_less_alpm_params(intel_dp, crtc_state))
165		return false;
166
167	if (display->params.psr_safest_params)
168		check_entry_lines = 15;
169
170	crtc_state->alpm_state.check_entry_lines = check_entry_lines;
171
172	return true;
173}
174
175/*
176 * IO wake time for DISPLAY_VER < 12 is not directly mentioned in Bspec. There
177 * are 50 us io wake time and 32 us fast wake time. Clearly preharge pulses are
178 * not (improperly) included in 32 us fast wake time. 50 us - 32 us = 18 us.
179 */
180static int skl_io_buffer_wake_time(void)
181{
182	return 18;
183}
184
185static int tgl_io_buffer_wake_time(void)
186{
187	return 10;
188}
189
190static int io_buffer_wake_time(const struct intel_crtc_state *crtc_state)
191{
192	struct intel_display *display = to_intel_display(crtc_state);
193
194	if (DISPLAY_VER(display) >= 12)
195		return tgl_io_buffer_wake_time();
196	else
197		return skl_io_buffer_wake_time();
198}
199
200bool intel_alpm_compute_params(struct intel_dp *intel_dp,
201			       struct intel_crtc_state *crtc_state)
202{
203	struct intel_display *display = to_intel_display(intel_dp);
204	int io_wake_lines, io_wake_time, fast_wake_lines, fast_wake_time;
205	int tfw_exit_latency = 20; /* eDP spec */
206	int phy_wake = 4;	   /* eDP spec */
207	int preamble = 8;	   /* eDP spec */
208	int precharge = intel_dp_aux_fw_sync_len(intel_dp) - preamble;
209	u8 max_wake_lines;
210
211	io_wake_time = max(precharge, io_buffer_wake_time(crtc_state)) +
212		preamble + phy_wake + tfw_exit_latency;
213	fast_wake_time = precharge + preamble + phy_wake +
214		tfw_exit_latency;
215
216	if (DISPLAY_VER(display) >= 20)
217		max_wake_lines = 68;
218	else if (DISPLAY_VER(display) >= 12)
219		max_wake_lines = 12;
220	else
221		max_wake_lines = 8;
222
223	io_wake_lines = intel_usecs_to_scanlines(
224		&crtc_state->hw.adjusted_mode, io_wake_time);
225	fast_wake_lines = intel_usecs_to_scanlines(
226		&crtc_state->hw.adjusted_mode, fast_wake_time);
227
228	if (io_wake_lines > max_wake_lines ||
229	    fast_wake_lines > max_wake_lines)
230		return false;
231
232	if (!_lnl_compute_alpm_params(intel_dp, crtc_state))
233		return false;
234
235	if (display->params.psr_safest_params)
236		io_wake_lines = fast_wake_lines = max_wake_lines;
237
238	/* According to Bspec lower limit should be set as 7 lines. */
239	crtc_state->alpm_state.io_wake_lines = max(io_wake_lines, 7);
240	crtc_state->alpm_state.fast_wake_lines = max(fast_wake_lines, 7);
241
242	return true;
243}
244
245void intel_alpm_lobf_compute_config(struct intel_dp *intel_dp,
246				    struct intel_crtc_state *crtc_state,
247				    struct drm_connector_state *conn_state)
248{
249	struct intel_display *display = to_intel_display(intel_dp);
250	struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode;
251	int waketime_in_lines, first_sdp_position;
252	int context_latency, guardband;
253
254	if (intel_dp->alpm.lobf_disable_debug) {
255		drm_dbg_kms(display->drm, "LOBF is disabled by debug flag\n");
256		return;
257	}
258
259	if (intel_dp->alpm.sink_alpm_error)
260		return;
261
262	if (!intel_dp_is_edp(intel_dp))
263		return;
264
265	if (DISPLAY_VER(display) < 20)
266		return;
267
268	if (!intel_dp->as_sdp_supported)
269		return;
270
271	if (crtc_state->has_psr)
272		return;
273
274	if (crtc_state->vrr.vmin != crtc_state->vrr.vmax ||
275	    crtc_state->vrr.vmin != crtc_state->vrr.flipline)
276		return;
277
278	if (!(intel_alpm_aux_wake_supported(intel_dp) ||
279	      intel_alpm_aux_less_wake_supported(intel_dp)))
280		return;
281
282	if (!intel_alpm_compute_params(intel_dp, crtc_state))
283		return;
284
285	context_latency = adjusted_mode->crtc_vblank_start - adjusted_mode->crtc_vdisplay;
286	guardband = adjusted_mode->crtc_vtotal -
287		    adjusted_mode->crtc_vdisplay - context_latency;
288	first_sdp_position = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_start;
289	if (intel_alpm_aux_less_wake_supported(intel_dp))
290		waketime_in_lines = crtc_state->alpm_state.io_wake_lines;
291	else
292		waketime_in_lines = crtc_state->alpm_state.aux_less_wake_lines;
293
294	crtc_state->has_lobf = (context_latency + guardband) >
295		(first_sdp_position + waketime_in_lines);
296}
297
298static void lnl_alpm_configure(struct intel_dp *intel_dp,
299			       const struct intel_crtc_state *crtc_state)
300{
301	struct intel_display *display = to_intel_display(intel_dp);
302	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
303	u32 alpm_ctl;
304
305	if (DISPLAY_VER(display) < 20 || (!intel_psr_needs_alpm(intel_dp, crtc_state) &&
306					  !crtc_state->has_lobf))
307		return;
308
309	mutex_lock(&intel_dp->alpm.lock);
310	/*
311	 * Panel Replay on eDP is always using ALPM aux less. I.e. no need to
312	 * check panel support at this point.
313	 */
314	if (intel_alpm_is_alpm_aux_less(intel_dp, crtc_state)) {
315		alpm_ctl = ALPM_CTL_ALPM_ENABLE |
316			ALPM_CTL_ALPM_AUX_LESS_ENABLE |
317			ALPM_CTL_AUX_LESS_SLEEP_HOLD_TIME_50_SYMBOLS |
318			ALPM_CTL_AUX_LESS_WAKE_TIME(crtc_state->alpm_state.aux_less_wake_lines);
319
320		if (intel_dp->as_sdp_supported) {
321			u32 pr_alpm_ctl = PR_ALPM_CTL_ADAPTIVE_SYNC_SDP_POSITION_T1;
322
323			if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
324			    DP_PANEL_REPLAY_LINK_OFF_SUPPORTED_IN_PR_AFTER_ADAPTIVE_SYNC_SDP)
325				pr_alpm_ctl |= PR_ALPM_CTL_ALLOW_LINK_OFF_BETWEEN_AS_SDP_AND_SU;
326			if (!(intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)] &
327						DP_PANEL_REPLAY_ASYNC_VIDEO_TIMING_NOT_SUPPORTED_IN_PR))
328				pr_alpm_ctl |= PR_ALPM_CTL_AS_SDP_TRANSMISSION_IN_ACTIVE_DISABLE;
329
330			intel_de_write(display, PR_ALPM_CTL(display, cpu_transcoder),
331				       pr_alpm_ctl);
332		}
333
334	} else {
335		alpm_ctl = ALPM_CTL_EXTENDED_FAST_WAKE_ENABLE |
336			ALPM_CTL_EXTENDED_FAST_WAKE_TIME(crtc_state->alpm_state.fast_wake_lines);
337	}
338
339	if (crtc_state->has_lobf) {
340		alpm_ctl |= ALPM_CTL_LOBF_ENABLE;
341		drm_dbg_kms(display->drm, "Link off between frames (LOBF) enabled\n");
342	}
343
344	alpm_ctl |= ALPM_CTL_ALPM_ENTRY_CHECK(crtc_state->alpm_state.check_entry_lines);
345
346	intel_de_write(display, ALPM_CTL(display, cpu_transcoder), alpm_ctl);
347	mutex_unlock(&intel_dp->alpm.lock);
348}
349
350void intel_alpm_configure(struct intel_dp *intel_dp,
351			  const struct intel_crtc_state *crtc_state)
352{
353	lnl_alpm_configure(intel_dp, crtc_state);
354	intel_dp->alpm.transcoder = crtc_state->cpu_transcoder;
355}
356
357void intel_alpm_port_configure(struct intel_dp *intel_dp,
358			       const struct intel_crtc_state *crtc_state)
359{
360	struct intel_display *display = to_intel_display(intel_dp);
361	enum port port = dp_to_dig_port(intel_dp)->base.port;
362	u32 alpm_ctl_val = 0, lfps_ctl_val = 0;
363
364	if (DISPLAY_VER(display) < 20)
365		return;
366
367	if (intel_alpm_is_alpm_aux_less(intel_dp, crtc_state)) {
368		alpm_ctl_val = PORT_ALPM_CTL_ALPM_AUX_LESS_ENABLE |
369			PORT_ALPM_CTL_MAX_PHY_SWING_SETUP(15) |
370			PORT_ALPM_CTL_MAX_PHY_SWING_HOLD(0) |
371			PORT_ALPM_CTL_SILENCE_PERIOD(
372				crtc_state->alpm_state.silence_period_sym_clocks);
373		lfps_ctl_val = PORT_ALPM_LFPS_CTL_LFPS_CYCLE_COUNT(LFPS_CYCLE_COUNT) |
374			PORT_ALPM_LFPS_CTL_LFPS_HALF_CYCLE_DURATION(
375				crtc_state->alpm_state.lfps_half_cycle_num_of_syms) |
376			PORT_ALPM_LFPS_CTL_FIRST_LFPS_HALF_CYCLE_DURATION(
377				crtc_state->alpm_state.lfps_half_cycle_num_of_syms) |
378			PORT_ALPM_LFPS_CTL_LAST_LFPS_HALF_CYCLE_DURATION(
379				crtc_state->alpm_state.lfps_half_cycle_num_of_syms);
380	}
381
382	intel_de_write(display, PORT_ALPM_CTL(port), alpm_ctl_val);
383
384	intel_de_write(display, PORT_ALPM_LFPS_CTL(port), lfps_ctl_val);
385}
386
387void intel_alpm_pre_plane_update(struct intel_atomic_state *state,
388				 struct intel_crtc *crtc)
389{
390	struct intel_display *display = to_intel_display(state);
391	const struct intel_crtc_state *crtc_state =
392		intel_atomic_get_new_crtc_state(state, crtc);
393	const struct intel_crtc_state *old_crtc_state =
394		intel_atomic_get_old_crtc_state(state, crtc);
395	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
396	struct intel_encoder *encoder;
397
398	if (DISPLAY_VER(display) < 20)
399		return;
400
401	if (crtc_state->has_lobf || crtc_state->has_lobf == old_crtc_state->has_lobf)
402		return;
403
404	for_each_intel_encoder_mask(display->drm, encoder,
405				    crtc_state->uapi.encoder_mask) {
406		struct intel_dp *intel_dp;
407
408		if (!intel_encoder_is_dp(encoder))
409			continue;
410
411		intel_dp = enc_to_intel_dp(encoder);
412
413		if (!intel_dp_is_edp(intel_dp))
414			continue;
415
416		if (old_crtc_state->has_lobf) {
417			mutex_lock(&intel_dp->alpm.lock);
418			intel_de_write(display, ALPM_CTL(display, cpu_transcoder), 0);
419			drm_dbg_kms(display->drm, "Link off between frames (LOBF) disabled\n");
420			mutex_unlock(&intel_dp->alpm.lock);
421		}
422	}
423}
424
425void intel_alpm_enable_sink(struct intel_dp *intel_dp,
426			    const struct intel_crtc_state *crtc_state)
427{
428	u8 val;
429
430	if (!intel_psr_needs_alpm(intel_dp, crtc_state) && !crtc_state->has_lobf)
431		return;
432
433	val = DP_ALPM_ENABLE | DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE;
434
435	if (crtc_state->has_panel_replay || (crtc_state->has_lobf &&
436					     intel_alpm_aux_less_wake_supported(intel_dp)))
437		val |= DP_ALPM_MODE_AUX_LESS;
438
439	drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, val);
440}
441
442void intel_alpm_post_plane_update(struct intel_atomic_state *state,
443				  struct intel_crtc *crtc)
444{
445	struct intel_display *display = to_intel_display(state);
446	const struct intel_crtc_state *crtc_state =
447		intel_atomic_get_new_crtc_state(state, crtc);
448	const struct intel_crtc_state *old_crtc_state =
449		intel_atomic_get_old_crtc_state(state, crtc);
450	struct intel_encoder *encoder;
451
452	if (crtc_state->has_psr || !crtc_state->has_lobf ||
453	    crtc_state->has_lobf == old_crtc_state->has_lobf)
454		return;
455
456	for_each_intel_encoder_mask(display->drm, encoder,
457				    crtc_state->uapi.encoder_mask) {
458		struct intel_dp *intel_dp;
459
460		if (!intel_encoder_is_dp(encoder))
461			continue;
462
463		intel_dp = enc_to_intel_dp(encoder);
464
465		if (intel_dp_is_edp(intel_dp)) {
466			intel_alpm_enable_sink(intel_dp, crtc_state);
467			intel_alpm_configure(intel_dp, crtc_state);
468		}
469	}
470}
471
472static int i915_edp_lobf_info_show(struct seq_file *m, void *data)
473{
474	struct intel_connector *connector = m->private;
475	struct intel_display *display = to_intel_display(connector);
476	struct drm_crtc *crtc;
477	struct intel_crtc_state *crtc_state;
478	enum transcoder cpu_transcoder;
479	u32 alpm_ctl;
480	int ret;
481
482	ret = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
483	if (ret)
484		return ret;
485
486	crtc = connector->base.state->crtc;
487	if (connector->base.status != connector_status_connected || !crtc) {
488		ret = -ENODEV;
489		goto out;
490	}
491
492	crtc_state = to_intel_crtc_state(crtc->state);
493	cpu_transcoder = crtc_state->cpu_transcoder;
494	alpm_ctl = intel_de_read(display, ALPM_CTL(display, cpu_transcoder));
495	seq_printf(m, "LOBF status: %s\n", str_enabled_disabled(alpm_ctl & ALPM_CTL_LOBF_ENABLE));
496	seq_printf(m, "Aux-wake alpm status: %s\n",
497		   str_enabled_disabled(!(alpm_ctl & ALPM_CTL_ALPM_AUX_LESS_ENABLE)));
498	seq_printf(m, "Aux-less alpm status: %s\n",
499		   str_enabled_disabled(alpm_ctl & ALPM_CTL_ALPM_AUX_LESS_ENABLE));
500out:
501	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
502
503	return ret;
504}
505
506DEFINE_SHOW_ATTRIBUTE(i915_edp_lobf_info);
507
508static int
509i915_edp_lobf_debug_get(void *data, u64 *val)
510{
511	struct intel_connector *connector = data;
512	struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
513
514	*val = intel_dp->alpm.lobf_disable_debug;
515
516	return 0;
517}
518
519static int
520i915_edp_lobf_debug_set(void *data, u64 val)
521{
522	struct intel_connector *connector = data;
523	struct intel_dp *intel_dp = enc_to_intel_dp(connector->encoder);
524
525	intel_dp->alpm.lobf_disable_debug = val;
526
527	return 0;
528}
529
530DEFINE_SIMPLE_ATTRIBUTE(i915_edp_lobf_debug_fops,
531			i915_edp_lobf_debug_get, i915_edp_lobf_debug_set,
532			"%llu\n");
533
534void intel_alpm_lobf_debugfs_add(struct intel_connector *connector)
535{
536	struct intel_display *display = to_intel_display(connector);
537	struct dentry *root = connector->base.debugfs_entry;
538
539	if (DISPLAY_VER(display) < 20 ||
540	    connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
541		return;
542
543	debugfs_create_file("i915_edp_lobf_debug", 0644, root,
544			    connector, &i915_edp_lobf_debug_fops);
545
546	debugfs_create_file("i915_edp_lobf_info", 0444, root,
547			    connector, &i915_edp_lobf_info_fops);
548}
549
550void intel_alpm_disable(struct intel_dp *intel_dp)
551{
552	struct intel_display *display = to_intel_display(intel_dp);
553	enum transcoder cpu_transcoder = intel_dp->alpm.transcoder;
554
555	if (DISPLAY_VER(display) < 20 || !intel_dp->alpm_dpcd)
556		return;
557
558	mutex_lock(&intel_dp->alpm.lock);
559
560	intel_de_rmw(display, ALPM_CTL(display, cpu_transcoder),
561		     ALPM_CTL_ALPM_ENABLE | ALPM_CTL_LOBF_ENABLE, 0);
562
563	drm_dbg_kms(display->drm, "Disabling ALPM\n");
564	mutex_unlock(&intel_dp->alpm.lock);
565}
566
567bool intel_alpm_get_error(struct intel_dp *intel_dp)
568{
569	struct intel_display *display = to_intel_display(intel_dp);
570	struct drm_dp_aux *aux = &intel_dp->aux;
571	u8 val;
572	int r;
573
574	r = drm_dp_dpcd_readb(aux, DP_RECEIVER_ALPM_STATUS, &val);
575	if (r != 1) {
576		drm_err(display->drm, "Error reading ALPM status\n");
577		return true;
578	}
579
580	if (val & DP_ALPM_LOCK_TIMEOUT_ERROR) {
581		drm_dbg_kms(display->drm, "ALPM lock timeout error\n");
582
583		/* Clearing error */
584		drm_dp_dpcd_writeb(aux, DP_RECEIVER_ALPM_STATUS, val);
585		return true;
586	}
587
588	return false;
589}
~/ Read-only file preview.