drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/hisilicon/hibmc/dp/dp_link.c
Extension
.c
Size
9656 bytes
Lines
393
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 (ret) {
			drm_err(dp->dev, "Get lane status failed\n");
			return ret;
		}

		if (drm_dp_clock_recovery_ok(lane_status, dp->link.cap.lanes)) {
			drm_dbg_dp(dp->dev, "dp link training cr done\n");
			dp->link.status.clock_recovered = true;
			return 0;
		}

		if (voltage_tries == 5) {
			drm_dbg_dp(dp->dev, "same voltage tries 5 times\n");
			dp->link.status.clock_recovered = false;
			return 0;
		}

		level_changed = hibmc_dp_link_get_adjust_train(dp, lane_status);

		ret = hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set);
		if (ret)
			return ret;

		ret = drm_dp_dpcd_write(dp->aux, DP_TRAINING_LANE0_SET, dp->link.train_set,
					dp->link.cap.lanes);
		if (ret != dp->link.cap.lanes) {
			drm_dbg_dp(dp->dev, "Update link training failed\n");
			return ret >= 0 ? -EIO : ret;
		}

		voltage_tries = level_changed ? 1 : voltage_tries + 1;
	}

	drm_err(dp->dev, "dp link training clock recovery 80 times failed\n");
	dp->link.status.clock_recovered = false;

	return 0;
}

static int hibmc_dp_link_training_channel_eq(struct hibmc_dp_dev *dp)
{
	u8 lane_status[DP_LINK_STATUS_SIZE] = {0};
	u8 eq_tries;
	int ret;

	ret = hibmc_dp_link_set_pattern(dp, DP_TRAINING_PATTERN_2);
	if (ret)
		return ret;

	for (eq_tries = 0; eq_tries < HIBMC_EQ_MAX_RETRY; eq_tries++) {
		drm_dp_link_train_channel_eq_delay(dp->aux, dp->dpcd);

		ret = drm_dp_dpcd_read_link_status(dp->aux, lane_status);
		if (ret) {
			drm_err(dp->dev, "get lane status failed\n");
			break;
		}

		if (!drm_dp_clock_recovery_ok(lane_status, dp->link.cap.lanes)) {
			drm_dbg_dp(dp->dev, "clock recovery check failed\n");
			drm_dbg_dp(dp->dev, "cannot continue channel equalization\n");
			dp->link.status.clock_recovered = false;
			break;
		}

		if (drm_dp_channel_eq_ok(lane_status, dp->link.cap.lanes)) {
			dp->link.status.channel_equalized = true;
			drm_dbg_dp(dp->dev, "dp link training eq done\n");
			break;
		}

		hibmc_dp_link_get_adjust_train(dp, lane_status);

		ret = hibmc_dp_serdes_set_tx_cfg(dp, dp->link.train_set);
		if (ret)
			return ret;

		ret = drm_dp_dpcd_write(dp->aux, DP_TRAINING_LANE0_SET,
					dp->link.train_set, dp->link.cap.lanes);
		if (ret != dp->link.cap.lanes) {
			drm_dbg_dp(dp->dev, "Update link training failed\n");
			ret = (ret >= 0) ? -EIO : ret;
			break;
		}
	}

	if (eq_tries == HIBMC_EQ_MAX_RETRY)
		drm_err(dp->dev, "channel equalization failed %u times\n", eq_tries);

	hibmc_dp_link_set_pattern(dp, DP_TRAINING_PATTERN_DISABLE);

Annotation

Implementation Notes