drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c
Extension
.c
Size
40204 bytes
Lines
1292
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 (!tg->funcs->is_counter_moving(tg)) {
			/* error - no point to wait if counter is not moving */
			break;
		}
	}

	while (!dce120_timing_generator_is_in_vertical_blank(tg)) {
		if (!tg->funcs->is_counter_moving(tg)) {
			/* error - no point to wait if counter is not moving */
			break;
		}
	}
}

/* wait until TG is in beginning of active region */
static void dce120_timing_generator_wait_for_vactive(struct timing_generator *tg)
{
	while (dce120_timing_generator_is_in_vertical_blank(tg)) {
		if (!tg->funcs->is_counter_moving(tg)) {
			/* error - no point to wait if counter is not moving */
			break;
		}
	}
}

/*********** Timing Generator Synchronization routines ****/

/* Setups Global Swap Lock group, TimingServer or TimingClient*/
static void dce120_timing_generator_setup_global_swap_lock(
	struct timing_generator *tg,
	const struct dcp_gsl_params *gsl_params)
{
	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
	uint32_t value_crtc_vtotal =
							dm_read_reg_soc15(tg->ctx,
							mmCRTC0_CRTC_V_TOTAL,
							tg110->offsets.crtc);
	/* Checkpoint relative to end of frame */
	uint32_t check_point =
							get_reg_field_value(value_crtc_vtotal,
							CRTC0_CRTC_V_TOTAL,
							CRTC_V_TOTAL);


	dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_GSL_WINDOW, tg110->offsets.crtc, 0);

	CRTC_REG_UPDATE_N(DCP0_DCP_GSL_CONTROL, 6,
		/* This pipe will belong to GSL Group zero. */
		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 1,
		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), gsl_params->gsl_master == tg->inst,
		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY,
		/* Keep signal low (pending high) during 6 lines.
		 * Also defines minimum interval before re-checking signal. */
		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY,
		/* DCP_GSL_PURPOSE_SURFACE_FLIP */
		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0,
		FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 1);

	CRTC_REG_SET_2(
			CRTC0_CRTC_GSL_CONTROL,
			CRTC_GSL_CHECK_LINE_NUM, check_point - FLIP_READY_BACK_LOOKUP,
			CRTC_GSL_FORCE_DELAY, VFLIP_READY_DELAY);
}

/* Clear all the register writes done by setup_global_swap_lock */
static void dce120_timing_generator_tear_down_global_swap_lock(
	struct timing_generator *tg)
{
	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);

	/* Settig HW default values from reg specs */
	CRTC_REG_SET_N(DCP0_DCP_GSL_CONTROL, 6,
			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 0,
			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), 0,
			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY,
			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY,
			/* DCP_GSL_PURPOSE_SURFACE_FLIP */
			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0,
			FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 0);

	CRTC_REG_SET_2(CRTC0_CRTC_GSL_CONTROL,
		       CRTC_GSL_CHECK_LINE_NUM, 0,
		       CRTC_GSL_FORCE_DELAY, 0x2); /*TODO Why this value here ?*/
}

/* Reset slave controllers on master VSync */
static void dce120_timing_generator_enable_reset_trigger(
	struct timing_generator *tg,
	int source)
{

Annotation

Implementation Notes