Ejemplo n.º 1
0
static int rk_edp_link_power_up(struct rk_edp *edp)
{
	u8 value;
	int err;

	/* DP_SET_POWER register is only available on DPCD v1.1 and later */
	if (edp->link_train.revision < 0x11)
		return 0;

	err = rk_edp_dpcd_read(edp, DPCD_LINK_POWER_STATE, &value, 1);
	if (err < 0)
		return err;

	value &= ~DP_SET_POWER_MASK;
	value |= DP_SET_POWER_D0;

	err = rk_edp_dpcd_write(edp, DPCD_LINK_POWER_STATE, &value, 1);
	if (err < 0)
		return err;

	/*
	 * According to the DP 1.1 specification, a "Sink Device must exit the
	 * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
	 * Control Field" (register 0x600).
	 */
	mdelay(1);

	return 0;
}
Ejemplo n.º 2
0
static int rk_edp_link_train_ce(struct rk_edp *edp)
{
	int channel_eq;
	u8 value, tries = 0;
	u8 status[DP_LINK_STATUS_SIZE];

	value = DP_TRAINING_PATTERN_2;
	write32(&edp->regs->dp_training_ptn_set, value);
	rk_edp_dpcd_write(edp, DPCD_TRAINING_PATTERN_SET, &value, 1);

	/* channel equalization loop */
	channel_eq = 0;
	for (tries = 0; tries < 5; tries++) {
		rk_edp_set_link_training(edp, edp->train_set);
		rk_edp_dpcd_write(edp, DPCD_TRAINING_LANE0_SET,
					edp->train_set,
					edp->link_train.lane_count);

		udelay(400);
		if (rk_edp_dpcd_read_link_status(edp, status) < 0) {
			printk(BIOS_ERR, "displayport link status failed\n");
			return -1;
		}

		if (rk_edp_channel_eq_ok(status,
			edp->link_train.lane_count)) {
			channel_eq = 1;
			break;
		}
		edp_get_adjust_train(status,
			edp->link_train.lane_count,
			edp->train_set);
	}

	if (!channel_eq) {
		printk(BIOS_ERR, "channel eq failed\n");
		return -1;
	} else {
		printk(BIOS_DEBUG, "channel eq at voltage %d pre-emphasis %d\n",
			  edp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
			  (edp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
			  >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
		return 0;
	}
}
Ejemplo n.º 3
0
static int rk_edp_link_configure(struct rk_edp *edp)
{
	u8 values[2];

	values[0] = edp->link_train.link_rate;
	values[1] = edp->link_train.lane_count;

	return rk_edp_dpcd_write(edp, DPCD_LINK_BW_SET, values, sizeof(values));
}
Ejemplo n.º 4
0
static int rk_edp_link_train_ce(struct rk_edp_priv *edp)
{
	struct rk3288_edp *regs = edp->regs;
	int channel_eq;
	u8 value;
	int tries;
	u8 status[DP_LINK_STATUS_SIZE];
	int ret;

	value = DP_TRAINING_PATTERN_2;
	writel(value, &regs->dp_training_ptn_set);
	ret = rk_edp_dpcd_write(regs, DPCD_TRAINING_PATTERN_SET, &value, 1);
	if (ret)
		return ret;

	/* channel equalization loop */
	channel_eq = 0;
	for (tries = 0; tries < 5; tries++) {
		rk_edp_set_link_training(edp, edp->train_set);
		udelay(400);

		if (rk_edp_dpcd_read_link_status(edp, status) < 0) {
			printf("displayport link status failed\n");
			return -1;
		}

		channel_eq = rk_edp_channel_eq(status,
					       edp->link_train.lane_count);
		if (!channel_eq)
			break;
		edp_get_adjust_train(status, edp->link_train.lane_count,
				     edp->train_set);
	}

	if (channel_eq) {
		printf("channel eq failed, ret=%d\n", channel_eq);
		return channel_eq;
	}

	debug("channel eq at voltage %d pre-emphasis %d\n",
	      edp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
	      (edp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
			>> DP_TRAIN_PRE_EMPHASIS_SHIFT);

	return 0;
}
Ejemplo n.º 5
0
static int rk_edp_link_train_cr(struct rk_edp *edp)
{
	int clock_recovery;
	u8 voltage, tries = 0;
	u8 status[DP_LINK_STATUS_SIZE];
	int i;
	u8 value;

	value = DP_TRAINING_PATTERN_1;
	write32(&edp->regs->dp_training_ptn_set, value);
	rk_edp_dpcd_write(edp, DPCD_TRAINING_PATTERN_SET, &value, 1);
	memset(edp->train_set, 0, 4);

	/* clock recovery loop */
	clock_recovery = 0;
	tries = 0;
	voltage = 0xff;

	while (1) {
		rk_edp_set_link_training(edp, edp->train_set);
		rk_edp_dpcd_write(edp, DPCD_TRAINING_LANE0_SET,
					edp->train_set,
					edp->link_train.lane_count);

		mdelay(1);

		if (rk_edp_dpcd_read_link_status(edp, status) < 0) {
			printk(BIOS_ERR, "displayport link status failed\n");
			break;
		}

		if (rk_edp_clock_recovery_ok(status,
			edp->link_train.lane_count)) {
			clock_recovery = 1;
			break;
		}

		for (i = 0; i < edp->link_train.lane_count; i++) {
			if ((edp->train_set[i] &
				DP_TRAIN_MAX_SWING_REACHED) == 0)
				break;
		}
		if (i == edp->link_train.lane_count) {
			printk(BIOS_ERR, "clock recovery reached max voltage\n");
			break;
		}

		if ((edp->train_set[0] &
			DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
			++tries;
			if (tries == MAX_CR_LOOP) {
				printk(BIOS_ERR, "clock recovery tried 5 times\n");
				break;
			}
		} else
			tries = 0;

		voltage = edp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;

		/* Compute new train_set as requested by sink */
		edp_get_adjust_train(status, edp->link_train.lane_count,
					edp->train_set);
	}
	if (!clock_recovery) {
		printk(BIOS_ERR, "clock recovery failed\n");
		return -1;
	} else {
		printk(BIOS_DEBUG, "clock recovery at voltage %d pre-emphasis %d\n",
			  edp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
			  (edp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
			  DP_TRAIN_PRE_EMPHASIS_SHIFT);
		return 0;
	}
}
Ejemplo n.º 6
0
static int rk_edp_link_train_cr(struct rk_edp_priv *edp)
{
	struct rk3288_edp *regs = edp->regs;
	int clock_recovery;
	uint voltage, tries = 0;
	u8 status[DP_LINK_STATUS_SIZE];
	int i, ret;
	u8 value;

	value = DP_TRAINING_PATTERN_1;
	writel(value, &regs->dp_training_ptn_set);
	ret = rk_edp_dpcd_write(regs, DPCD_TRAINING_PATTERN_SET, &value, 1);
	if (ret)
		return ret;
	memset(edp->train_set, '\0', sizeof(edp->train_set));

	/* clock recovery loop */
	clock_recovery = 0;
	tries = 0;
	voltage = 0xff;

	while (1) {
		rk_edp_set_link_training(edp, edp->train_set);
		ret = rk_edp_dpcd_write(regs, DPCD_TRAINING_LANE0_SET,
					edp->train_set,
					edp->link_train.lane_count);
		if (ret)
			return ret;

		mdelay(1);

		ret = rk_edp_dpcd_read_link_status(edp, status);
		if (ret) {
			printf("displayport link status failed, ret=%d\n", ret);
			break;
		}

		clock_recovery = rk_edp_clock_recovery(status,
						edp->link_train.lane_count);
		if (!clock_recovery)
			break;

		for (i = 0; i < edp->link_train.lane_count; i++) {
			if ((edp->train_set[i] &
				DP_TRAIN_MAX_SWING_REACHED) == 0)
				break;
		}
		if (i == edp->link_train.lane_count) {
			printf("clock recovery reached max voltage\n");
			break;
		}

		if ((edp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
				voltage) {
			if (++tries == MAX_CR_LOOP) {
				printf("clock recovery tried 5 times\n");
				break;
			}
		} else {
			tries = 0;
		}

		voltage = edp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;

		/* Compute new train_set as requested by sink */
		edp_get_adjust_train(status, edp->link_train.lane_count,
				     edp->train_set);
	}
	if (clock_recovery) {
		printf("clock recovery failed: %d\n", clock_recovery);
		return clock_recovery;
	} else {
		debug("clock recovery at voltage %d pre-emphasis %d\n",
		      edp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
		      (edp->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
				DP_TRAIN_PRE_EMPHASIS_SHIFT);
		return 0;
	}
}