drivers/gpu/drm/i915/display/intel_psr.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/i915/display/intel_psr.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/i915/display/intel_psr.c
Extension
.c
Size
145394 bytes
Lines
4712
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (DISPLAY_VER(display) >= 9) {
			u32 val;

			val = intel_de_rmw(display,
					   PSR_EVENT(display, cpu_transcoder),
					   0, 0);

			psr_event_print(display, val, intel_dp->psr.sel_update_enabled);
		}
	}

	if (psr_iir & psr_irq_psr_error_bit_get(intel_dp)) {
		drm_warn(display->drm, "[transcoder %s] PSR aux error\n",
			 transcoder_name(cpu_transcoder));

		intel_dp->psr.irq_aux_error = true;

		/*
		 * If this interruption is not masked it will keep
		 * interrupting so fast that it prevents the scheduled
		 * work to run.
		 * Also after a PSR error, we don't want to arm PSR
		 * again so we don't care about unmask the interruption
		 * or unset irq_aux_error.
		 */
		intel_de_rmw(display, psr_imr_reg(display, cpu_transcoder),
			     0, psr_irq_psr_error_bit_get(intel_dp));

		queue_work(display->wq.unordered, &intel_dp->psr.work);
	}
}

static u8 intel_dp_get_sink_sync_latency(struct intel_dp *intel_dp)
{
	struct intel_display *display = to_intel_display(intel_dp);
	u8 val = 8; /* assume the worst if we can't read the value */

	if (drm_dp_dpcd_readb(&intel_dp->aux,
			      DP_SYNCHRONIZATION_LATENCY_IN_SINK, &val) == 1)
		val &= DP_MAX_RESYNC_FRAME_COUNT_MASK;
	else
		drm_dbg_kms(display->drm,
			    "Unable to get sink synchronization latency, assuming 8 frames\n");
	return val;
}

static void _psr_compute_su_granularity(struct intel_dp *intel_dp,
					struct intel_connector *connector)
{
	struct intel_display *display = to_intel_display(intel_dp);
	ssize_t r;
	__le16 w;
	u8 y;

	/*
	 * If sink don't have specific granularity requirements set legacy
	 * ones.
	 */
	if (!(connector->dp.psr_caps.dpcd[1] & DP_PSR2_SU_GRANULARITY_REQUIRED)) {
		/* As PSR2 HW sends full lines, we do not care about x granularity */
		w = cpu_to_le16(4);
		y = 4;
		goto exit;
	}

	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_X_GRANULARITY, &w, sizeof(w));
	if (r != sizeof(w))
		drm_dbg_kms(display->drm,
			    "Unable to read selective update x granularity\n");
	/*
	 * Spec says that if the value read is 0 the default granularity should
	 * be used instead.
	 */
	if (r != sizeof(w) || w == 0)
		w = cpu_to_le16(4);

	r = drm_dp_dpcd_read(&intel_dp->aux, DP_PSR2_SU_Y_GRANULARITY, &y, 1);
	if (r != 1) {
		drm_dbg_kms(display->drm,
			    "Unable to read selective update y granularity\n");
		y = 4;
	}
	if (y == 0)
		y = 1;

exit:
	connector->dp.psr_caps.su_w_granularity = le16_to_cpu(w);
	connector->dp.psr_caps.su_y_granularity = y;
}

Annotation

Implementation Notes