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

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/i915/display/intel_snps_phy.c
Extension
.c
Size
72370 bytes
Lines
2029
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 (crtc_state->port_clock == tables[i]->clock) {
			crtc_state->dpll_hw_state.mpllb = *tables[i];
			return 0;
		}
	}

	/* For HDMI PLLs try SNPS PHY algorithm, if there are no precomputed tables */
	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) {
		intel_snps_hdmi_pll_compute_mpllb(&crtc_state->dpll_hw_state.mpllb,
						  crtc_state->port_clock);

		return 0;
	}

	return -EINVAL;
}

void intel_mpllb_enable(struct intel_encoder *encoder,
			const struct intel_crtc_state *crtc_state)
{
	struct intel_display *display = to_intel_display(encoder);
	const struct intel_mpllb_state *pll_state = &crtc_state->dpll_hw_state.mpllb;
	enum phy phy = intel_encoder_to_phy(encoder);
	intel_reg_t enable_reg = (phy <= PHY_D ?
				 DG2_PLL_ENABLE(phy) : MG_PLL_ENABLE(0));

	/*
	 * 3. Software programs the following PLL registers for the desired
	 * frequency.
	 */
	intel_de_write(display, SNPS_PHY_MPLLB_CP(phy), pll_state->mpllb_cp);
	intel_de_write(display, SNPS_PHY_MPLLB_DIV(phy), pll_state->mpllb_div);
	intel_de_write(display, SNPS_PHY_MPLLB_DIV2(phy), pll_state->mpllb_div2);
	intel_de_write(display, SNPS_PHY_MPLLB_SSCEN(phy), pll_state->mpllb_sscen);
	intel_de_write(display, SNPS_PHY_MPLLB_SSCSTEP(phy), pll_state->mpllb_sscstep);
	intel_de_write(display, SNPS_PHY_MPLLB_FRACN1(phy), pll_state->mpllb_fracn1);
	intel_de_write(display, SNPS_PHY_MPLLB_FRACN2(phy), pll_state->mpllb_fracn2);

	/*
	 * 4. If the frequency will result in a change to the voltage
	 * requirement, follow the Display Voltage Frequency Switching -
	 * Sequence Before Frequency Change.
	 *
	 * We handle this step in bxt_set_cdclk().
	 */

	/* 5. Software sets DPLL_ENABLE [PLL Enable] to "1". */
	intel_de_rmw(display, enable_reg, 0, PLL_ENABLE);

	/*
	 * 9. Software sets SNPS_PHY_MPLLB_DIV dp_mpllb_force_en to "1". This
	 * will keep the PLL running during the DDI lane programming and any
	 * typeC DP cable disconnect. Do not set the force before enabling the
	 * PLL because that will start the PLL before it has sampled the
	 * divider values.
	 */
	intel_de_write(display, SNPS_PHY_MPLLB_DIV(phy),
		       pll_state->mpllb_div | SNPS_PHY_MPLLB_FORCE_EN);

	/*
	 * 10. Software polls on register DPLL_ENABLE [PLL Lock] to confirm PLL
	 * is locked at new settings. This register bit is sampling PHY
	 * dp_mpllb_state interface signal.
	 */
	if (intel_de_wait_for_set_ms(display, enable_reg, PLL_LOCK, 5))
		drm_dbg_kms(display->drm, "Port %c PLL not locked\n", phy_name(phy));

	/*
	 * 11. If the frequency will result in a change to the voltage
	 * requirement, follow the Display Voltage Frequency Switching -
	 * Sequence After Frequency Change.
	 *
	 * We handle this step in bxt_set_cdclk().
	 */
}

void intel_mpllb_disable(struct intel_encoder *encoder)
{
	struct intel_display *display = to_intel_display(encoder);
	enum phy phy = intel_encoder_to_phy(encoder);
	intel_reg_t enable_reg = (phy <= PHY_D ?
				 DG2_PLL_ENABLE(phy) : MG_PLL_ENABLE(0));

	/*
	 * 1. If the frequency will result in a change to the voltage
	 * requirement, follow the Display Voltage Frequency Switching -
	 * Sequence Before Frequency Change.
	 *
	 * We handle this step in bxt_set_cdclk().
	 */

Annotation

Implementation Notes