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

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/i915/display/vlv_dsi_pll.c
Extension
.c
Size
17995 bytes
Lines
624
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 (d < delta) {
				delta = d;
				calc_m = m;
				calc_p = p;
			}
		}
	}

	/* register has log2(N1), this works fine for powers of two */
	config->dsi_pll.ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2);
	config->dsi_pll.div =
		(ffs(n) - 1) << DSI_PLL_N1_DIV_SHIFT |
		(u32)lfsr_converts[calc_m - 62] << DSI_PLL_M1_DIV_SHIFT;

	return 0;
}

static int vlv_dsi_pclk(struct intel_encoder *encoder,
			struct intel_crtc_state *config)
{
	struct intel_display *display = to_intel_display(encoder);
	struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
	int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
	u32 dsi_clock;
	u32 pll_ctl, pll_div;
	u32 m = 0, p = 0, n;
	int refclk = display->platform.cherryview ? 100000 : 25000;
	int i;

	pll_ctl = config->dsi_pll.ctrl;
	pll_div = config->dsi_pll.div;

	/* mask out other bits and extract the P1 divisor */
	pll_ctl &= DSI_PLL_P1_POST_DIV_MASK;
	pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2);

	/* N1 divisor */
	n = (pll_div & DSI_PLL_N1_DIV_MASK) >> DSI_PLL_N1_DIV_SHIFT;
	n = 1 << n; /* register has log2(N1) */

	/* mask out the other bits and extract the M1 divisor */
	pll_div &= DSI_PLL_M1_DIV_MASK;
	pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT;

	p = fls(pll_ctl);
	if (p)
		p--;

	if (!p) {
		drm_err(display->drm, "wrong P1 divisor\n");
		return 0;
	}

	for (i = 0; i < ARRAY_SIZE(lfsr_converts); i++) {
		if (lfsr_converts[i] == pll_div)
			break;
	}

	if (i == ARRAY_SIZE(lfsr_converts)) {
		drm_err(display->drm, "wrong m_seed programmed\n");
		return 0;
	}

	m = i + 62;

	dsi_clock = (m * refclk) / (p * n);

	return DIV_ROUND_CLOSEST(dsi_clock * intel_dsi->lane_count, bpp);
}

/*
 * XXX: The muxing and gating is hard coded for now. Need to add support for
 * sharing PLLs with two DSI outputs.
 */
int vlv_dsi_pll_compute(struct intel_encoder *encoder,
			struct intel_crtc_state *config)
{
	struct intel_display *display = to_intel_display(encoder);
	struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
	int pclk, dsi_clk, ret;

	dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
				    intel_dsi->lane_count);

	ret = dsi_calc_mnp(display, config, dsi_clk);
	if (ret) {
		drm_dbg_kms(display->drm, "dsi_calc_mnp failed\n");
		return ret;
	}

Annotation

Implementation Notes